Securing your Dockerized web projects with HTTPS is essential, but Let’s Encrypt certificates need to Sure! Here’s a detailed blog post inspired by the original guide, with an extra focus on certbot’s deploy hook for certificate renewal—a key step that ensures your services update their configuration dynamically as soon as new certificates are issued.
Nginx and Let’s Encrypt with Docker—How to Add a Deploy Hook for Seamless Cert Renewal
Setting up Nginx with Let’s Encrypt in Docker is a classic move for secure, scalable websites and microservices. The usual guides get you through the initial setup, but there’s a critical enhancement rarely covered: automating service reload (or any action) instantly after certificate renewal using certbot’s deploy hook.
Below, I’ll walk you through the full stack setup—from Docker Compose to Nginx config, certbot automation, and the crucial deploy hook fix.
Step 1: Basic docker-compose.yml Setup
Start with nginx and certbot containers:
version: '3'
services:
nginx:
image: nginx:1.15-alpine
ports:
- "80:80"
- "443:443"
volumes:
- ./data/nginx:/etc/nginx/conf.d
- ./data/certbot/conf:/etc/letsencrypt
- ./data/certbot/www:/var/www/certbot
command: "/bin/sh -c 'while :; do sleep 6h & wait $${!}; nginx -s reload; done & nginx -g \"daemon off;\"'"
certbot:
image: certbot/certbot
volumes:
- ./data/certbot/conf:/etc/letsencrypt
- ./data/certbot/www:/var/www/certbot
entrypoint: "/bin/sh -c 'trap exit TERM; while :; do certbot renew; sleep 12h & wait $${!}; done;'"
Step 2: Nginx Configuration
Redirect HTTP to HTTPS & proxy requests, with challenge served from certbot volume:
server {
listen 80;
server_name yourdomain.com;
location /.well-known/acme-challenge/ {
root /var/www/certbot;
}
location / {
return 301 https://$host$request_uri;
}
}
server {
listen 443 ssl;
server_name yourdomain.com;
ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
location / {
proxy_pass http://your_backend_service:8080;
}
}
Step 3: Certificate Initialization Script
Use an enhanced init script to generate the first certificate, as in the original post. Store this as init-letsencrypt.sh, customizing domains and email as needed.
Step 4: Certificate Renewal—The Missing Piece: Deploy Hook
Most guides set up automatic renewal as shown above, but renewal alone isn’t enough. You want Nginx (or another service) to instantly reload or handle post-renewal actions whenever certbot issues a new certificate—not just on a fixed schedule!
Certbot’s deploy hook lets you do that:
Add the following to your renewal command in the certbot container’s entrypoint:
certbot renew --deploy-hook "nginx -s reload"
Or, for fine-grained control, point to a custom script. Example in entrypoint:
entrypoint: >
/bin/sh -c '
trap exit TERM;
while :; do
certbot renew --deploy-hook "/etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh";
sleep 12h & wait $${!};
done;'
And write reload-nginx.sh in /etc/letsencrypt/renewal-hooks/deploy/ (inside your certbot volume):
#!/bin/sh
echo "[deploy-hook] Reloading Nginx after cert renewal"
docker exec nginx_container_name nginx -s reload
Give it execute permissions:
chmod +x reload-nginx.sh
Why is this better?
- Nginx reloads immediately after renewal, not on a timer.
- You can add other logic (Slack notification, logging, etc.).
- Works with any service: just adjust the deploy hook script.
Wrap-Up
By enhancing the usual Docker Nginx + Let’s Encrypt stack with certbot’s deploy hook, you guarantee:
- Instant reloads of updated certificates.
- Reduced downtime risk.
- Straightforward extensibility for other post-renewal automation tasks.
If you found this helpful, follow for more practical DevOps fixes!