Skip to content

Caddy

Docker Compose deployment guide for Caddy on Ubuntu.

Caddy is a modern web server and reverse proxy that automatically obtains and renews HTTPS certificates.

This makes it an excellent choice for self-hosted applications and homelab environments.

Official project:


Create the Project Folder

mkdir -p ~/docker/caddy
cd ~/docker/caddy

Create the Docker Compose File

Create:

nano docker-compose.yml

Paste:

services:
  caddy:
    image: caddy:latest
    container_name: caddy

    ports:
      - "80:80"
      - "443:443"

    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile
      - ./data:/data
      - ./config:/config

    restart: unless-stopped

Create the Caddyfile

Create:

nano Caddyfile

Paste:

example.com {
    reverse_proxy 192.168.1.100:8080
}

Replace:

  • example.com with your domain name
  • 192.168.1.100:8080 with the IP address and port of the application you want to publish

Start Caddy

Run:

docker compose up -d

Configure DNS

Create an A record pointing your domain or subdomain to your public IP address.

Example:

Type: A
Name: jellyfin
Content: YOUR_PUBLIC_IP

Result:

https://jellyfin.example.com

When traffic reaches Caddy, it will automatically request and renew HTTPS certificates.


Access Your Application

Open:

https://your-domain.com

or

https://your-subdomain.example.com

Example Reverse Proxy Configurations

Jellyfin:

jellyfin.example.com {
    reverse_proxy 192.168.1.100:8096
}

Vaultwarden:

vaultwarden.example.com {
    reverse_proxy 192.168.1.100:8122
}

Paperless-ngx:

paperless.example.com {
    reverse_proxy 192.168.1.100:8456
}

Home Assistant:

homeassistant.example.com {
    reverse_proxy 192.168.1.100:8123
}

Notes

  • Ports 80 and 443 must be accessible from the internet
  • DNS records must point to your public IP address
  • HTTPS certificates are managed automatically
  • No manual certificate renewal is required
  • Most homelab users run a single Caddy instance for all services

Advanced Example (Reference Only)

This is my current deployment.

It includes:

  • Automatic HTTPS via Caddy
  • Multiple reverse proxies
  • Dynamic DNS updates through Cloudflare
  • Automatic DNS updates when the public IP address changes
services:
  caddy:
    image: caddy:latest
    container_name: caddy
    stop_grace_period: 30s
    restart: unless-stopped

    ports:
      - "80:80"
      - "443:443"

    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile
      - ./data:/data
      - ./config:/config

  cloudflare-ddns:
    image: oznu/cloudflare-ddns:latest
    container_name: cloudflare-ddns
    restart: unless-stopped

    environment:
      - API_KEY=your_cloudflare_api_token
      - ZONE=example.com
      - SUBDOMAIN=*
      - PROXIED=false

Example Caddyfile:

jellyfin.example.com {
    reverse_proxy 192.168.1.100:8096
}

vaultwarden.example.com {
    reverse_proxy 192.168.1.100:8122
}

paperless.example.com {
    reverse_proxy 192.168.1.100:8456
}

homeassistant.example.com {
    reverse_proxy 192.168.1.100:8123
}

Why My Setup Differs from the Basic Example

My homelab uses Caddy as a central reverse proxy for all internet-facing services.

Combining Caddy with Cloudflare Dynamic DNS provides:

  • Automatic HTTPS certificates
  • Automatic certificate renewal
  • Centralised reverse proxy management
  • Automatic DNS updates after ISP IP changes
  • Simple configuration and maintenance

For most users, the basic deployment shown earlier in this guide is sufficient. This advanced example is included as a reference for readers who want to explore a more complete homelab setup.


Conclusion

Caddy is one of the easiest reverse proxies to deploy and maintain.

For homelab users, it provides automatic HTTPS, simple configuration, and reliable reverse proxy functionality with very little ongoing maintenance.