Docker Let's Encrypt SSL Certificate Renewal Fix
In this tutorial, you'll learn about Docker Let's Encrypt SSL Certificate Renewal Fix. We cover key concepts, practical examples, and best practices.
Let's Encrypt SSL certificates expire every 90 days, and renewal fails when Certbot cannot reach port 80, the webroot path is wrong, or Docker containers block the ACME challenge. Without renewal, browsers show "NET::ERR_CERT_DATE_INVALID".
The Problem
certbot renew
Error:
Attempting to renew cert (example.com) from /etc/letsencrypt/renewal/example.com.conf failed
http-01 challenge failed for domain example.com
Error: Could not issue certificate
Or in Docker:
docker run certbot/certbot renew
Error:
Certbot failed to authenticate some domains (timed out)
Wrong Approach
# WRONG — running Certbot outside Docker while Nginx is inside
certbot certonly --webroot -d example.com
# Fails because Certbot cannot access the webroot inside the container
Right Approach
# Mount the webroot and Nginx config, share the network
docker run --rm \
-v /docker/nginx/html:/usr/share/nginx/html \
-v /docker/certbot/etc:/etc/letsencrypt \
-v /docker/certbot/lib:/var/lib/letsencrypt \
certbot/certbot certonly --webroot \
-w /usr/share/nginx/html \
-d example.com
Expected output:
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Successfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/example.com/fullchain.pem
Step-by-Step Fix
Step 1: Set up shared volumes in docker-compose
services:
nginx:
image: nginx
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx/conf:/etc/nginx/conf.d
- ./nginx/html:/usr/share/nginx/html
- ./certbot/etc:/etc/letsencrypt
- ./certbot/lib:/var/lib/letsencrypt
certbot:
image: certbot/certbot
volumes:
- ./nginx/html:/usr/share/nginx/html
- ./certbot/etc:/etc/letsencrypt
- ./certbot/lib:/var/lib/letsencrypt
entrypoint: "/bin/sh -c 'trap exit TERM; while :; do certbot renew; sleep 12h & wait $${!}; done;'"
Step 2: Obtain the initial certificate
docker compose run --rm certbot certonly --webroot \
-w /usr/share/nginx/html -d example.com
Step 3: Configure Nginx to use the certificate
server {
listen 443 ssl;
server_name example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
}
Step 4: Test renewal manually
docker compose run --rm certbot renew --dry-run
Step 5: Automate renewal with a cron job
0 3 * * * cd /docker && docker compose run --rm certbot renew && docker compose exec nginx nginx -s reload
Prevention Tips
- Mount the same webroot and cert volumes in both Nginx and Certbot containers
- Always test renewal with
--dry-runbefore relying on automation - Set up a cron job to run renewal and Nginx reload
- Monitor certificate expiry with
openssl x509 -checkend 86400 - Use Certbot DNS plugins for domains behind firewalls that block port 80
Common Mistakes with letsencrypt ssl
- Overlapping type class instances that cause GHC to reject the program with ambiguous dispatch errors
- Non-exhaustive pattern matches that compile with warnings then crash at runtime
- Misunderstanding that
Stringis[Char]with poor performance for large text operations
These mistakes appear frequently in real-world DOCKER code. DodaTech's contributors have identified these patterns through analysis of open-source projects and production systems.
Practice Exercise
Write a pure function that safely divides two integers using Maybe, then test it with edge cases like division by zero and negative numbers.
This exercise reinforces the concepts covered in this guide. Try implementing it before checking online solutions.
FAQ
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro