Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Caddy Setup

Overview

Caddy is a modern web server that handles HTTPS automatically, reverse proxies, and static file serving with minimal configuration. Unlike traditional servers, Caddy obtains and renews SSL certificates from Let’s Encrypt on its own — no separate tool like Certbot required.

This guide runs Caddy as a Docker container via Docker Compose, which keeps the host clean and makes the configuration portable.

Prerequisites

What is a domain? A domain (like example.com) is a human-readable address that points to your server’s IP address. You can buy domains from registrars like Namecheap, Cloudflare, or Google Domains. After buying a domain, you need to create an A record in your DNS settings that points to your VPS’s IP address. Caddy needs this to verify you own the domain and issue an SSL certificate.

Firewall Rules

Caddy needs ports 80 (HTTP) and 443 (HTTPS) open so it can serve traffic and complete ACME challenges:

sudo ufw allow 80/tcp
sudo ufw allow 443/tcp

Docker Compose Deployment

Create the Caddy directory:

sudo mkdir -p /opt/caddy && cd /opt/caddy

Create the Caddyfile:

sudo vim Caddyfile

A minimal reverse proxy configuration looks like this:

<domain> {
    reverse_proxy <service-name>:<port>
}

Create docker-compose.yml:

services:
  caddy:
    image: caddy:2
    container_name: caddy
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile
      - caddy_data:/data
      - caddy_config:/config
    networks:
      - caddy
    restart: unless-stopped

volumes:
  caddy_data:
  caddy_config:

networks:
  caddy:
    external: true

Create the external network before starting Caddy:

sudo docker network create caddy
Volume / NetworkPurpose
./CaddyfileYour server configuration
caddy_dataTLS certificates and state (persisted)
caddy_configCaddy’s internal config
caddy (external)Shared network for Caddy to reach other containers

Start Caddy:

sudo docker compose up -d

Caddy will automatically obtain an SSL certificate for <domain> and begin serving HTTPS.

Connecting Other Services

Each of your services lives in its own Docker Compose project under /opt. To let Caddy reverse proxy to them, attach each service to the external caddy network.

In the service’s docker-compose.yml, add:

services:
  <service-name>:
    # ... existing config ...
    networks:
      - caddy

networks:
  caddy:
    external: true

Then recreate the container to join the network:

cd /opt/<service-name>
sudo docker compose up -d

Once connected, Caddy can reach the service by its Compose service name:

<domain> {
    reverse_proxy <service-name>:<port>
}

Caddyfile Basics

Reverse Proxy to a Container

With the shared caddy network, use the service name from the target Compose file:

calibre.<yourdomain>.com {
    reverse_proxy calibre-web:8083
}

Static File Serving

Serve files from a directory inside the Caddy container:

<domain> {
    root * /usr/share/caddy
    file_server
}

Mount the files into the container:

services:
  caddy:
    # ...
    volumes:
      - ./site:/usr/share/caddy

Multiple Sites

Caddy handles multiple sites in one Caddyfile:

calibre.<yourdomain>.com {
    reverse_proxy calibre-web:8083
}

linkding.<yourdomain>.com {
    reverse_proxy linkding:9090
}

Common Commands

cd /opt/caddy
sudo docker compose up -d          # Start Caddy
sudo docker compose down           # Stop and remove
sudo docker compose logs -f caddy  # Follow logs
sudo docker compose restart caddy  # Restart after Caddyfile changes

After editing Caddyfile, Caddy auto-reloads in most cases. If not, restart the container:

sudo docker compose restart caddy

Notes

  • Caddy stores certificates in the caddy_data volume. Do not delete this volume unless you want to reissue certificates.
  • The caddy Docker network is external so multiple Compose projects can attach to it. Create it once with docker network create caddy.
  • If you need to use a wildcard certificate or a DNS provider challenge, Caddy supports those via modules, but the default HTTP/ALPN challenge works for standard domains without extra configuration.