Implement Nginx SSL certificate automation with Let's Encrypt using Certbot

Intermediate 35 min May 27, 2026 98 views
Ubuntu 24.04 Debian 12 AlmaLinux 9 Rocky Linux 9

Set up automated SSL certificate management for Nginx using Let's Encrypt and Certbot. Configure automatic certificate renewal, implement SSL security hardening, and monitor certificate health for production websites.

Prerequisites

  • Root or sudo access to the server
  • Domain name pointed to server
  • Nginx installed and running
  • Port 80 and 443 accessible

What this solves

Manual SSL certificate management creates security risks and service interruptions when certificates expire unexpectedly. This tutorial implements automated SSL certificate management for Nginx using Let's Encrypt and Certbot, with automatic renewal and monitoring to ensure your websites maintain HTTPS without manual intervention.

Step-by-step installation

Update system packages

Start by updating your package manager to ensure you get the latest versions of all packages.

sudo apt update && sudo apt upgrade -y
sudo dnf update -y

Install Nginx if not already present

Ensure Nginx is installed and running before configuring SSL certificates.

sudo apt install -y nginx
sudo systemctl enable --now nginx
sudo dnf install -y nginx
sudo systemctl enable --now nginx

Install Certbot and Nginx plugin

Install Certbot with the Nginx plugin to enable automatic certificate installation and configuration.

sudo apt install -y certbot python3-certbot-nginx
sudo dnf install -y certbot python3-certbot-nginx

Configure Nginx virtual host

Create a basic Nginx virtual host configuration for your domain. This initial configuration uses HTTP only, which Certbot will automatically upgrade to HTTPS.

server {
    listen 80;
    listen [::]:80;
    server_name example.com www.example.com;
    root /var/www/html;
    index index.html index.htm;

    location / {
        try_files $uri $uri/ =404;
    }

    location /.well-known/acme-challenge/ {
        root /var/www/html;
    }
}

Enable the virtual host

Create a symbolic link to enable the virtual host and test the Nginx configuration.

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

Create web root directory

Create the web root directory and set proper permissions for the web server to serve files.

sudo mkdir -p /var/www/html
sudo chown -R www-data:www-data /var/www/html
sudo chmod -R 755 /var/www/html
Never use chmod 777. It gives every user on the system full access to your files. The correct permissions are 755 for directories and 644 for files, with proper ownership set to the web server user.

Create test content

Add a simple test page to verify the web server is working before obtaining SSL certificates.




    SSL Test Page


    

SSL Certificate Automation Test

This page will be served over HTTPS after certificate installation.

SSL certificate automation configuration

Obtain SSL certificates with Certbot

Use Certbot to automatically obtain and install SSL certificates for your domain. The nginx plugin will automatically modify your Nginx configuration to use HTTPS.

sudo certbot --nginx -d example.com -d www.example.com --email admin@example.com --agree-tos --non-interactive
Note: Replace example.com with your actual domain name and admin@example.com with a valid email address for certificate notifications.

Verify SSL certificate installation

Check that Certbot successfully modified your Nginx configuration and installed the SSL certificate.

sudo certbot certificates
sudo nginx -t

Configure automatic renewal with systemd timer

Create a systemd timer for automatic certificate renewal instead of relying on cron. This provides better logging and monitoring capabilities.

[Unit]
Description=Certbot SSL certificate renewal
After=network.target

[Service]
Type=oneshot
ExecStart=/usr/bin/certbot renew --quiet --nginx --post-hook "systemctl reload nginx"
User=root

Create systemd timer configuration

Configure the timer to run certificate renewal checks twice daily to ensure certificates are renewed well before expiration.

[Unit]
Description=Run Certbot SSL renewal twice daily
Requires=certbot-renewal.service

[Timer]
OnCalendar=--* 00,12:00:00
RandomizedDelaySec=3600
Persistent=true

[Install]
WantedBy=timers.target

Enable and start the renewal timer

Enable the systemd timer to ensure automatic certificate renewal continues after system reboots.

sudo systemctl daemon-reload
sudo systemctl enable --now certbot-renewal.timer
sudo systemctl status certbot-renewal.timer

SSL security hardening

Configure SSL security parameters

Create a shared SSL configuration file with modern security settings to be included in all virtual hosts.

# Modern SSL configuration
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers off;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;
ssl_ecdh_curve secp384r1;
ssl_session_timeout 10m;
ssl_session_cache shared:SSL:10m;
ssl_session_tickets off;
ssl_stapling on;
ssl_stapling_verify on;

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 Referrer-Policy "strict-origin-when-cross-origin"; add_header X-XSS-Protection "1; mode=block";

Update virtual host with security parameters

Modify your virtual host configuration to include the SSL security parameters and ensure proper certificate handling.

server {
    listen 80;
    listen [::]:80;
    server_name example.com www.example.com;
    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name example.com www.example.com;
    root /var/www/html;
    index index.html index.htm;

    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
    include /etc/nginx/snippets/ssl-params.conf;

    location / {
        try_files $uri $uri/ =404;
    }

    location /.well-known/acme-challenge/ {
        root /var/www/html;
    }
}

Test and reload Nginx configuration

Verify the updated configuration and reload Nginx to apply the SSL security hardening.

sudo nginx -t
sudo systemctl reload nginx

Certificate monitoring and alerting

Create certificate monitoring script

Develop a monitoring script to check certificate expiration dates and send alerts if certificates are nearing expiration.

#!/bin/bash

SSL Certificate Expiry Monitor

DOMAINS=("example.com" "www.example.com") WARN_DAYS=30 ALERT_EMAIL="admin@example.com" LOGFILE="/var/log/ssl-monitor.log" for DOMAIN in "${DOMAINS[@]}"; do EXPIRY_DATE=$(echo | openssl s_client -servername $DOMAIN -connect $DOMAIN:443 2>/dev/null | openssl x509 -noout -dates | grep notAfter | cut -d= -f2) EXPIRY_EPOCH=$(date -d "$EXPIRY_DATE" +%s) CURRENT_EPOCH=$(date +%s) DAYS_UNTIL_EXPIRY=$(( (EXPIRY_EPOCH - CURRENT_EPOCH) / 86400 )) echo "$(date): $DOMAIN expires in $DAYS_UNTIL_EXPIRY days" >> $LOGFILE if [ $DAYS_UNTIL_EXPIRY -le $WARN_DAYS ]; then echo "SSL certificate for $DOMAIN expires in $DAYS_UNTIL_EXPIRY days" | mail -s "SSL Certificate Expiry Warning" $ALERT_EMAIL fi done

Make monitoring script executable

Set proper permissions for the monitoring script and create the log file.

sudo chmod +x /usr/local/bin/check-ssl-expiry.sh
sudo touch /var/log/ssl-monitor.log
sudo chown root:root /var/log/ssl-monitor.log
sudo chmod 644 /var/log/ssl-monitor.log

Schedule certificate monitoring

Create a cron job to run the certificate monitoring script daily and alert on certificates nearing expiration.

sudo crontab -e

Add this line to run the monitoring script daily at 8 AM:

0 8   * /usr/local/bin/check-ssl-expiry.sh

Configure log rotation for monitoring

Set up log rotation for the SSL monitoring log to prevent disk space issues.

/var/log/ssl-monitor.log {
    weekly
    missingok
    rotate 4
    compress
    delaycompress
    notifempty
    copytruncate
}

Advanced renewal configuration

Create renewal hooks directory

Set up directories for pre and post renewal hooks to customize certificate renewal behavior.

sudo mkdir -p /etc/letsencrypt/renewal-hooks/pre
sudo mkdir -p /etc/letsencrypt/renewal-hooks/post
sudo mkdir -p /etc/letsencrypt/renewal-hooks/deploy

Create post-renewal hook

Add a post-renewal hook to reload Nginx and log successful renewals for monitoring purposes.

#!/bin/bash

Post-renewal hook to reload Nginx and log renewal

echo "$(date): SSL certificates renewed successfully" >> /var/log/ssl-renewal.log

Reload Nginx to use new certificates

systemctl reload nginx

Verify Nginx is still running

if systemctl is-active --quiet nginx; then echo "$(date): Nginx reloaded successfully after certificate renewal" >> /var/log/ssl-renewal.log else echo "$(date): ERROR: Nginx failed to reload after certificate renewal" >> /var/log/ssl-renewal.log systemctl status nginx >> /var/log/ssl-renewal.log fi

Make renewal hook executable

Set proper permissions for the renewal hook script.

sudo chmod +x /etc/letsencrypt/renewal-hooks/post/reload-nginx.sh
sudo touch /var/log/ssl-renewal.log
sudo chown root:root /var/log/ssl-renewal.log
sudo chmod 644 /var/log/ssl-renewal.log

Test automatic renewal

Perform a dry run of the certificate renewal process to ensure everything works correctly.

sudo certbot renew --dry-run
sudo systemctl status certbot-renewal.timer

Verify your setup

Test your SSL certificate automation setup with these verification commands:

# Check certificate status and expiration
sudo certbot certificates

Verify SSL configuration

curl -I https://example.com

Test renewal timer status

sudo systemctl status certbot-renewal.timer sudo systemctl list-timers certbot-renewal.timer

Check SSL security grade (external tool)

curl -s "https://api.ssllabs.com/api/v3/analyze?host=example.com&publish=off"

Verify certificate chain

openssl s_client -connect example.com:443 -servername example.com

Check monitoring script

sudo /usr/local/bin/check-ssl-expiry.sh

Review logs

sudo tail -f /var/log/ssl-monitor.log sudo tail -f /var/log/ssl-renewal.log

Common issues

SymptomCauseFix
Certificate request failsDomain not pointing to serverVerify DNS records point to server IP
Renewal timer not runningService disabled or failedsudo systemctl enable --now certbot-renewal.timer
Nginx fails to reload after renewalConfiguration syntax errorsudo nginx -t to check configuration
SSL certificate not trustedIncomplete certificate chainUse fullchain.pem instead of cert.pem
Rate limit exceededToo many certificate requestsWait for rate limit reset, use staging environment for testing
Port 80 blockedFirewall blocking HTTPOpen port 80: sudo ufw allow 80/tcp
Monitoring script failsMissing mail commandInstall mailutils: sudo apt install mailutils
Permission denied on webrootIncorrect ownership/permissionssudo chown -R www-data:www-data /var/www/html

Next steps

Running this in production?

Want this handled for you? Setting up SSL automation once is straightforward. Keeping it monitored, maintained, and integrated with your broader infrastructure across environments is the harder part. See how we run infrastructure like this for European SaaS and e-commerce teams.

Automated install script

Run this to automate the entire setup

Need help?

Don't want to manage this yourself?

We handle infrastructure security hardening for businesses that depend on uptime. From initial setup to ongoing operations.