Traefik
Traefik config lives on Docker labels attached to your containers, so there’s no separate config file to babysit. It also handles SSL through Let’s Encrypt automatically.
Prerequisites
You’ll want a Traefik instance already running on the same Docker network, with a proxy network defined and a Let’s Encrypt certificate resolver named letsencrypt. New to this? The Traefik docs walk through the setup.
Labels
Add these labels to the hub service in your docker-compose.yml:
services:
hub:
image: lxghtblvee/perch-hub:latest
labels:
- "traefik.enable=true"
- "traefik.http.routers.perch.rule=Host(`metrics.example.com`)"
- "traefik.http.routers.perch.entrypoints=websecure"
- "traefik.http.routers.perch.tls.certresolver=letsencrypt"
- "traefik.http.services.perch.loadbalancer.server.port=8484"
networks:
- proxy
- default
environment:
PERCH_HUB_TOKEN: ${PERCH_HUB_TOKEN}
PERCH_DB_HOST: db
PERCH_DB_USER: perch
PERCH_DB_PASS: ${PERCH_DB_PASS}
PERCH_DB_NAME: perch
PERCH_ADMIN_EMAIL: ${PERCH_ADMIN_EMAIL}
PERCH_ADMIN_PASSWORD: ${PERCH_ADMIN_PASSWORD}
PERCH_BASE_URL: https://metrics.example.com
volumes:
- hub-uploads:/app/apps/hub/uploads
depends_on:
db:
condition: service_healthy
restart: unless-stopped
networks:
proxy:
external: true
default: WebSockets just work
Traefik passes WebSocket upgrades through with no extra config, so the live dashboard and container logs work out of the box.
Custom domain status pages
Using custom domains on status pages? You’ll want a catch-all router with a lower priority sitting next to your main one.
Replace the label block above with this version, which keeps your hub domain as the primary route and sends everything else to the same service:
labels:
- "traefik.enable=true"
# Primary router: your hub domain
- "traefik.http.routers.perch.rule=Host(`metrics.example.com`)"
- "traefik.http.routers.perch.entrypoints=websecure"
- "traefik.http.routers.perch.tls.certresolver=letsencrypt"
- "traefik.http.routers.perch.priority=10"
- "traefik.http.services.perch.loadbalancer.server.port=8484"
# Catch-all router: custom status page domains
- "traefik.http.routers.perch-custom.rule=HostRegexp(`.+`)"
- "traefik.http.routers.perch-custom.entrypoints=websecure"
- "traefik.http.routers.perch-custom.tls.certresolver=letsencrypt"
- "traefik.http.routers.perch-custom.priority=1"
- "traefik.http.routers.perch-custom.service=perch" The catch-all sits at priority 1, so any domain that a higher-priority router doesn’t claim falls through to the hub. The hub then serves the right status page based on the Host header. Your main metrics.example.com router stays at priority 10, so it always wins for your dashboard.