Exploring SSL, Let’s Encrypt & Cloudflare Integrations
This is the third article in the Taming Nginx series, where we explore creative ways to configure Nginx. In this article, we focus on securing your web server with SSL, wildcard certificates, and we touch on mutual SSL.
So far, we’ve covered:
- Smarter Defaults for Subdomains and SSL - how to organize your subdomain configuration in Nginx.
- Why Your Web Server Structure is Holding You Back - a deep dive into common folder structures and the system I’ve settled on.
- Wildcard SSL and Beyond - You are reading this now.
- The Art of Proxying: Mastering Traffic Management Like a Pro - where we push Nginx to its limits with advanced and peculiar use cases in reverse proxying.
It might be worth reading In the Beginning… We Shared (whether we liked it or not!) which is a light-hearted exploration of how self-hosting evolved over the decades.
What in the world is SSL and where did TLS come from?
SSL (Secure Sockets Layer) was introduced in the mid-1990s to secure internet communications but was deprecated in favour of TLS (Transport Layer Security), which is far more secure and efficient. While SSL versions are now obsolete, TLS 1.2 and 1.3 remain widely used, providing encryption, integrity, and authenticity.
Fun Fact:“SSL” is still colloquially used to refer to TLS, even though SSL is no longer in use.
Today, we have services like Cloudflare and Let’s Encrypt that have made securing your site or service so much easier.
But this wasn’t always the case. In the early days of web hosting, you had to purchase certificates from providers at exorbitant prices, ranging from $100 to over $1,500 per year, depending on the reputation of the Certificate Authority!
Thankfully, if you’re looking for the simplest way to secure your site today, Cloudflare offers an outstanding free solution.
Cloudflare
To be fair, when Cloudflare was first introduced, it didn’t yet issue certificates for your domain. That said, it was already a game-changer, excelling at protecting your site from DDoS attacks and offering useful 3rd party integrations like analytics.
SSL wasn’t even part of the picture yet, but Cloudflare still stood out as a critical tool for website owners.
The way it worked was simple: you’d buy a domain from a registrar of your choice, then point your domain’s name servers (NS Records) to Cloudflare.
This allowed Cloudflare to act as your DNS provider and deliver its features seamlessly.
Perhaps the biggest benefit? You didn’t have to pay a cent. And when Cloudflare introduced automated SSL provisioning, it added a layer of security that elevated its value to an entirely new level.
At the time of this article, there’s still no service quite like it that offers so much – for free.
Getting Started with Cloudflare
Setting up Cloudflare for your domain is straightforward:
- Sign Up: Create a free Cloudflare account.
- Add Your Domain: Register your domain with Cloudflare and follow the step-by-step instructions to configure DNS settings.
- Update Your Name Servers: Point your domain’s name servers (NS Records) to Cloudflare as directed during setup.
And that’s it, really! Once you’ve completed the setup, you’ll have DDoS protection and SSL out of the box. However, Cloudflare offers a few options that are worth mentioning to get the most out of your configuration.
DNS Proxied vs. DNS Only
When a record is Proxied, traffic is routed through Cloudflare’s network, allowing it to leverage DDoS protection, caching, and SSL termination. On the other hand, a DNS Only record directs traffic straight to your origin server, completely bypassing Cloudflare. This is typically used for services like mail servers or anything that doesn’t work well with Cloudflare’s proxy.
Cloudflare provides several SSL modes based on different security needs.
The Off mode disables SSL entirely which not recommended unless you know what you’re doing.
The Flexible option encrypts traffic between the browser and Cloudflare but leaves communication with the origin server unencrypted, making it less secure.
The Full mode ensures encryption from end to end but does not validate the origin server’s certificate. Finally, Full (Strict) is the most secure setting, encrypting traffic end-to-end while also validating the origin server’s certificate.
For a fully secure setup, always aim for Full (Strict) SSL mode if your origin server has a valid certificate (such as one issued by Let’s Encrypt or your own CA). While Cloudflare simplifies SSL for many scenarios, it’s worth knowing how to use Certbot to issue your own certificates, which we’ll dive into next.
Certbot
Let’s Encrypt revolutionized SSL provisioning by making certificates free and accessible to everyone. At the heart of this process is certbot
, a powerful CLI tool that automates certificate issuance and renewal.
Fun Fact:certbot
—the CLI tool—used to be known asletsencrypt
and was really annoying to type out each time! The rebranding was more than welcome, not to mention its expanded capabilities.
There are many tutorials on using Certbot to provision single-domain certificates, so this guide focuses on wildcard certificates. These simplify SSL management by covering all subdomains of a domain, making them ideal for scalable and dynamic setups.
Getting Started with Let’s Encrypt
Let’s set up Certbot on Ubuntu with Nginx to automate SSL provisioning. If your configuration differs, the Certbot interactive guide is a great resource. We’ll focus on the basics:
# Update your package list and install snapd (if not already installed)
sudo apt update
sudo apt install snapd
# Install Certbot using snap
sudo snap install --classic certbot
# Verify Certbot installation
certbot --version
# If certbot isn't found, create a symlink to the binary
sudo ln -s /snap/bin/certbot /usr/bin/certbot
# Allow Certbot to use plugins with root access
sudo snap set certbot trust-plugin-with-root=ok
# Install Certbot's Cloudflare DNS plugin
sudo snap install certbot-dns-cloudflare
To get a Cloudflare API Token:
→ API Tokens in Cloudflare’s Dashboard → Create Token → Use the Edit zone DNS
template → Select the domain (zone) you want to manage → Copy the token and save it securely.
On your machine, create a cloudflare.ini
file:
# Cloudflare API token used by Certbot dns_cloudflare_api_token = <your token>
Save the file in a secure location and set its permissions:
# use sudo depending on where you save it. chmod 600 ./cloudflare.ini
And now it’s time to generate the wildcard certificate:
certbot certonly --dns-cloudflare --dns-cloudflare-credentials ~/.secrets/certbot/cloudflare.ini -dns-cloudflare-propagation-seconds 60 -d example.com -d *.example.com
The command may take a minute due to the DNS propagation delay, but once complete, your certificates will be saved to:
- Certificate:
/etc/letsencrypt/live/
example.com/fullchain.pem
- Private Key:
/etc/letsencrypt/live/
example.com/privkey.pem
Nginx Integration
Remember the handy ssl_params
file from the first article? That’s where you’ll update the certificate paths with the locations generated above.
To illustrate how this works, here’s a minimal example of an Nginx configuration for a subdomain:
# File: /etc/nginx/sites-available/freebies.example.com server { listen 443 ssl; listen [::]:443 ssl; server_name freebies.example.com; root /srv/freebies.example.com/; index index.html; # SSL Configuration is the same for every subdomains thanks the # wildcard certificate include /etc/nginx/ssl_params; # Serve files and directories, or return 404 location / { try_files $uri $uri/ =404; } }
This example illustrates how the wildcard certificate makes SSL configuration consistent across subdomains. With this foundation in place, let’s take it a step further and explore enabling Mutual SSL for secure system-to-system communication.
Mutual SSL
Before APIs were everywhere, developers relied on simpler methods like API keys or IP whitelisting to secure system-to-system communication. Mutual SSL improves on this by verifying both the client and server using certificates, ensuring trust at the system level.
It’s important to note that Mutual SSL verifies requests at the transport layer and does not replace user-level authentication methods like OAuth or passwords.
How to Do It with Nginx
Let’s take a hypothetical scenario where you want to establish Mutual SSL with two of your subdomains:
api.example.com
: Your API serviceclient.example.com
: Your WebApp that calls the API for data
Since we’ve already created a wildcard certificate earlier for browser-level verification, that setup remains unchanged. Here, we’ll generate additional certificates specifically for Mutual SSL using OpenSSL:
For a production-grade guide on setting this up, be sure to check outNginx’s Documentation
# Create a custom CA certificate and private key openssl req -new -x509 -days 365 -nodes -out ca.crt -keyout ca.key # Generate a private key and CSR (Certificate Signing Request) for the client openssl req -new -nodes -out client.csr -keyout client.key # Sign the CSR with the CA to create the client certificate openssl x509 -req -in client.csr # Input: Client CSR -CA ca.crt # CA certificate -CAkey ca.key # CA private key -CAcreateserial # Generate a serial number for the certificate -out client.crt # Output: Client certificate -days 365 # Valid for 365 days
Server Configuration forapi.example.com
Update the configuration for api.example.com
to include Mutual SSL settings:
# File: /etc/nginx/sites-available/api.example.com server { listen 443 ssl; listen [::]:443 ssl; server_name api.example.com; root /srv/api.example.com/; index index.html; # Include wildcard certificate include /etc/nginx/ssl_params; # Mutual SSL settings ssl_client_certificate /path/to/ca.crt; ssl_verify_client on; location / { # Enforce client verification by leveraging ssl_verify_client error_page 495 = /error/missing_or_invalid_client_cert; try_files $uri $uri/ =404; } # Custom error for missing or invalid certificates location = /error/missing_or_invalid_client_cert { return 403 "mTLS certificate missing or invalid"; } }
Client Configuration forclient.example.com
To connect securely to the API, configure the client.example.com
subdomain to use the generated certificates:
# File: /etc/nginx/sites-available/client.example.com server { listen 443 ssl; listen [::]:443 ssl; server_name client.example.com; root /srv/client.example.com/; index index.html; # Include wildcard certificate include /etc/nginx/ssl_params; # Configure Mutual SSL for outgoing requests to api.example.com location /api/ { proxy_pass https://api.example.com; proxy_ssl_certificate /path/to/client.crt; proxy_ssl_certificate_key /path/to/client.key; proxy_ssl_trusted_certificate /path/to/ca.crt; } }
Verification Steps
Let’s make sure everything is configured correctly by testing NGINX and verifying the API endpoint.
# Test the NGINX configuration for syntax errors sudo nginx -t # Reload NGINX to apply changes (use restart if significant changes were made) sudo service nginx reload # or restart # Verify the API with the client certificate and key curl --cert /path/to/client.crt --key /path/to/client.key https://api.example.com
If everything is set up correctly, the nginx -t
test should pass, and the curl
command should return a valid response from the API. If something’s off, check Nginx’s access.log
or error.log
for SSL-related issues or misconfigurations.
Finally, open client.example.com
in your browser and ensure the WebApp loads without SSL warnings. No red screens? Perfect! Mutual SSL is up and running while keeping browser compatibility intact!
I didn’t anticipate this article being so detailed, but I wanted to share a bit more depth compared to the usual guides out there. This wasn’t meant to be a quick copy-paste style tutorial so I hope you found it informative and useful.
So far, we’ve explored three articles in the Taming Nginx series, and next up, we’ll dive into some Advanced Caching and Scaling Techniques. Stay tuned, and don’t forget to subscribe to the newsletter below to get the latest updates.
Cheers!