Tutorial Self-Hosting
Secure Docker services with Caddy on a VPS

Secure Docker services with Caddy on a VPS

Deploying containerized web services on a virtual private server requires a reliable reverse proxy that handles automatic TLS certificates without complex maintenance. This tutorial assumes you already have Docker installed on your VPS, and you already have a domain configured.

Setting up the core network and Caddy

To allow multiple separate Docker Compose stacks to communicate securely through a single reverse proxy, create an external Docker network named ingress by running this command:

mkdir -p /srv/core-and-shared/caddy
cd /srv/core-and-shared/caddy

Next, create the directory structure for Caddy and place this code in /srv/core-and-shared/caddy/compose.yaml:

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

volumes:
  caddy-data:
  caddy-config:

networks:
  caddy:
    name: caddy

Configuring the Caddyfile and cloudflare tunnel

Put this code in /srv/core-and-shared/caddy/Caddyfile, replacing the example domain with your own. The test configuration uses test.lulzcasz.dev, and you will need to point your domain to your VPS:

<domain> {
    respond "Hello World!"
}

If you prefer running your proxy behind a secure tunnel rather than opening direct inbound firewall ports, you can integrate a Cloudflare tunnel by creating /srv/core-and-shared/cloudflared/compose.yaml:

docker compose up -d

Testing the deployment

Once your containers are running, verify that everything responds correctly over HTTPS by running:

curl https://<domain>

For alternative architectures, you can review how to configure Caddy on a local server.

Use Caddy as a reverse proxy on a local server

Use Caddy as a reverse proxy on a local server

Learn how to configure Caddy as a local reverse proxy using Docker and Docker Compose, complete with automatic routing and Cloudflare Tunnel integration.

To scale containerized workloads into full-stack deployments, check out our guide on production hosting.

No Cover

Deploy Django in production with Docker