Skip to main content

A Guide to Implementing Let's Encrypt SSL with NGINX Reverse Proxy

11 minutes


Introduction

This article is about everything you need to know about implementing Let's Encrypt SSL with NGINX reverse proxy. We'll cover NGINX installation, reverse proxy configuration, Installation and automatic renewal of certificates, and best practices for SSL settings to get an A+ grade for the SSL test.

According to a study by Google, 95% of internet traffic is encrypted. That's huge! Not only does SSL keep your visitors' data safe, but it also gives you a nice little SEO boost. Google loves secure sites, and so do your users!

Therefore, If you are looking to secure your NGINX server with SSL encryption then there is no other better option than using free SSL certificates from Lets Encrypt CA. Follow the steps given in this article to setup NGINX with Lets Encrypt SSL in Ubuntu 22.04 or 24.04.

Understanding Let's Encrypt and NGINX Reverse Proxy

What is Let's Encrypt?

It's a free, automated, and trusted open Certificate Authority (CA) that's here to save you from paying for expensive SSL certificates. Let's Encrypt is a non-profit organization sponsored by some big names in tech and their motto is to encrypt the entire web.

Lets Encrypt uses ACME protocol (Automated Certificate Management Environment) to verify that you control a domain and then issue a certificate automatically. It's like having a robot issuing certificates for your SSL needs!

Benefits of using Let's Encrypt with NGINX reverse proxy

NGINX is a web server that can also act as a reverse proxy, load balancer, and HTTP cache. When it comes to SSL, NGINX handles the encryption and decryption of traffic, taking the load off your application servers.

By combining Let's Encrypt with NGINX reverse proxy, you not only get free, automatically renewed SSL certificates but also a powerful, flexible way to manage your web traffic.

There is a common misconceptions that "Setting up Let's Encrypt with NGINX is too complicated for beginners." However, this is not true. Although there's a small learning curve but with the right steps as described in this article, you'll be up and running with Lets Encrypt SSL in no time.

 

 

Prerequisites for Implementing Let's Encrypt with NGINX

NGINX installation and basic configuration

Let us dive into the nitty-gritty of setting up Let's Encrypt with NGINX. First of all, install NGINX with a default configuration. If you haven't already got NGINX up and running, you'll need to install it. On Ubuntu, it's as simple as running:

$ sudo apt update
$ sudo apt install nginx

Once it's installed, make sure it's running with:

$ sudo systemctl status nginx

You should see a nice green "active (running)" message. If not, try starting it with:

$ sudo systemctl start nginx

Enable systemd service of NGINX to automatically start it during a system reboot.

$ sudo systemctl enable nginx

Firewall considerations

Now, configure the firewall and make sure that ports 80 (HTTP) and 443 (HTTPS) are open. Let's Encrypt needs these to verify your domain and serve your encrypted traffic. If you're using UFW (Uncomplicated Firewall) on Ubuntu, you can open these ports with:

$ sudo ufw allow 'Nginx Full'

This allows both HTTP and HTTPS traffic through your firewall.

Now point your web browser to http://SERVER_IP (no domain at this moment) to view the default welcome page of NGINX.


NGINX default welcome page


Take a look at the default NGINX configuration file at /etc/nginx/site-available/default. However, we will create a fresh NGINX configuration file for our subdomain.

Domain name and DNS setup

Next up, configure the DNS setup for your domain. You need to have a registered domain name and make sure it's pointing to your server's IP address. If you're not sure how to do this, log into your domain registrar's website and look for DNS settings. You'll want to create an A record that points your domain or subdomain to your server's IP.

If you are planning to install Lets Encrypt SSL certificate for your root domain then create two A records - one for the root domain and another for the www subdomain.


DNS settings for sub domain


However, in this article we will install and configure Lets Encrypt SSL certificate for a subdomain(mail)

Step-by-Step Guide to Installing Certbot

What is Certbot?

The Certbot is a tool to fetch and update free, automated Lets Encrypt SSL certificates. 
It handles the nitty-gritty of obtaining and renewing certificates, so you don't have to.

Now, installing Certbot is a straightforward process depending on your operating system, here we'll go through this process for Ubuntu 22.04/24.04.

First up, add the Certbot repository. Open up your terminal and type:

$ sudo add-apt-repository ppa:certbot/certbot
$ sudo apt-get update

Now install Certbot and the NGINX plugin:

$ sudo apt-get install certbot python3-certbot-nginx

Verifying Certbot installation

Certbot is now installed on your system.  let's verify the installation.

$ certbot --version
certbot 1.21.0

If you see a version number pop up - you've successfully installed Certbot!

The Certbot website has excellent documentation for other operating systems. Just head over to certbot.eff.org, select your web server and OS, and follow the instructions. It's usually just a matter of running a few different commands.

In the next section, we'll configure NGINX with a reverse proxy.

Configure NGINX reverse proxy

First things first, let's configure the NGINX reverse proxy for our subdomain. Create a new configuration for your subdomain to start from scratch rather than using NGINX default settings.

$ sudo vi /etc/nginx/sites-available/node-app.conf 
server {
       listen 80;
       server_name mail.kubelynx.com;
       location / {
                     proxy_pass http://localhost:3000;
                     proxy_set_header Host $host;
                     proxy_set_header X-Real-IP $remote_addr;
       }
}

Enable the site and do a configuration test for NGINX.

$ cd /etc/nginx/sites-enabled/
$ sudo ln -s ../sites-available/node-app.conf .
$ sudo nginx -t
$ sudo systemctl restart nginx

This configuration tells NGINX to listen on port 80 (HTTP) and forward requests to backend node apps running on localhost:3000. Of course, adjust the proxy_pass directive to match your actual backend server. 

Point your browser to http://your-subdomain to view the non-SSL version(without Lets Encrypt SSL) of your site.


Subdomain without SSL
 

 

Obtaining and Installing Let's Encrypt SSL Certificates

It's time to obtain a new Let's Encrypt SSL certificate for the subdomain! We're going to run Certbot for the first time and the command we'll use:

$ sudo certbot --nginx -d mail.kubelynx.com
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Requesting a certificate for mail.kubelynx.com
Successfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/mail.kubelynx.com/fullchain.pem
Key is saved at:         /etc/letsencrypt/live/mail.kubelynx.com/privkey.pem
This certificate expires on 2024-12-09.
These files will be updated when the certificate renews.
Certbot has set up a scheduled task to automatically renew this certificate in the background.
Deploying certificate
Successfully deployed certificate for mail.kubelynx.com to /etc/nginx/sites-enabled/node-app.conf
Congratulations! You have successfully enabled HTTPS on https://mail.kubelynx.com
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
If you like Certbot, please consider supporting our work by:
* Donating to ISRG / Let's Encrypt:   https://letsencrypt.org/donate
* Donating to EFF:                    https://eff.org/donate-le
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -


The Lets Encrypt will perform a domain validation and once validated successfully, it will issue the certificates. The messages right after the command will confirm successful installation of SSL certificates. To fetch Let's Encrypt certificate for root domain, use the following command.

$ sudo certbot --nginx -d yourdomain.com -d www.yourdomain.com

Replace "yourdomain.com" with your actual domain name, of course. This command tells Certbot to use the NGINX plugin and obtain certificates for both the root domain and the www subdomain.

Now, let's verify that the SSL certificate installation was successful. Open up your favorite web browser and navigate to https://yoursubdomain.com. You should see that beautiful padlock icon next to your URL. Click on the padlock icon and check out the certificate details. You'll see that it's issued by Let's Encrypt.


Subdomain with Lets Encrypt SSL certificates


Review NGINX reverse proxy configuration

After fetching certificates, certbot will update the NGINX configuration file for the subdomain by including a few SSL configuration settings. Review the updated nginx SSL configuration settings.

$ sudo cat /etc/nginx/sites-available/node-app.conf
server {
       server_name mail.kubelynx.com;
       location / {
                       proxy_pass http://localhost:3000;
                       proxy_set_header Host $host;
                       proxy_set_header X-Real-IP $remote_addr;
        }
       listen 443 ssl; # managed by Certbot
       ssl_certificate /etc/letsencrypt/live/mail.kubelynx.com/fullchain.pem; # managed by Certbot
       ssl_certificate_key /etc/letsencrypt/live/mail.kubelynx.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
}
server {
       if ($host = mail.kubelynx.com) {
            return 301 https://$host$request_uri;
       } # managed by Certbot
       listen 80;
       server_name mail.kubelynx.com;
       return 404; # managed by Certbot
}

There are now two server blocks - one for HTTP version and another for HTTPS version of your site.

The certbot has updated our previous basic http implementation with the following SSL redirect.  This line instructs NGINX to redirect all HTTP traffic(port 80) to HTTPS(port 443) using a 301 redirect.

return 301 https://$host$request_uri;

You should also see a few lines added by Certbot in the new NGINX server block where it has added a path for certificates something like:

ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;

These lines tell NGINX where to find your SSL certificate chain and private key.

We're not done yet! We need to make sure the NGINX SSL configuration is optimized for security and performance, the configuration which we will discuss in the next section. 

Optimizing SSL Configuration for Security and Performance

Let's optimize the SSL configuration for NGINX reverse proxy for maximum security and performance.  The SSL performance optimization and best practices are worth it. Your site will be faster, and more secure, and your users will have a better experience overall.

The SSL configuration parameters can be found in the file /etc/letsencrypt/options-ssl-nginx.conf where some of the important parameters are already included.

Add the following SSL parameters in this file but make sure they are not duplicated.

First up, implement strong SSL cipher suites. They determine how your server and your users' browsers agree on how to encrypt data. Here's a configuration that works well by including modern encryption algorithms:

ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;

This config disables older, less secure protocols and prioritizes strong, modern SSL ciphers.

Next up, let's enable faster HTTP/2 protocol support. It can significantly improve load times, especially for SSL connections.

listen 443 ssl http2;

Just add http2 to your listen directive, and you're done with nginx http2 configuration!

Now, let's talk about HSTS implementation (HTTP Strict Transport Security). HSTS tells browsers to always use HTTPS for a domain, even if the user types in "http://".

add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;

The max-age value is in seconds, so this sets it for one year. The includeSubDomains directive applies HSTS to all subdomains too.

Let's optimize SSL session caching. This reduces the number of full SSL handshakes, which can significantly speed up repeat connections. Here's a config that's worked well for most situations:

ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;

This sets up a 10MB shared cache and keeps sessions for 10 minutes. 

Next, enable OCSP stapling. It speeds up the certificate validation process and improves privacy. Here's how:

ssl_stapling on;
ssl_stapling_verify on;
resolver 8.8.8.8 8.8.4.4 valid=300s;
resolver_timeout 5s;

This tells NGINX to handle OCSP requests on behalf of clients, using Google's DNS servers to resolve OCSP responder hostnames.

Enable SSL session tickets to speed up SSL handshakes:

ssl_session_tickets on;

Just be aware that this can have some security implications in certain scenarios, so make sure it fits your use case. The complete NGINX ssl directives in the option file is given below.

ssl_session_cache shared:le_nginx_SSL:10m;
ssl_session_timeout 10m;
ssl_session_tickets on;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
ssl_ciphers "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384";
# Manually added for Performance and Security
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
ssl_stapling on;
ssl_stapling_verify on;
resolver 8.8.8.8 8.8.4.4 valid=300s;
resolver_timeout 5s;

Lastly, don't forget to test your SSL configuration! I like to use SSL Labs' server test. It's like getting a report card for your SSL setup. Aim for that A+ grade!


SSL lab test
 
 

 

Automating SSL Certificate Renewal with Let's Encrypt

Lets encrypt certificates are valid for 90 days during which you have to renew the certificates. Short-lived certificates improve security by reducing the amount of time a compromised certificate can be used.

However, manually renewing certificates every 90 days is a tedious process. To automate the process of renewing Lets encrypt certificates before expiration, set up a cron job to automatically renew certificates.

Here's the command we'll use to set up the cron job:

$ sudo crontab -e

This will open up your crontab file. Add the following line:

0 3 1 * * /usr/bin/certbot renew --quiet --post-hook "systemctl reload nginx"

Let's break this down:

  • 0 3 1 * * means this job will run at 3:00 AM on the first day of every month.
  • /usr/bin/certbot renew attempts to renew all installed certificates.
  • --quiet keeps the output minimal.
  • --post-hook "systemctl reload nginx" tells NGINX to reload after successful renewal.

Let's test the certbot automation process to make sure everything's working as it should. Run this command:

$ sudo certbot renew --dry-run
Saving debug log to /var/log/letsencrypt/letsencrypt.log
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Processing /etc/letsencrypt/renewal/mail.kubelynx.com.conf
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Account registered.
Simulating renewal of an existing certificate for mail.kubelynx.com
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Congratulations, all simulated renewals succeeded: 
 /etc/letsencrypt/live/mail.kubelynx.com/fullchain.pem (success)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -


This simulates a renewal without actually modifying your certificates. If you see "Congratulations, all simulated renewals succeeded:" - you're all set with automated certificate renewal!

Now, let's talk about handling renewal failures. There may be a reason for which the ssl certificate renewal process may not go according to plan. In such circumstances, set up email notifications for renewal failures.

Add this line to your /etc/letsencrypt/cli.ini file:

email-on-failure = your-email@example.com

Replace your-email@example.com with your actual email address, of course. This way, if something goes wrong with the renewal process, you'll know about it right away.

You've not only secured your site with Let's Encrypt SSL, but you've also set up automatic renewals. 

Conclusion

Throughout this guide, we've covered a lot of ground - from understanding the nuances of Let's Encrypt and NGINX reverse proxy to optimizing SSL configuration for maximum security and performance.

By staying on top of automatic certificate renewals, regularly monitoring your SSL setup, and keeping your NGINX and Certbot versions up-to-date, you'll be well on your way to secure your site with Lets Encrypt SSL certificates.

fivestar_rating
No votes yet
Comments