System Administration

Automated SSL Certificate Renewal for Docker Nginx

Prerequisites

  • Docker and Docker Compose installed
  • Nginx running in Docker container
  • Certbot installed on host
  • Sudo access

Step 1: Configure Passwordless Sudo

Install certbot

sudo apt install certbot

Allow certbot to run without password prompts:

# Create sudoers entry
echo "$USER ALL=(ALL) NOPASSWD: /usr/bin/certbot, /usr/bin/docker" | sudo tee /etc/sudoers.d/$USER-nopasswd

# Set permissions
sudo chmod 440 /etc/sudoers.d/$USER-nopasswd

# Test it works
sudo certbot --version

Step 2: Test Renewal

Find your paths and test the renewal process:

# Find your docker-compose.yml path
# Example: /home/user/myapp/docker-compose.yml

# Find your nginx container name
docker ps | grep nginx
# Example: nginx_prod, nginx, myapp_nginx

# Run dry-run test (doesn't actually renew)
sudo certbot renew --dry-run 
  --pre-hook "docker compose -f /path/to/docker-compose.yml stop nginx_container" 
  --post-hook "docker compose -f /path/to/docker-compose.yml start nginx_container"

Example with real paths:

sudo certbot renew --dry-run 
  --pre-hook "docker compose -f /home/yocto-admin/builds/ymB6__kg9/0/yocto.dev/pmpassport/docker-compose.yml stop nginx" 
  --post-hook "docker compose -f /home/yocto-admin/builds/ymB6__kg9/0/yocto.dev/pmpassport/docker-compose.yml start nginx"

Step 3: Add Cron Job

Automate daily renewal checks:

# Edit crontab
crontab -e

# Add this line (replace with your actual paths):
0 2 * * * sudo certbot renew --pre-hook "docker compose -f /path/to/docker-compose.yml stop nginx_container" --post-hook "docker compose -f /path/to/docker-compose.yml start nginx_container" >> /var/log/certbot-renew.log 2>&1

# Save and exit

Real example:

0 2 * * * sudo certbot renew --pre-hook "docker compose -f /home/yocto-admin/builds/ymB6__kg9/0/yocto.dev/pmpassport/docker-compose.yml stop nginx" --post-hook "docker compose -f /home/yocto-admin/builds/ymB6__kg9/0/yocto.dev/pmpassport/docker-compose.yml start nginx" >> /var/log/certbot-renew.log 2>&1

Verify it was added:

crontab -l

How It Works

  • Cron runs daily at 2 AM
  • Certbot checks if renewal is needed (within 30 days of expiry)
  • If not needed: Does nothing
  • If needed: Stops nginx → Renews certificate → Starts nginx
  • Logs everything to: /var/log/certbot-renew.log

Monitoring

Check if renewal happened

cat /var/log/certbot-renew.log

Check certificate expiry

sudo certbot certificates

Force renewal (for testing)

sudo certbot renew --force-renewal 
  --pre-hook "docker compose -f /path/to/docker-compose.yml stop nginx" 
  --post-hook "docker compose -f /path/to/docker-compose.yml start nginx"

Quick Troubleshooting

“Certificate not yet due for renewal”
→ Normal. Certbot only renews within 30 days of expiry.

“Port 80 already in use”
→ Check your nginx container name: docker ps

Cron not running
→ Test manually: Run the exact cron command from terminal

Complete Example

# Step 1: Configure sudo
echo "yocto-admin ALL=(ALL) NOPASSWD: /usr/bin/certbot, /usr/bin/docker" | sudo tee /etc/sudoers.d/yocto-admin-nopasswd
sudo chmod 440 /etc/sudoers.d/yocto-admin-nopasswd

# Step 2: Test
sudo certbot renew --dry-run 
  --pre-hook "docker compose -f /home/yocto-admin/builds/ymB6__kg9/0/yocto.dev/pmpassport/docker-compose.yml stop nginx" 
  --post-hook "docker compose -f /home/yocto-admin/builds/ymB6__kg9/0/yocto.dev/pmpassport/docker-compose.yml start nginx"

# Step 3: Automate
crontab -e
# Add:
0 2 * * * sudo certbot renew --pre-hook "docker compose -f /home/yocto-admin/builds/ymB6__kg9/0/yocto.dev/pmpassport/docker-compose.yml stop nginx" --post-hook "docker compose -f /home/yocto-admin/builds/ymB6__kg9/0/yocto.dev/pmpassport/docker-compose.yml start nginx" >> /var/log/certbot-renew.log 2>&1