Easier Alternative to Nginx + Let’s Encrypt with Caddy Docker Proxy
Managing SSL certificates and proxying Docker applications has traditionally required a combination of Nginx and Let’s Encrypt. While effective, this setup can feel overly complex for many use cases. Enter Caddy Docker Proxy, a tool that simplifies this process, making it ideal for small applications or CI/CD pipelines.
The Nginx + Let’s Encrypt Approach
Here’s a typical setup with Nginx and Let’s Encrypt:
services:
web:
image: nginx:latest
restart: always
volumes:
- ./public:/var/www/html
- ./conf.d:/etc/nginx/conf.d
- ./certbot/conf:/etc/nginx/ssl
- ./certbot/data:/var/www/certbot
ports:
- 80:80
- 443:443
certbot:
image: certbot/certbot:latest
command: certonly --webroot --webroot-path=/var/www/certbot --email [email protected] --agree-tos --no-eff-email -d domain.com -d www.domain.com
volumes:
- ./certbot/conf:/etc/letsencrypt
- ./certbot/logs:/var/log/letsencrypt
- ./certbot/data:/var/www/certbot
While functional, this setup involves managing configuration files, running Certbot for SSL, and integrating Nginx for proxying. For many, this is more work than necessary.
The Caddy Docker Proxy Alternative
Caddy simplifies this entire process by automatically managing SSL certificates and serving as a reverse proxy. Below is an example using Caddy Docker Proxy for a Grafana application:
services:
caddy:
image: lucaslorentz/caddy-docker-proxy:ci-alpine
ports:
- 80:80
- 443:443
environment:
- CADDY_INGRESS_NETWORKS=caddy
networks:
- caddy
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- caddy_data:/data
restart: unless-stopped
grafana:
environment:
GF_SERVER_ROOT_URL: "https://grafana.example.com"
GF_INSTALL_PLUGINS: "digiapulssi-breadcrumb-panel,grafana-polystat-panel"
image: grafana/grafana:latest
restart: unless-stopped
volumes:
- grafana-storage:/var/lib/grafana
- ./grafana/grafana.ini:/etc/grafana/grafana.ini
networks:
- caddy
labels:
caddy: grafana.example.com
caddy.reverse_proxy: "{{upstreams 3000}}"
How It Works
- Caddy listens on external ports and proxies traffic to your Docker applications.
- Applications define their domains using Docker labels (
caddy: your-domain.com
). - Caddy automatically fetches and manages SSL certificates for defined domains.
Example: Hosting a Ghost Blog
Here’s how to set up a blog using Ghost and Caddy:
services:
ghost:
image: ghost:latest
restart: always
networks:
- caddy
environment:
url: https://example.com
volumes:
- /opt/ghost_content:/var/lib/ghost/content
labels:
caddy: example.com
caddy.reverse_proxy: "{{upstreams 2368}}"
caddy:
image: lucaslorentz/caddy-docker-proxy:ci-alpine
ports:
- 80:80
- 443:443
environment:
- CADDY_INGRESS_NETWORKS=caddy
networks:
- caddy
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- caddy_data:/data
restart: unless-stopped
networks:
caddy:
external: true
volumes:
caddy_data: {}
Steps:
- Install Docker Compose.
- Create a Docker network with:
docker network create caddy
- Replace
example.com
with your domain. - Run:
docker-compose up -d
- Visit your domain to configure Ghost.
Why Use Caddy?
- Automation: SSL certificates are managed automatically.
- Simplicity: Configure apps with Docker labels.
- Performance: Caddy is lightweight and highly efficient.
- CI/CD Friendly: Works seamlessly in automated pipelines.
For small developers and CI/CD setups, Caddy is a game-changer. It offers an easier, more reliable alternative to Nginx + Let’s Encrypt. Give it a try and see how it simplifies your workflow!
For more tips, connect with me on LinkedIn, GitHub, or BlueSky.