Introduction

Remember the days when setting up SSL certificates meant hours of manual configuration, expensive certificate purchases, and the constant anxiety of forgetting renewal dates? Yeah, those days are thankfully behind us. Today, we’re diving into how you can completely automate SSL certificate management for your Dockerized applications using Let’s Encrypt, and trust me, once you set this up, you’ll wonder how you ever lived without it.
As Nepal’s digital landscape continues to grow and more businesses move online, having proper SSL certificates isn’t just a nice-to-have anymore; it’s absolutely essential. Whether you’re running an e-commerce site in Kathmandu or a SaaS platform serving clients across South Asia, your users expect that green padlock in their browser.
Why Automate SSL Certificates?
Let’s be honest, manual certificate management is a pain. I’ve seen too many websites go down because someone forgot to renew their SSL certificate. It’s embarrassing, bad for business, and completely avoidable in 2025.
Here’s what manual SSL management typically looks like:
- Purchase certificates annually (expensive!)
- Manual installation and configuration
- Setting calendar reminders for renewal
- Potential downtime during updates
- Risk of human error
With automation, you get:
- Free certificates from Let’s Encrypt
- Automatic renewal every 60-90 days
- Zero downtime during certificate updates
- Better security with always up-to-date certificates
- Peace of mind knowing your sites stay secure
Understanding Let’s Encrypt and Docker
Let’s Encrypt revolutionized SSL certificates by making them free and automatable. They issue certificates that are valid for 90 days, but here’s the genius part: they’re designed to be renewed automatically every 60 days.
When you combine this with Docker, you get a powerful, portable solution that works consistently across development, staging, and production environments. Whether you’re deploying on a VPS in Singapore or a dedicated server in Kathmandu, the setup remains the same.
The Tools We’ll Use
For this setup, we’ll be working with:
Tool | Purpose | Why We Choose It |
Certbot | Let’s Encrypt client | Official client, well-maintained |
Docker Compose | Container orchestration | Easy multi-container management |
Nginx | Reverse proxy/web server | Lightweight, excellent for SSL termination |
Cron or Systemd Timer | Renewal scheduling | Built into most Linux systems |
Method 1: Using Certbot Container with Nginx
This is probably the most straightforward approach and works great for most scenarios.
Step 1: Project Structure
First, let’s set up our project structure:
ssl-docker-app/
├── docker-compose.yml
├── nginx/
│ ├── nginx.conf
│ └── ssl.conf
├── certbot/
│ └── (certificates will go here)
├── web/
│ └── (your app files)
└── scripts/
└── renew-certs.sh
Step 2: Docker Compose Configuration
Here’s a solid docker-compose.yml that handles both your app and SSL automation:
version: '3.8'
services:
nginx:
image: nginx:alpine
container_name: nginx-proxy
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx/nginx.conf:/etc/nginx/nginx.conf
- ./nginx/ssl.conf:/etc/nginx/ssl.conf
- ./certbot/conf:/etc/letsencrypt
- ./certbot/www:/var/www/certbot
depends_on:
- app
restart: unless-stopped
app:
build: ./web
container_name: your-app
expose:
- "3000"
restart: unless-stopped
certbot:
image: certbot/certbot
container_name: certbot
volumes:
- ./certbot/conf:/etc/letsencrypt
- ./certbot/www:/var/www/certbot
command: certonly --webroot --webroot-path=/var/www/certbot --email your-email@example.com --agree-tos --no-eff-email -d yourdomain.com -d www.yourdomain.com
Step 3: Nginx Configuration
Your nginx.conf should handle both HTTP and HTTPS traffic:
events {
worker_connections 1024;
}
http {
upstream app {
server app:3000;
}
# HTTP server - handles ACME challenges and redirects
server {
listen 80;
server_name yourdomain.com www.yourdomain.com;
location /.well-known/acme-challenge/ {
root /var/www/certbot;
}
location / {
return 301 https://$server_name$request_uri;
}
}
# HTTPS server
server {
listen 443 ssl http2;
server_name yourdomain.com www.yourdomain.com;
ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;
include /etc/nginx/ssl.conf;
location / {
proxy_pass http://app;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
}
Step 4: SSL Security Configuration
Create an ssl.conf file for enhanced security:
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers off;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
# OCSP stapling
ssl_stapling on;
ssl_stapling_verify on;
# Security headers
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header X-Frame-Options DENY always;
add_header X-Content-Type-Options nosniff always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
Method 2: Using Traefik for Automatic SSL
If you want something even more automated, Traefik is fantastic. It handles SSL certificate generation and renewal automatically based on container labels.
Traefik Docker Compose Example
version: '3.8'
services:
traefik:
image: traefik:v3.0
container_name: traefik
ports:
- "80:80"
- "443:443"
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- ./traefik/acme.json:/acme.json
- ./traefik/traefik.yml:/traefik.yml
restart: unless-stopped
app:
build: ./web
container_name: your-app
labels:
- "traefik.enable=true"
- "traefik.http.routers.app.rule=Host(`yourdomain.com`)"
- "traefik.http.routers.app.tls=true"
- "traefik.http.routers.app.tls.certresolver=letsencrypt"
restart: unless-stopped
Setting Up Automatic Renewal
The beauty of this setup is in the automation. Here’s how to ensure your certificates renew automatically:
Option 1: Cron Job
Create a script /scripts/renew-certs.sh:
#!/bin/bash
# Navigate to your project directory
cd /path/to/your/ssl-docker-app
# Renew certificates
docker-compose exec certbot certbot renew --quiet
# Reload nginx to use new certificates
docker-compose exec nginx nginx -s reload
# Log the renewal attempt
echo "$(date): SSL renewal attempted" >> /var/log/ssl-renewal.log
Add to crontab (runs twice daily):
0 12 * * * /scripts/renew-certs.sh
0 0 * * * /scripts/renew-certs.sh
Option 2: Systemd Timer
Create /etc/systemd/system/ssl-renewal.service:
[Unit]
Description=SSL Certificate Renewal
After=docker.service
[Service]
Type=oneshot
ExecStart=/scripts/renew-certs.sh
User=your-user
And /etc/systemd/system/ssl-renewal.timer:
[Unit]
Description=Run SSL renewal twice daily
[Timer]
OnCalendar=*-*-* 00,12:00:00
Persistent=true
[Install]
WantedBy=timers.target
Enable with: sudo systemctl enable ssl-renewal.timer
Common Issues and Troubleshooting
Issue 1: Rate Limiting
Let’s Encrypt has rate limits. During testing, use their staging environment:
docker-compose exec certbot certbot certonly --staging --webroot --webroot-path=/var/www/certbot --email your-email@example.com --agree-tos -d yourdomain.com
Issue 2: DNS Propagation
Make sure your domain points to your server before requesting certificates. You can check with:
dig yourdomain.com
Issue 3: Firewall Issues
Ensure ports 80 and 443 are open:
sudo ufw allow 80
sudo ufw allow 443
Security Best Practices
- Keep Docker Images Updated: Regularly update your nginx and certbot images
- Monitor Certificate Expiry: Set up monitoring even with automation
- Use Strong SSL Configuration: Follow the SSL config we provided above
- Regular Backups: Back up your certificate directory
- Test Renewals: Regularly test your renewal process
Performance Considerations
For High-Traffic Sites
If you’re running high-traffic applications (which we see more of in Nepal’s growing tech scene), consider:
- SSL Session Resumption: Already configured in our SSL setup
- HTTP/2: Enabled in our nginx configuration
- OCSP Stapling: Reduces SSL handshake time
- Certificate Caching: Nginx handles this automatically
Resource Usage
This setup is quite lightweight:
- Nginx container: ~10MB RAM
- Certbot container: Only runs during renewal
- Minimal CPU usage outside of renewal periods
Monitoring and Maintenance
Set up basic monitoring to ensure everything’s working:
#!/bin/bash
# Check certificate expiry
EXPIRY=$(openssl x509 -enddate -noout -in /path/to/cert.pem | cut -d= -f2)
EXPIRY_DATE=$(date -d "$EXPIRY" +%s)
CURRENT_DATE=$(date +%s)
DAYS_LEFT=$(((EXPIRY_DATE - CURRENT_DATE) / 86400))
if [ $DAYS_LEFT -lt 30 ]; then
echo "Certificate expires in $DAYS_LEFT days!" | mail -s "SSL Certificate Warning" admin@yourdomain.com
Conclusion

Automating SSL certificates for your Dockerized applications isn’t just a nice-to-have – it’s essential for any serious deployment in 2025. With this setup, you get free, automatically renewing certificates that keep your applications secure without any manual intervention.
The initial setup might seem a bit involved, but once it’s running, you can literally forget about SSL certificate management. Your certificates will renew automatically, your users will see that green padlock, and you’ll sleep better knowing your applications are secure.
Whether you’re a startup in Pokhara or an enterprise in Lalitpur, this approach scales beautifully and works consistently across different hosting environments. At Nest Nepal, we’ve seen firsthand how proper SSL automation reduces support tickets and improves overall application reliability.
Remember to test your setup thoroughly in a staging environment first, and don’t hesitate to reach out if you run into any issues. Happy containerizing, and may your SSL certificates always be green!
Need help implementing SSL automation for your Dockerized applications? Our team at Nest Nepal specializes in secure, scalable hosting solutions for businesses across Nepal and beyond. Get in touch to learn how we can help secure your digital presence.