dynamic ssl certificate with nginx - docker

I had a Shopify-like application. So, my customer get sub-domain when they create store(i.e customer1.myShopify.com).
to handle this case of dynamic sub-domains with nginx:
server {
listen 443 ssl;
server_name admin.myapp.com;
ssl_certificate /etc/letsencrypt/live/myapp/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/myapp/privkey.pem;
location / {
proxy_pass http://admin-front-end:80/;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header Host $host;
}
}
server {
listen 443 ssl;
server_name *.myapp.com;
ssl_certificate /etc/letsencrypt/live/myapp/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/myapp/privkey.pem;
location / {
proxy_pass http://app-front-end:80/;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header Host $host;
}
}
this works great so if you visit admin.myapp.com you'll see the admin application and if you visit any xxx.myapp.com you'll see the shop-front-end application.
The Problem
I want to allow my customer to connect their own domain. so I told them to connect with CNAME and A Record.
A Record => # => 12.12.12.3(my root nginx ip)
CNAME => WWW => thier.myapp.com
not each request to customer.com will resolved by my nginx.
so I added this configuration to my nginx, to catch all other server_name request:
server {
listen 80;
server_name server_name ~^.*$;
location / {
proxy_pass http://app-front-end:80/;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header Host $host;
}
}
and it works fine.
but how can I handle SSL for this case? because it could be any domain name.I don't know what the customer domain name will be.
how i can give them the ability to add SSL certificate automatically and without create manually ?

This server block should work since variable names are supported for ssl_certificate and ssl_certificate_key directives.
http {
map "$ssl_server_name" $domain_name { ~(.*)\.(.*)\.(.*)$ $2.$3; }
server {
listen 443;
server_name server_name ~^.*$;
ssl_certificate /path/to/cert/files/$domain_name.crt;
ssl_certificate_key /path/to/cert/keys/$domain_name.key;
location / {
proxy_pass http://app-front-end:80/;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header Host $host;
}
}
}
P.S. Using variable names would compromise performance because now nginx would load the files on each ssl handshake.
Ref: https://nginx.org/en/docs/http/ngx_http_ssl_module.html#ssl_certificate

In my view instead of compromising the nginx performance, we should use one cron job, say letsencrypt bot, which will fetch certificate based on user requested domain, and you can add the certificate in nginx conf, and restart server.
Bonus:
I have used traefik which is kubernetes based solutions, they load configs on the fly without the restart.

In VM you can use the certbot for managing the SSL/TLS certificate.
Now if you are using the HTTP-01 method to verify your domain you won't be able to get the Wild card domain name.
i would suggest to use the DNS-01 method in cert-bot for domain verification and you can get the wild card certificate and use it.
Adding the certificate to Nginx config using :
ssl_certificate /path/to/cert/files/tls.crt;
ssl_certificate_key /path/to/cert/keys/tls.key;
If you are using the certbot it will also auto inject and add the SSL config above lines to the configuration file.
For different domains also you can run the job or certbot with HTTP-01 method and you will get the certificate.
If you are on Kubernetes you can use the cert-manager, which will be managing the SSL/TLS certificate.

I suggest using separete block with different ssh certificates thats the only solution that worked for me
server {
listen 80;
root /var/www/html/example1.com;
index index.html;
server_name example1.com;
ssl_certificate /etc/letsencrypt/live/example1.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example1.com/privkey.pem;
location / {
try_files $uri $uri/ =404;
}
}
server {
listen 80;
root /var/www/html/example2.com;
index index.html;
server_name example2.com;
ssl_certificate /etc/letsencrypt/live/example2.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example2.com/privkey.pem;
location / {
try_files $uri $uri/ =404;
}
}

Related

NGINX Reverse Proxy Configuration Structure

Is there a "proper" structure for the directives of an NGINX Reverse Proxy? I have seen 2 main differences when looking for examples of an NGINX reverse proxy.
http directive is used to house all server directives. Servers with data are listed in a pool within the upstream directive.
server directives are listed directly within the main directive.
Is there any reason for this or is this just a syntactical sugar difference?
Example of #1 within ./nginx.conf file:
upstream docker-registry {
server registry:5000;
}
http {
server {
listen 80;
listen [::]:80;
return 301 https://$host#request_uri;
}
server {
listen 443 default_server;
ssl on;
ssl_certificate external/cert.pem;
ssl_certificate_key external/key.pem;
# set HSTS-Header because we only allow https traffic
add_header Strict-Transport-Security "max-age=31536000;";
proxy_set_header Host $http_host; # required for Docker client sake
proxy_set_header X-Real-IP $remote_addr; # pass on real client IP
location / {
auth_basic "Restricted"
auth_basic_user_file external/docker-registry.htpasswd;
proxy_pass http://docker-registry; # the docker container is the domain name
}
location /v1/_ping {
auth_basic off;
proxy_pass http://docker-registry;
}
}
}
Example of #2 within ./nginx.conf file:
server {
listen 80;
listen [::]:80;
return 301 https://$host#request_uri;
}
server {
listen 443 ssl;
listen [::]:443 ssl;
error_log /var/log/nginx/error.log info;
access_log /var/log/nginx/access.log main;
ssl_certificate /etc/ssl/private/{SSL_CERT_FILENAME};
ssl_certificate_key /etc/ssl/private/{SSL_CERT_KEY_FILENAME};
location / {
proxy_pass http://app1
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-For $remote_addr; # could also be `$proxy_add_x_forwarded_for`
proxy_set_header X-Forwarded-Port $server_port;
proxy_set_header X-Request-Start $msec;
}
}
I dont quite understand your question, but it seems to me that the second example is missing the http {}, I dont think that nginx will start without it.
unless your example2 file is included somehow in the nginx.conf that has the http{}

Webpage keeps being redirected to upstream server address after login logout

My page keeps redirecting back to my upstream proxy server backend,https://backend/, when I want it to redirect back to main page which is http://localhost/. How do I redirect it back to localhost? If it helps, I am using proxy pass to direct a Rails server. Any advice would be most welcome.
These are my nginx conf files.
upstream backend{
server localhost:3000;
}
server {
listen 80;
listen 443 ssl;
server_name localhost;
ssl_certificate localhost.cert;
ssl_certificate_key localhost.key;
#charset koi8-r;
#access_log logs/host.access.log main;
location / {
root html;
index index.html index.htm;
proxy_pass http://backend;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header X-Forwarded-Ssl on;
proxy_set_header origin 'https://backend';
}
My solution was based off this post here: https://unix.stackexchange.com/questions/290141/nginx-reverse-proxy-redirection
What you're missing are headers that need to be sent to the app. The most important of them is HOST. This shall perform the proxying as desired and shall keep the correct URL in the browser.
location / {
root html;
index index.html index.htm;
proxy_pass http://backend;
proxy_set_header HOST $host;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header X-Forwarded-Ssl on;
proxy_set_header origin 'https://localhost';
}
In the location block, what I added in to solve the issue was proxy_set_header HOST $host; and changing the origin to https://localhost, which is my HOST page.

Native Nginx reverse proxy to Docker container with Letsencrypt

I have an ubuntu 18.0.4 lts box with nginx installed and configuered as a reverse proxy:
/etc/nginx/sites-enabled/default:
server {
server_name example.com;
location / {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
proxy_pass http://0.0.0.0:3000;
}
I have a website running in a docker container listening on port 3000. With this configuration if I browse to http://example.com I see the site.
I've then installed LetsEncypt using the standard install from their website then I run sudo certbot --nginx and follow the instructions to enable https for mydomain.com.
Now my etc/nginx/sites-enabled/default looks like this and i'm unable to load the site on both https://example.com and http://example.com:
server {
server_name example.com;
location / {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
proxy_pass http://0.0.0.0:3000;
}
listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
Any ideas?
I figured it out. The problem wasn't with my nginx/letsencrypt config it was a networking issue at the provider level (azure).
I noticed the Network Security Group only allowed traffic on port 80. The solution was to add a rule for 443.
After adding this rule everything now works as expected.

Trying to Get SSL Up with Docker Nginx and Certbot

I have hit this roadblock where I am not able get the SSL Certificates from Let's encrypt.
I am using Nginx , Certbot and trying to get SSL running for my site with a node backend.
I tried to follow this post as my knowledge is limited. Any help pointers would be highly appreciated.
https://medium.com/#pentacent/nginx-and-lets-encrypt-with-docker-in-less-than-5-minutes-b4b8a60d3a71
As the post mentions , I first try to run the script to get a dummy certificate. I have modified the script to point to my domain.
But I get this error
Failed authorization procedure. example.org (http-01):
urn:ietf:params:acme:error:connection :: The server could not connect
to the client to verify the domain :: Fetching
http://example.org/.well-known/acme-challenge/Jca_rbXSDHEmXz8-y3bKKckD8g0lsuoQJgAxeSEz5Jo:
Connection refused
IMPORTANT NOTES:
- The following errors were reported by the server:
Domain: example.org Type: connection Detail: Fetching
http://example.org/.well-known/acme-challenge/Jca_rbXSDHEmXz8-y3bKKckD8g0lsuoQJgAxeSEz5Jo:
Connection refused
This is my nginx configuration
upstream app {
server app:3000;
}
server {
listen 80;
server_name example.org;
location / {
proxy_pass http://app/;
}
location /.well-known/acme-challenge/ {
root /var/www/certbot;
}
# location /api/ {
# proxy_pass http://app/;
# proxy_redirect off;
# proxy_set_header Host $host;
# proxy_set_header X-Real-IP $remote_addr;
# proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# proxy_set_header X-Forwarded-Host $server_name;
# }
}
server {
listen 443 ssl;
server_name example.org;
ssl_certificate /etc/letsencrypt/live/example.org/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.org/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
location / {
proxy_pass http://example.org; #for demo purposes
}
}

Setting up HTTPS for Jenkins

What is the recommended method for setting up HTTPS for Jenkins?
Setting up HTTPS in Jenkins itself?
Using Apache as proxy for HTTPS setup?
We have a VM in which Jenkins is the only application.
Method I use and I believe to be the most simple is to use nginx as proxy, example configuration:
root#redacted-jenkins-2:/etc/nginx/sites-available# cat jenkins_http.conf
#Ansible managed
server {
listen 80;
server_name jenkins.redacted.com.ar;
return 301 https://jenkins.redacted.com.ar$request_uri;
}
server {
listen 443 ssl;
server_name jenkins.redacted.com.ar;
ssl_certificate /etc/letsencrypt/live/jenkins.redacted.com.ar/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/jenkins.redacted.com.ar/privkey.pem;
ssl_trusted_certificate /etc/letsencrypt/live/jenkins.redacted.com.ar/fullchain.pem;
include /etc/nginx/snippets/ssl.conf;
location / {
proxy_set_header Host $host:$server_port;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_redirect http:// https://;
proxy_pass http://127.0.0.1:8080;
}
}

Resources