How to Set Up Let’s Encrypt SSL with Nginx Reverse Proxy for Multiple Subdomains


2 views

I'm running a development server on Ubuntu 14.04 LTS with multiple services hosted on different ports. To simplify access, I've configured Nginx as a reverse proxy to route traffic based on hostnames rather than port numbers. For example:

upstream sub {
    server 127.0.0.1:7547;
}

server {
    listen 80;
    server_name sub.domain.com www.sub.domain.com;
    access_log /var/log/nginx/sub.log combined;
    location / {
            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_pass http://127.0.0.1:7547;
            proxy_set_header Authorization "";
    }
}

Now I want to secure these services with Let's Encrypt SSL certificates while maintaining this proxy structure.

First, install Certbot and the Nginx plugin:

sudo add-apt-repository ppa:certbot/certbot
sudo apt-get update
sudo apt-get install certbot python-certbot-nginx

For a single subdomain:

sudo certbot --nginx -d sub.domain.com -d www.sub.domain.com

For multiple subdomains (more efficient):

sudo certbot --nginx -d sub1.domain.com -d sub2.domain.com -d sub3.domain.com

Here's how to modify your existing configuration for SSL:

server {
    listen 443 ssl;
    server_name sub.domain.com www.sub.domain.com;
    
    ssl_certificate /etc/letsencrypt/live/sub.domain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/sub.domain.com/privkey.pem;
    
    location / {
        proxy_pass http://127.0.0.1:7547;
        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-Proto $scheme;
    }
}

server {
    listen 80;
    server_name sub.domain.com www.sub.domain.com;
    return 301 https://$host$request_uri;
}

Add this to your crontab (sudo crontab -e):

0 12 * * * /usr/bin/certbot renew --quiet

If you need to use webroot authentication (for services not directly served by Nginx):

sudo certbot certonly --webroot -w /var/www/html -d sub.domain.com

Then manually configure Nginx to use the certificate as shown above.

Check your configuration:

sudo nginx -t

Test SSL configuration:

openssl s_client -connect sub.domain.com:443 -servername sub.domain.com

Check certificate expiration:

sudo certbot certificates

I'm running a development environment on Ubuntu 14.04 with multiple services exposed through an Nginx reverse proxy configuration. Here's a typical setup for one of my subdomains:

upstream service_x {
    server 127.0.0.1:7547;
}

server {
    listen 80;
    server_name x.domain.com www.x.domain.com;
    access_log /var/log/nginx/x.log combined;
    
    location / {
        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_pass http://service_x;
        proxy_set_header Authorization "";
    }
}

To secure these subdomains with HTTPS, we'll use Certbot, the official Let's Encrypt client. First, install Certbot and the Nginx plugin:

sudo apt-get update
sudo apt-get install software-properties-common
sudo add-apt-repository ppa:certbot/certbot
sudo apt-get update
sudo apt-get install python-certbot-nginx

For a single subdomain (x.domain.com), run:

sudo certbot --nginx -d x.domain.com -d www.x.domain.com

For multiple subdomains in one command:

sudo certbot --nginx \
-d x.domain.com -d www.x.domain.com \
-d y.domain.com -d www.y.domain.com \
-d z.domain.com -d www.z.domain.com

After running Certbot, your configuration will automatically be updated. Here's what the HTTPS version looks like:

server {
    listen 443 ssl;
    server_name x.domain.com www.x.domain.com;
    
    ssl_certificate /etc/letsencrypt/live/x.domain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/x.domain.com/privkey.pem;
    ssl_trusted_certificate /etc/letsencrypt/live/x.domain.com/chain.pem;
    
    access_log /var/log/nginx/x.log combined;
    
    location / {
        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-Proto $scheme;
        proxy_pass http://service_x;
        proxy_set_header Authorization "";
    }
}

server {
    listen 80;
    server_name x.domain.com www.x.domain.com;
    return 301 https://$host$request_uri;
}

Let's Encrypt certificates expire every 90 days. Add this cron job for automatic renewal:

0 12 * * * /usr/bin/certbot renew --quiet

If you need to use webroot authentication instead of the Nginx plugin:

sudo certbot certonly --webroot -w /var/www/html \
-d x.domain.com -d www.x.domain.com \
--email admin@domain.com --agree-tos

For improved security, add these SSL parameters to your Nginx config:

ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384...';
ssl_session_timeout 1d;
ssl_session_cache shared:SSL:50m;
ssl_stapling on;
ssl_stapling_verify on;