Configure NGINX to use Let's Encrypt for SSL Certificates.

I've started moving toward using Let's Encrypt for HTTPS in my web applications and sites. First, set an environment variable with the domain name:

DOMAIN=www.example.com

Once the variable is set, here is how I configure the web server to handle the ACME challenge and serving HTTPS content:

sudo mkdir -p /var/www/letsencrypt/.well-known/acme-challenge
 
cat > /tmp/default-redirect << EOF
map \$request_uri \$do_redirect {
        "~/.well-known/acme-challenge/" 1;
        default 0;
}
 
server {
        listen 80;
        listen [::]:80;
 
        location ^~ /.well-known/acme-challenge/ {
                default_type "text/plain";
                root /var/www/letsencrypt;
        }
 
        if (\$do_redirect = "0") {
                rewrite (.*) https://\$http_host permanent;
        }
}
EOF
 
sudo mv /tmp/default-redirect /etc/nginx/sites-available/
 
sudo ln -s /etc/nginx/sites-available/default-redirect /etc/nginx/sites-enabled/default-redirect
 
sudo service nginx restart

Now, I install Certbot:

sudo add-apt-repository ppa:certbot/certbot -y
sudo apt update
sudo apt install certbot -y

Initialize system random number generator…

dd if=/dev/random of=/dev/urandom bs=1 count=32 2> /dev/null

Get the certificate. Make sure to replace the values below with the correct values…:

sudo certbot certonly --no-eff-email --webroot --agree-tos --email you@example.com -w /var/www/letsencrypt -d $DOMAIN

The certificates will be saved in %%/etc/letsencrypt/live/ in a directory that matches the domain name.

Configure the server to serve an SSL site:

cat > /tmp/$DOMAIN<< EOF
server {
    listen 443 ssl http2;
 
    ssl on;
    ssl_certificate /etc/letsencrypt/live/$DOMAIN/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/$DOMAIN/privkey.pem;
 
    ssl_ciphers 'kEECDH+ECDSA+AES128 kEECDH+ECDSA+AES256 kEECDH+AES128 kEECDH+AES256 +SHA !aNULL !eNULL !LOW !MD5 !EXP !DSS !PSK !SRP !kECDH !CAMELLIA !RC4 !SEED';
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_session_timeout 5m;
    ssl_session_cache shared:SSL:10m;
 
    ssl_stapling on;
    ssl_stapling_verify on;
 
    ssl_prefer_server_ciphers on;
    ssl_dhparam /etc/ssl/certs/dhparam.pem;
 
    add_header Strict-Transport-Security max-age=63072000;
    add_header X-Frame-Options DENY;
    add_header X-Content-Type-Options nosniff;
 
    keepalive_timeout 90;
 
    location / {
        proxy_set_header X-Real-IP \$remote_addr;
        proxy_set_header X-Forwarded-For \$remote_addr;
        proxy_set_header Host \$host;
        proxy_pass http://127.0.0.1:80;
    }
}
EOF
 
sudo mv /tmp/$DOMAIN /etc/nginx/sites-available/
 
sudo ln -s /etc/nginx/sites-available/$DOMAIN /etc/nginx/sites-enabled/$DOMAIN
 
sudo openssl dhparam -out /etc/ssl/certs/dhparam.pem 4096
 
sudo service nginx reload

Certbot will renew this certificate when it is within 30 days of expiring but you can verify that it will renew:

certbot renew --dry-run