Cybersecurity Updates & Tools

Secure Nginx with Let’s Encrypt on Ubuntu 16.04: SSL Setup Guide

Let’s Encrypt is a free, automated, and open certificate authority run by the Internet Security Research Group (ISRG). Certificates issued by Let’s Encrypt are trusted by virtually all modern browsers and provide full HTTPS for your domain at no cost.

This guide covers how to secure Nginx with Let’s Encrypt on Ubuntu 16.04 using Certbot and the Webroot domain validation plugin. The setup includes generating strong Diffie-Hellman parameters, creating reusable Nginx SSL snippets, and configuring auto-renewal.

Prerequisites:

  • A domain name pointing to your server IP (this guide uses example.com)
  • Nginx installed with a server block configured for your domain
  • Sudo access

Secure Nginx with Let’s Encrypt: Install Certbot via PPA on Ubuntu 16.04

On Ubuntu 16.04, Certbot is not available in the default repositories. It is distributed through a dedicated PPA maintained by the Electronic Frontier Foundation (EFF). To add third-party PPAs, you first need software-properties-common:

bashsudo apt updatesudo apt install software-properties-commonsudo add-apt-repository ppa:certbot/certbotsudo apt updatesudo apt install certbot

Generate Diffie-Hellman parameters. DH key exchange strengthens the SSL handshake against passive interception attacks. Generate a 2048-bit DH file:

bashsudo openssl dhparam -out /etc/ssl/certs/dhparam.pem 2048

You can increase this to 4096 bits for stronger security, though generation can take over 30 minutes on lower-resource servers.

Create the ACME webroot directory and set ownership for the Nginx user:

bashsudo mkdir -p /var/lib/letsencrypt/.well-knownsudo chgrp www-data /var/lib/letsencryptsudo chmod g+s /var/lib/letsencrypt

Obtain the SSL Certificate Using the Certbot Webroot Plugin

The Webroot plugin validates your domain by writing a temporary file inside .well-known/acme-challenge/. Let’s Encrypt fetches that file over HTTP to confirm the domain resolves to your server.

Create two reusable Nginx snippet files to avoid duplicating SSL settings across multiple server blocks.

/etc/nginx/snippets/letsencrypt.conf — routes all ACME challenge requests to the webroot directory:

nginxlocation ^~ /.well-known/acme-challenge/ {  allow all;  root /var/lib/letsencrypt/;  default_type "text/plain";  try_files $uri =404;}

/etc/nginx/snippets/ssl.conf — includes Mozilla-recommended cipher suites, OCSP stapling for faster certificate validation, HSTS to prevent protocol downgrade attacks, and security response headers (X-Frame-OptionsX-Content-Type-Options). Reference your dhparam.pem file at the top of this snippet.

Include the letsencrypt.conf snippet in your current HTTP server block, create the symlink from sites-available to sites-enabled, and reload Nginx. Then run Certbot to issue the certificate:

bashsudo certbot certonly --agree-tos --email admin@example.com \  --webroot -w /var/lib/letsencrypt/ -d example.com -d www.example.com

Certbot places the certificate files at /etc/letsencrypt/live/example.com/, including fullchain.pemprivkey.pem, and chain.pem.

Configure Nginx for HTTPS and Enable Auto-Renewal

Update your server block file with three separate blocks. The first redirects all HTTP traffic to HTTPS. The second redirects www to the bare domain over HTTPS. The third is the main HTTPS block, referencing the certificate files and including both Nginx snippets.

Reload Nginx to apply the HTTPS configuration:

bashsudo systemctl reload nginx

Auto-renewal. Let’s Encrypt certificates expire every 90 days. The Certbot package automatically creates a cron job at /etc/cron.d/certbot that runs twice daily and renews certificates 30 days before expiry. Nginx does not pick up a renewed certificate automatically, so you need to add a reload hook. Open that file and append --renew-hook "systemctl reload nginx" to the certbot line:

0 */12 * * * root ... certbot -q renew --renew-hook "systemctl reload nginx"

Test the renewal pipeline without actually issuing a new certificate:

bashsudo certbot renew --dry-run

No errors means the renewal configuration is working correctly and Nginx will reload automatically after each future renewal.

Your Nginx server on Ubuntu 16.04 is now secured with a trusted Let’s Encrypt SSL certificate. The certificate renews automatically, and the reload hook ensures Nginx serves the new certificate immediately after each renewal. Leave a comment below if you run into any issues.