Automating HTTPS with Docker, Nginx & Certbot

Collapse
X
 
  • Time
  • Show
Clear All
new posts
  • MyrinNew
    Senior Member
    • Feb 2024
    • 5175

    #1

    Automating HTTPS with Docker, Nginx & Certbot

    Secure web traffic with HTTPS is no longer optional — it’s expected. This guide shows how to automate certificate issuance and renewal using Docker, Nginx and Certbot, packaged so deployment is repeatable and low-maintenance. Target audience: developers and ops engineers comfortable with Docker and basic Linux commands.





    What you'll achieve

    • Deploy Nginx as a reverse proxy inside Docker.
    • Automatically obtain and renew Let's Encrypt TLS certificates using Certbot.
    • Keep configuration simple, reproducible, and safe for production.


    Prerequisites
    • Docker and Docker Compose installed on a host with a public domain name pointing to its IP.
    • Port 80 and 443 reachable from the internet.
    • Basic familiarity with Nginx configuration and Docker Compose.





    Project layout

    Create a project directory; inside it, you’ll have:
    • docker-compose.yml
    • nginx/
      • conf.d/
      • default.conf (or site-specific conf)
    • certbot/
      • www/ (for HTTP challenge files)
    • data/ (certificate storage)





    Step 1 — Write the Docker Compose file

    Compose will run two services: nginx and certbot. Nginx serves traffic and proxies ACME HTTP-01 challenges to Certbot’s challenge directory.


    Example docker-compose.yml:






    version: "3.8"
    services:
    nginx:
    image: nginx:stable-alpine
    ports:
    - "80:80"
    - "443:443"
    volumes:
    - ./nginx/conf.d:/etc/nginx/conf.d:ro
    - ./certbot/www:/var/www/certbot:ro
    - ./data:/etc/letsencrypt
    depends_on:
    - certbot
    restart: unless-stopped

    certbot:
    image: certbot/certbot
    volumes:
    - ./certbot/www:/var/www/certbot
    - ./data:/etc/letsencrypt
    entrypoint: /bin/sh -c "trap exit TERM; while :; do sleep 12h & wait $${!}; certbot renew --webroot -w /var/www/certbot --deploy-hook 'nginx -s reload' || true; done"
    restart: unless-stopped







    Notes:
    • Certificates live in ./data so they persist across container restarts.
    • Certbot is configured to periodically run renew and reload Nginx on success.





    Step 2 — Configure Nginx to handle ACME challenges and proxy traffic

    Create an Nginx server block that:
    • Serves /.well-known/acme-challenge from the certbot/www directory.
    • Proxies other requests to your upstream app.


    Example nginx/conf.d/default.conf:






    server {
    listen 80;
    server_name example.com www.example.com;

    location /.well-known/acme-challenge/ {
    alias /var/www/certbot/.well-known/acme-challenge/;
    }

    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;

    # Basic SSL hardening (tune for your needs)
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_prefer_server_ciphers on;

    location / {
    proxy_pass http://your_upstream:8080;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    }
    }







    Replace example.com and your_upstream accordingly.





    Step 3 — Obtain the initial certificate

    Before HTTPS works, Certbot needs initial issuance. Run a one-off certbot command to request certificates using the webroot plugin.


    Example command:






    docker-compose run --rm certbot certonly \
    --webroot -w /var/www/certbot \
    -d example.com -d www.example.com \
    --email you@example.com \
    --agree-tos \
    --no-eff-email







    If successful, certificates are written under ./data/live/example.com. Then start or restart the stack:






    docker-compose up -d







    Certbot will handle renewals automatically via the background loop in docker-compose.





    Step 4 — Validation & testing

    • Visit https://example.com and confirm the site loads with a valid certificate. Certificate should be issued by Let's Encrypt.
    • Test renewal simulation:




    docker-compose run --rm certbot renew --dry-run --webroot -w /var/www/certbot










    Troubleshooting checklist

    • DNS: Ensure domain points to the host IP.
    • Ports: Confirm 80 and 443 are open and not blocked by firewall.
    • File permissions: Nginx must be able to read the certbot/www path.
    • Nginx config test: inside container run nginx -t to check syntax.





    Security & operational tips

    • Store the data directory on encrypted disk if it contains sensitive keys.
    • Monitor certificate expiry with alerts (letsencrypt certs expire every 90 days).
    • Consider using a dedicated ACME container like dehydrated or an ACME client with webhook/notifications for more advanced flows.
    • For high-availability, move certificate issuance into a single central manager and distribute certs via secure sync.





    Optional enhancements

    • Use Docker labels + Traefik to automate routing and certs (alternative to this stack).
    • Add HSTS, OCSP stapling and stronger cipher suites in Nginx for production hardening.
    • Automate backups of ./data with rotation.







    More...
Working...