BLOG POSTS
    MangoHost Blog / How to Secure Nginx with Let’s Encrypt on Ubuntu 24
How to Secure Nginx with Let’s Encrypt on Ubuntu 24

How to Secure Nginx with Let’s Encrypt on Ubuntu 24

Securing Nginx with Let’s Encrypt on Ubuntu 24 is essential for anyone running web services who wants to implement SSL/TLS encryption without the cost and complexity of traditional certificate authorities. Let’s Encrypt provides free, automated certificates that are trusted by all major browsers, making HTTPS accessible to everyone. In this guide, you’ll learn how to install and configure Let’s Encrypt with Nginx on Ubuntu 24, automate certificate renewal, handle multiple domains, and troubleshoot common issues that can trip up even experienced administrators.

How Let’s Encrypt and Certbot Work

Let’s Encrypt operates on the ACME (Automatic Certificate Management Environment) protocol, which automates the traditionally manual process of certificate creation, validation, signing, and installation. When you request a certificate, Let’s Encrypt needs to verify that you control the domain you’re requesting it for.

The validation happens through challenges – typically either HTTP-01 (placing a file at a specific URL on your web server) or DNS-01 (creating a specific DNS TXT record). Certbot, the official Let’s Encrypt client, handles these challenges automatically and can even modify your Nginx configuration to implement the SSL settings.

Certificates from Let’s Encrypt are valid for 90 days, which encourages automation. This shorter lifespan actually improves security by limiting the window of exposure if a private key gets compromised, and forces you to set up proper renewal processes from the start.

Prerequisites and Initial Setup

Before diving into the SSL setup, make sure your Ubuntu 24 system is properly configured. You’ll need a domain name pointing to your server’s IP address and Nginx already installed and serving content.

sudo apt update
sudo apt install nginx
sudo systemctl start nginx
sudo systemctl enable nginx

Verify that Nginx is running and accessible:

sudo systemctl status nginx
curl -I http://your-domain.com

Install snapd if it’s not already present, as the recommended way to install Certbot is through snap packages:

sudo apt install snapd
sudo snap install core; sudo snap refresh core
sudo snap install --classic certbot

Create a symbolic link to make Certbot accessible system-wide:

sudo ln -s /snap/bin/certbot /usr/bin/certbot

Configuring Nginx for Let’s Encrypt

Before obtaining certificates, you need a basic Nginx configuration. Create a server block for your domain:

sudo nano /etc/nginx/sites-available/your-domain.com

Add this basic configuration:

server {
    listen 80;
    server_name your-domain.com www.your-domain.com;
    
    root /var/www/your-domain.com;
    index index.html index.htm index.nginx-debian.html;
    
    location / {
        try_files $uri $uri/ =404;
    }
    
    # Let's Encrypt validation
    location /.well-known/acme-challenge/ {
        root /var/www/your-domain.com;
    }
}

Enable the site and test the configuration:

sudo ln -s /etc/nginx/sites-available/your-domain.com /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx

Create the web root directory and add a simple index file for testing:

sudo mkdir -p /var/www/your-domain.com
echo "

Hello from your-domain.com

" | sudo tee /var/www/your-domain.com/index.html

Obtaining SSL Certificates

Now comes the main event – getting your SSL certificate. Certbot offers several methods, but the Nginx plugin is the most straightforward as it automatically modifies your configuration:

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

During the process, Certbot will ask for your email address and agreement to terms of service. Choose whether to redirect HTTP traffic to HTTPS (recommended for most cases).

If you prefer more control over the process, you can obtain the certificate without automatic configuration changes:

sudo certbot certonly --nginx -d your-domain.com -d www.your-domain.com

For multiple unrelated domains, you can obtain separate certificates:

sudo certbot --nginx -d domain1.com -d www.domain1.com
sudo certbot --nginx -d domain2.com -d www.domain2.com

After successful certificate generation, Certbot will show you the certificate and key locations, typically:

  • Certificate: /etc/letsencrypt/live/your-domain.com/fullchain.pem
  • Private Key: /etc/letsencrypt/live/your-domain.com/privkey.pem

Optimizing SSL Configuration

Certbot’s default SSL configuration is decent, but you can enhance security and performance. Here’s an optimized configuration that incorporates modern security practices:

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name your-domain.com www.your-domain.com;
    
    # SSL Configuration
    ssl_certificate /etc/letsencrypt/live/your-domain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/your-domain.com/privkey.pem;
    
    # SSL Security Settings
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384;
    ssl_prefer_server_ciphers off;
    
    # SSL Performance
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 10m;
    ssl_session_tickets off;
    
    # OCSP Stapling
    ssl_stapling on;
    ssl_stapling_verify on;
    ssl_trusted_certificate /etc/letsencrypt/live/your-domain.com/chain.pem;
    resolver 8.8.8.8 8.8.4.4 valid=300s;
    resolver_timeout 5s;
    
    # Security Headers
    add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload";
    add_header X-Frame-Options DENY;
    add_header X-Content-Type-Options nosniff;
    add_header X-XSS-Protection "1; mode=block";
    
    root /var/www/your-domain.com;
    index index.html index.htm index.nginx-debian.html;
    
    location / {
        try_files $uri $uri/ =404;
    }
}

server {
    listen 80;
    listen [::]:80;
    server_name your-domain.com www.your-domain.com;
    
    # Redirect all HTTP requests to HTTPS
    return 301 https://$server_name$request_uri;
}

Setting Up Automatic Renewal

Let’s Encrypt certificates expire every 90 days, so automatic renewal is crucial. Certbot installs a systemd timer for this purpose. Check if it’s active:

sudo systemctl status snap.certbot.renew.timer

Test the renewal process without actually renewing:

sudo certbot renew --dry-run

You can also set up a custom cron job for more control over the renewal process:

sudo crontab -e

Add this line to run renewal twice daily:

0 12,23 * * * /usr/bin/certbot renew --quiet --post-hook "systemctl reload nginx"

For monitoring renewal status, create a simple script that logs renewal attempts:

#!/bin/bash
LOG_FILE="/var/log/certbot-renewal.log"
echo "$(date): Starting certificate renewal check" >> $LOG_FILE
/usr/bin/certbot renew --quiet --post-hook "systemctl reload nginx" >> $LOG_FILE 2>&1
echo "$(date): Certificate renewal check completed" >> $LOG_FILE

Handling Multiple Domains and Wildcard Certificates

For wildcard certificates, you’ll need to use DNS validation since HTTP validation can’t verify all possible subdomains:

sudo certbot certonly --manual --preferred-challenges dns -d your-domain.com -d *.your-domain.com

This process requires you to add TXT records to your DNS configuration. For automation, you can use DNS plugins for popular providers:

sudo snap install certbot-dns-cloudflare
sudo certbot certonly --dns-cloudflare --dns-cloudflare-credentials ~/.secrets/cloudflare.ini -d your-domain.com -d *.your-domain.com

The Cloudflare credentials file should contain:

# Cloudflare API credentials
dns_cloudflare_api_token = your-api-token

Set proper permissions on the credentials file:

chmod 600 ~/.secrets/cloudflare.ini

Performance Comparison and SSL Testing

Here’s a comparison of SSL configuration performance impacts:

Configuration Handshake Time (ms) CPU Usage Security Score
Basic Certbot 45-60 Low A
Optimized TLS 1.2/1.3 25-35 Medium A+
With OCSP Stapling 20-30 Medium A+
HTTP/2 Enabled 20-30 Medium A+

Test your SSL configuration using online tools:

You can also test locally using OpenSSL:

openssl s_client -connect your-domain.com:443 -servername your-domain.com
echo | openssl s_client -connect your-domain.com:443 2>/dev/null | openssl x509 -noout -dates

Common Issues and Troubleshooting

Rate limiting is a frequent issue when testing. Let’s Encrypt has several rate limits:

  • 20 certificates per registered domain per week
  • 300 new orders per account per 3 hours
  • 5 duplicate certificates per week
  • 10 accounts per IP address per 3 hours

If you hit rate limits, use the staging environment for testing:

sudo certbot --nginx --staging -d your-domain.com

Port 80 must be accessible for HTTP-01 challenges. Check firewall settings:

sudo ufw status
sudo ufw allow 'Nginx Full'

For DNS resolution issues, verify your domain points to the correct IP:

dig your-domain.com
nslookup your-domain.com

If Certbot fails to modify Nginx configuration, check for syntax errors:

sudo nginx -t
sudo tail -f /var/log/nginx/error.log

Certificate chain issues can cause browser warnings. Verify the full chain:

openssl verify -CAfile /etc/ssl/certs/ca-certificates.crt /etc/letsencrypt/live/your-domain.com/fullchain.pem

Real-World Use Cases and Advanced Configurations

For high-traffic sites, consider implementing SSL session resumption and HTTP/2 push:

server {
    listen 443 ssl http2;
    
    # SSL session resumption for better performance
    ssl_session_cache shared:SSL:50m;
    ssl_session_timeout 1d;
    ssl_session_tickets off;
    
    # HTTP/2 Server Push for critical resources
    location = /index.html {
        add_header Link "; rel=preload; as=style, ; rel=preload; as=script";
        try_files $uri $uri/ =404;
    }
}

For API servers, you might want to implement certificate pinning headers:

add_header Public-Key-Pins 'pin-sha256="primary-key-hash"; pin-sha256="backup-key-hash"; max-age=2592000; includeSubDomains';

Load balancer configurations require special consideration for certificate management:

upstream backend {
    server 10.0.1.10:80;
    server 10.0.1.11:80;
}

server {
    listen 443 ssl http2;
    server_name api.your-domain.com;
    
    ssl_certificate /etc/letsencrypt/live/api.your-domain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/api.your-domain.com/privkey.pem;
    
    location / {
        proxy_pass http://backend;
        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;
    }
}

Best Practices and Security Considerations

Always backup your certificates and keys, especially before major system updates:

sudo cp -r /etc/letsencrypt /backup/letsencrypt-$(date +%Y%m%d)

Monitor certificate expiration dates proactively:

#!/bin/bash
for cert in /etc/letsencrypt/live/*/cert.pem; do
    domain=$(basename $(dirname $cert))
    expiry=$(openssl x509 -enddate -noout -in $cert | cut -d= -f2)
    echo "Domain: $domain expires on $expiry"
done

Implement proper log monitoring for SSL-related errors:

sudo tail -f /var/log/nginx/error.log | grep -i ssl

Consider using configuration management tools like Ansible for consistent SSL deployments across multiple servers. For high-availability setups, you might want to explore dedicated server solutions that provide the resources needed for complex SSL termination scenarios.

Regular security audits should include checking for weak cipher suites, outdated protocols, and proper HTTP security headers. The configuration provided here follows current best practices, but security standards evolve, so stay updated with the latest recommendations from Mozilla’s SSL Configuration Generator.

For development environments or smaller projects, VPS hosting can provide an excellent platform for implementing these SSL configurations while maintaining cost efficiency and full control over your server environment.



This article incorporates information and material from various online sources. We acknowledge and appreciate the work of all original authors, publishers, and websites. While every effort has been made to appropriately credit the source material, any unintentional oversight or omission does not constitute a copyright infringement. All trademarks, logos, and images mentioned are the property of their respective owners. If you believe that any content used in this article infringes upon your copyright, please contact us immediately for review and prompt action.

This article is intended for informational and educational purposes only and does not infringe on the rights of the copyright owners. If any copyrighted material has been used without proper credit or in violation of copyright laws, it is unintentional and we will rectify it promptly upon notification. Please note that the republishing, redistribution, or reproduction of part or all of the contents in any form is prohibited without express written permission from the author and website owner. For permissions or further inquiries, please contact us.

Leave a reply

Your email address will not be published. Required fields are marked