Part 3 – Caddy Reverse Proxy
Without a reverse proxy, every service runs on its own port — Nextcloud on 8080, Jellyfin on 8096, Vaultwarden on 8200, and so on. Caddy solves this by routing traffic based on the domain name, with HTTPS handled automatically via Tailscale certificates.
After this part, every service gets a clean URL like nextcloud.wcp with valid HTTPS — no certificate warnings, no browser complaints.
Prerequisites
- ✅ Docker and the
wcp-networkDocker network created - ✅ Tailscale connected and running
- ✅ MagicDNS enabled in Tailscale admin console
→ Follow Part 2 first.
How this setup works
Caddy runs as a Docker container on the wcp-network. Services that require HTTPS (Nextcloud, Vaultwarden) get Tailscale-issued certificates — trusted by all your Tailscale-connected devices without any warnings. Other services run on HTTP since they don’t need secure context.
Step 1 – Get Tailscale certificates
Tailscale can issue valid HTTPS certificates for your machine’s Tailscale hostname:
sudo tailscale cert wcpThis creates two files:
/var/lib/tailscale/certs/wcp.crt
/var/lib/tailscale/certs/wcp.keywcp with your actual Tailscale machine name if you named it differently. Check with tailscale status.Step 2 – Create the Caddy folder
mkdir -p /opt/docker/caddy/data
mkdir -p /opt/docker/caddy/config
cd /opt/docker/caddyStep 3 – Create the Caddyfile
nano Caddyfile# Global options
{
admin off
auto_https off
}
# Services requiring HTTPS (secure context)
https://nextcloud.wcp {
tls /certs/wcp.crt /certs/wcp.key
reverse_proxy nextcloud:80
}
https://vault.wcp {
tls /certs/wcp.crt /certs/wcp.key
reverse_proxy vaultwarden:80
}
# Services that work fine on HTTP
jellyfin.wcp {
reverse_proxy jellyfin:8096
}
immich.wcp {
reverse_proxy immich-server:2283
}
ai.wcp {
reverse_proxy open-webui:8080
}
status.wcp {
reverse_proxy uptime-kuma:3001
}
sync.wcp {
reverse_proxy syncthing:8384
}Step 4 – Create the compose.yml
nano compose.ymlservices:
caddy:
image: caddy:latest
container_name: caddy
ports:
- "80:80"
- "443:443"
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile
- ./data:/data
- ./config:/config
- /var/lib/tailscale/certs:/certs:ro
networks:
- wcp-network
restart: unless-stopped
networks:
wcp-network:
external: trueKey addition: /var/lib/tailscale/certs:/certs:ro mounts the Tailscale certificates into the Caddy container read-only.
Step 5 – Start Caddy
docker compose up -d
docker compose logs -fPress CTRL+C when running.
Step 6 – Set Up Local DNS
For hostnames like nextcloud.wcp to resolve on your devices, add entries to the hosts file on each machine.
On your Mac:
sudo nano /etc/hostsAdd (replace with your WCP machine’s Tailscale IP):
100.x.x.x nextcloud.wcp
100.x.x.x jellyfin.wcp
100.x.x.x immich.wcp
100.x.x.x ai.wcp
100.x.x.x vault.wcp
100.x.x.x status.wcp
100.x.x.x sync.wcpOn iPhone/iPad via Tailscale DNS:
In the Tailscale admin console under DNS → Nameservers, add a custom nameserver pointing to your WCP machine. This resolves .wcp hostnames automatically for all Tailscale-connected devices including phones.
Renewing Tailscale certificates
Tailscale certificates expire and need to be renewed periodically. Automate this with a cron job:
sudo crontab -eAdd:
0 0 1 * * tailscale cert wcp && docker exec caddy caddy reload --config /etc/caddy/CaddyfileThis renews the cert and reloads Caddy on the 1st of every month.
Adding new services
Every time a new service is added, add a block to the Caddyfile:
# For services that don't need HTTPS
newservice.wcp {
reverse_proxy container-name:port
}
# For services that need HTTPS
https://newservice.wcp {
tls /certs/wcp.crt /certs/wcp.key
reverse_proxy container-name:port
}Then reload Caddy:
docker exec caddy caddy reload --config /etc/caddy/CaddyfileUseful commands
| Command | What it does |
|---|---|
docker compose up -d |
Start Caddy |
docker compose logs -f |
Follow live logs |
docker exec caddy caddy reload --config /etc/caddy/Caddyfile |
Reload config without restart |
docker exec caddy caddy validate --config /etc/caddy/Caddyfile |
Check config for errors |
sudo tailscale cert wcp |
Renew Tailscale certificate |
What’s next
With Caddy in place and HTTPS working, Part 4 deploys Nextcloud — your private Google Drive.
Up next: Part 4 – Nextcloud (coming soon)
Related guides
- Part 2 – Docker and Tailscale — Tailscale setup
- Tailscale – Getting Started — Tailscale basics
- Caddy Documentation — official docs