Caddy

Honestly the easiest option of the bunch. Caddy handles HTTPS and certificate renewal on its own with zero extra config, and WebSocket proxying just works without any special headers.

Caddyfile

Caddyfile
metrics.example.com {
    reverse_proxy localhost:8484
}

That’s the whole thing. Caddy grabs a certificate from Let’s Encrypt on the first request and renews it automatically from then on.

Set PERCH_BASE_URL

Add PERCH_BASE_URL to your .env so OAuth callbacks point to the right place:

.env
PERCH_BASE_URL=https://metrics.example.com

Then restart the hub:

bash
docker compose restart hub

Where Caddy is running

If Caddy runs directly on the host, point it at localhost:

metrics.example.com {
    reverse_proxy localhost:8484
}

If Caddy runs in a container, use the hub’s service name instead of localhost, and make sure Caddy and the hub share a Docker network:

metrics.example.com {
    reverse_proxy hub:8484
}

Custom domain status pages

Using custom domains on status pages? Add a block for each custom domain pointing at the same backend, and Caddy sorts out the certificate for each one automatically:

Caddyfile
metrics.example.com {
    reverse_proxy localhost:8484
}

status.yourservice.com {
    reverse_proxy localhost:8484
}