Configure NGINX SSL certificate automation with Certbot and renewal monitoring

Intermediate 25 min Apr 30, 2026 141 views
Ubuntu 24.04 Debian 12 AlmaLinux 9 Rocky Linux 9

Set up automated SSL certificate provisioning and renewal for NGINX using Let's Encrypt Certbot with systemd timers, monitoring, and failure alerting for production environments.

Prerequisites

  • Root or sudo access
  • Domain name pointing to your server
  • NGINX web server
  • Internet connectivity for Let's Encrypt validation

What this solves

Manual SSL certificate management creates security risks and service interruptions when certificates expire unexpectedly. This tutorial automates SSL certificate provisioning, renewal, and monitoring for NGINX using Let's Encrypt Certbot with systemd timers, ensuring your web services maintain valid certificates without manual intervention.

Step-by-step configuration

Install NGINX and Certbot

Install NGINX web server and Certbot for Let's Encrypt certificate management.

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

Configure NGINX virtual host

Create a basic NGINX virtual host configuration for your domain before requesting SSL certificates.

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

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

    location /.well-known/acme-challenge/ {
        root /var/www/example.com;
        allow all;
    }
}

Create web root directory

Set up the web root directory with proper permissions for NGINX and Certbot validation.

sudo mkdir -p /var/www/example.com
sudo chown -R www-data:www-data /var/www/example.com
sudo chmod -R 755 /var/www/example.com
echo "

Welcome to example.com

" | sudo tee /var/www/example.com/index.html

Enable site and test configuration

Enable the virtual host and verify NGINX configuration syntax.

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

Request SSL certificate with Certbot

Use Certbot to request and automatically configure SSL certificates for your domain.

sudo certbot --nginx -d example.com -d www.example.com --email admin@example.com --agree-tos --no-eff-email
Note: Replace admin@example.com with your actual email address. This email receives expiration warnings as a backup to automated renewal.

Verify SSL certificate installation

Check that Certbot successfully modified your NGINX configuration with SSL settings.

sudo nginx -t
sudo systemctl reload nginx
sudo certbot certificates

Create certificate renewal script

Create a renewal script that handles certificate renewal and NGINX reloading with logging.

#!/bin/bash

Certbot renewal script with logging and error handling

LOG_FILE="/var/log/certbot-renewal.log" DATE=$(date '+%Y-%m-%d %H:%M:%S') echo "[$DATE] Starting certificate renewal check" >> "$LOG_FILE"

Attempt renewal

if /usr/bin/certbot renew --quiet --nginx >> "$LOG_FILE" 2>&1; then echo "[$DATE] Certificate renewal check completed successfully" >> "$LOG_FILE" # Test nginx configuration if /usr/sbin/nginx -t >> "$LOG_FILE" 2>&1; then # Reload nginx if config is valid /bin/systemctl reload nginx >> "$LOG_FILE" 2>&1 echo "[$DATE] NGINX reloaded successfully" >> "$LOG_FILE" else echo "[$DATE] ERROR: NGINX configuration test failed" >> "$LOG_FILE" exit 1 fi else echo "[$DATE] ERROR: Certificate renewal failed" >> "$LOG_FILE" exit 1 fi echo "[$DATE] Renewal process completed" >> "$LOG_FILE"

Make renewal script executable

Set proper permissions for the renewal script.

sudo chmod +x /usr/local/bin/certbot-renewal.sh
sudo chown root:root /usr/local/bin/certbot-renewal.sh

Create systemd service for renewal

Create a systemd service unit for certificate renewal.

[Unit]
Description=Certbot SSL Certificate Renewal
After=network.target

[Service]
Type=oneshot
User=root
ExecStart=/usr/local/bin/certbot-renewal.sh
StandardOutput=journal
StandardError=journal

Create systemd timer for automatic renewal

Configure a systemd timer to run certificate renewal checks twice daily.

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

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

[Install]
WantedBy=timers.target

Enable and start the renewal timer

Enable the systemd timer to start automatically and begin running renewal checks.

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

Create certificate monitoring script

Create a monitoring script to check certificate expiration and send alerts.

#!/bin/bash

Certificate monitoring script

WARN_DAYS=30 CRIT_DAYS=7 LOG_FILE="/var/log/cert-monitor.log" DATE=$(date '+%Y-%m-%d %H:%M:%S')

Function to check certificate expiration

check_cert() { local domain="$1" local exp_date local exp_epoch local now_epoch local days_until_exp exp_date=$(echo | openssl s_client -servername "$domain" -connect "$domain:443" 2>/dev/null | \ openssl x509 -noout -enddate 2>/dev/null | cut -d= -f2) if [ -z "$exp_date" ]; then echo "[$DATE] ERROR: Could not retrieve certificate for $domain" >> "$LOG_FILE" return 1 fi exp_epoch=$(date -d "$exp_date" +%s) now_epoch=$(date +%s) days_until_exp=$(( (exp_epoch - now_epoch) / 86400 )) echo "[$DATE] Certificate for $domain expires in $days_until_exp days" >> "$LOG_FILE" if [ "$days_until_exp" -lt "$CRIT_DAYS" ]; then echo "[$DATE] CRITICAL: Certificate for $domain expires in $days_until_exp days!" >> "$LOG_FILE" logger -p daemon.crit "SSL Certificate CRITICAL: $domain expires in $days_until_exp days" elif [ "$days_until_exp" -lt "$WARN_DAYS" ]; then echo "[$DATE] WARNING: Certificate for $domain expires in $days_until_exp days" >> "$LOG_FILE" logger -p daemon.warning "SSL Certificate WARNING: $domain expires in $days_until_exp days" fi }

Check certificates for all configured domains

for cert_file in /etc/letsencrypt/live/*/cert.pem; do if [ -f "$cert_file" ]; then cert_dir=$(dirname "$cert_file") domain=$(basename "$cert_dir") check_cert "$domain" fi done

Make monitoring script executable

Set permissions for the certificate monitoring script.

sudo chmod +x /usr/local/bin/cert-monitor.sh
sudo chown root:root /usr/local/bin/cert-monitor.sh

Create monitoring systemd service and timer

Set up systemd service and timer for certificate expiration monitoring.

[Unit]
Description=SSL Certificate Expiration Monitor
After=network.target

[Service]
Type=oneshot
User=root
ExecStart=/usr/local/bin/cert-monitor.sh
StandardOutput=journal
StandardError=journal
[Unit]
Description=Run SSL certificate monitoring daily
Requires=cert-monitor.service

[Timer]
OnCalendar=daily
RandomizedDelaySec=1800
Persistent=true

[Install]
WantedBy=timers.target

Enable certificate monitoring

Enable and start the certificate monitoring timer.

sudo systemctl daemon-reload
sudo systemctl enable cert-monitor.timer
sudo systemctl start cert-monitor.timer
sudo systemctl status cert-monitor.timer

Configure log rotation

Set up log rotation for certificate renewal and monitoring logs to prevent disk space issues.

/var/log/certbot-renewal.log /var/log/cert-monitor.log {
    weekly
    rotate 12
    compress
    delaycompress
    missingok
    notifempty
    create 644 root root
}

Verify your setup

Test your SSL certificate automation and monitoring configuration.

# Check SSL certificate status
sudo certbot certificates

Test renewal process (dry run)

sudo certbot renew --dry-run

Check systemd timers

sudo systemctl list-timers | grep cert

Test certificate monitoring

sudo /usr/local/bin/cert-monitor.sh

Check logs

sudo tail -f /var/log/certbot-renewal.log sudo tail -f /var/log/cert-monitor.log

Test SSL configuration

curl -I https://example.com openssl s_client -connect example.com:443 -servername example.com

Common issues

Symptom Cause Fix
Certbot validation fails DNS not pointing to server or firewall blocking port 80 Verify DNS with dig example.com and check firewall rules
NGINX fails to reload after renewal Invalid NGINX configuration Test config with sudo nginx -t and fix syntax errors
Certificate renewal timer not running Timer not enabled or systemd issues Check with sudo systemctl status certbot-renewal.timer
Monitoring script shows SSL errors Certificate not properly installed or expired Re-run Certbot with sudo certbot --nginx -d example.com
Log files growing too large Logrotate not configured properly Test logrotate with sudo logrotate -d /etc/logrotate.d/certbot-logs

Next steps

Running this in production?

Want this handled for you? Setting this up once is straightforward. Keeping it patched, monitored, backed up and performant across environments is the harder part. See how we run infrastructure like this for European teams.

Automated install script

Run this to automate the entire setup

Need help?

Don't want to manage this yourself?

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