
Securing Your Full-Stack App with HTTPS Using Certbot and Docker
Securing Your Full-Stack App with HTTPS Using Certbot and Docker
Learn how to generate and configure free SSL certificates for your full-stack application using Certbot with Docker. This step-by-step guide covers HTTPS setup for Nginx, explains port requirements, domain configuration, and certificate renewal.
In Part 1 of this deployment series, we set up Nginx as a reverse proxy for your full-stack app (NestJS + Next.js) using Docker. If you haven’t read it yet, check it out here: Understanding Nginx for Fullstack Apps.
Let’s walk through how to generate and apply an SSL certificate using Let’s Encrypt + Certbot, all inside Docker.
📌 What You Need Before Starting
Before you can set up HTTPS, make sure the following are ready:
- ✅ You have a domain name (like
example.com
) purchased from a domain registrar. - ✅ Your domain has an A record pointing to your server’s public IP address.
- ✅ Port 80 (HTTP) is open on your server and not blocked by a firewall.
- ✅ Docker and Docker Compose are installed on your server.
Example: If your domain isexample.com
and your server's IP is192.0.2.1
, your A record should be:example.com → 192.0.2.1
🔒 Step 1: Run Certbot in a Temporary Container
Certbot needs to verify your domain via HTTP challenge on port 80. We’ll run Certbot as a one-time container to generate the certificate.
Create a directory to store certificates:
mkdir -p ./certbot/conf mkdir -p ./certbot/www
Then run Certbot:
docker run --rm \ -v $(pwd)/certbot/www:/var/www/certbot \ -v $(pwd)/certbot/conf:/etc/letsencrypt \ certbot/certbot certonly \ --webroot -w /var/www/certbot \ -d example.com -d www.example.com
Replaceexample.com
with your domain. Certbot will create SSL certificates inside./certbot/conf
.
🔍 Why --webroot
?
Certbot will place a file inside /var/www/certbot/.well-known/...
which Let’s Encrypt must be able to reach via HTTP on port 80. This proves you own the domain.
⚙️ Step 2: Add SSL Configuration to Nginx
Now that you have your certificate files, update your Nginx config to support HTTPS.
Update your nginx/default.conf
to:
server { listen 80; server_name example.com www.example.com; location /.well-known/acme-challenge/ { root /var/www/certbot; } location / { return 301 https://$host$request_uri; } } server { listen 443 ssl; server_name example.com www.example.com; ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem; location /api/ { proxy_pass http://backend:5000/; proxy_set_header Host $host; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection 'upgrade'; proxy_cache_bypass $http_upgrade; } location / { proxy_pass http://frontend:3000/; proxy_set_header Host $host; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection 'upgrade'; proxy_cache_bypass $http_upgrade; } }
Don’t forget to replace example.com
with your domain.
Need help understanding this configuration? Review Part 1 of the series: Understanding Nginx for Fullstack Apps
🐳 Step 3: Mount Certbot Volumes in Docker Compose
Update your docker-compose.yml
:
nginx: image: nginx:alpine container_name: nginx_proxy ports: - "80:80" - "443:443" volumes: - ./nginx/default.conf:/etc/nginx/conf.d/default.conf - ./certbot/conf:/etc/letsencrypt - ./certbot/www:/var/www/certbot depends_on: - frontend - backend
Then restart services:
docker compose up -d --build
Now your site is accessible via https://example.com
🎉
🔁 Step 4: Auto-Renew SSL Certificates
Let’s Encrypt certificates expire every 90 days. Set up a cron job to renew them.
Create a shell script called renew_cert.sh
:
#!/bin/bash docker run --rm \ -v $(pwd)/certbot/www:/var/www/certbot \ -v $(pwd)/certbot/conf:/etc/letsencrypt \ certbot/certbot renew docker exec nginx_proxy nginx -s reload
Make it executable:
chmod +x renew_cert.sh
Schedule it using crontab:
crontab -e
Add this line to run daily at midnight:
0 0 * * * /path/to/your/renew_cert.sh >> /var/log/cert_renew.log 2>&1
This ensures your certificates never expire.
🧠 Summary
In this post, you learned:
- How to get free SSL certificates using Certbot
- How to configure Nginx for HTTPS inside Docker
- How to mount volumes and reload Nginx
- How to auto-renew your SSL certificates with a cron job
👉 Your app is now encrypted and production-ready!
📘 Still learning Docker? Read this first: Dockerize NestJS – Dockerfile & Compose
📘 Want to review the Nginx setup? Read Part 1 here: Understanding Nginx for Fullstack Apps
Need help? Reach out at kaisalhusrom.com or message me on LinkedIn.