Behind a reverse proxy
The repository has a ready compose file for each of these proxies under examples/: compose.caddy.yml, compose.traefik.yml and compose.pangolin.yml. Each runs the same image; only the network and the labels differ. For anything else (nginx, HAProxy) start from the standalone file and add your own front.
Three things every proxy setup needs
Section titled “Three things every proxy setup needs”- Trust exactly one peer. Labelyard reads
X-Forwarded-Foronly from the address inFORWARDED_ALLOW_IPS. Give your proxy a fixed address on the shared network and setPROXY_IPin.envto it; the examples pass it on. Without it every client looks like the proxy, and the per-address sign-in limit becomes one bucket for everybody. Do not use*or a subnet. - Set the public address.
LABELYARD_PUBLIC_URLis thehttpsaddress people open, for examplehttps://labelyard.example.com, andLABELYARD_HOSTthe host name the examples route. - Do not buffer the event stream. Live updates arrive as Server-Sent Events on
/api/v1/events. The Caddy example setsflush_interval -1, the Traefik exampleresponseforwarding.flushinterval=100ms. Settings for other proxies and how to check the stream: event stream and reverse proxies.
Pin the proxy’s address in its own stack (ipv4_address). An unpinned address can go to another container after a restart, and that container would then be trusted to set X-Forwarded-For. The sign-in limit counts IPv6 clients per /64 network (a unique-local or link-local address counts on its own), and an IPv4-mapped IPv6 address counts as its IPv4 address. If a trusted proxy forwards a value that is not an IP address, or the request arrives over a unix socket, all such sign-ins share one bucket.
The example uses the labels of caddy-docker-proxy:
labels: caddy: ${LABELYARD_HOST} caddy.reverse_proxy: "{{upstreams 8000}}" caddy.reverse_proxy.flush_interval: "-1"Traefik
Section titled “Traefik”Two routers point at one service. The second one serves the webhook paths with a higher priority, so you can give it its own middlewares (or none, if the main router has an SSO middleware):
labels: - "traefik.enable=true" - "traefik.http.routers.labelyard.rule=Host(`${LABELYARD_HOST}`)" - "traefik.http.routers.labelyard.entrypoints=websecure" - "traefik.http.routers.labelyard.tls.certresolver=letsencrypt" - "traefik.http.routers.labelyard-webhooks.rule=Host(`${LABELYARD_HOST}`) && PathPrefix(`/api/v1/webhook/`)" - "traefik.http.routers.labelyard-webhooks.priority=20" - "traefik.http.services.labelyard.loadbalancer.server.port=8000" - "traefik.http.services.labelyard.loadbalancer.responseforwarding.flushinterval=100ms"Pangolin
Section titled “Pangolin”The Pangolin example declares two public resources with blueprint labels: the hub behind Pangolin’s SSO, and the webhook path with authentication bypassed, because Spoolman and Grocy cannot sign in. The SSO resource injects the trust token as a request header:
labels: - "pangolin.public-resources.labelyard.auth.sso-enabled=true" - "pangolin.public-resources.labelyard.request-headers[0].name=X-Pangolin-Token" - "pangolin.public-resources.labelyard.request-headers[0].value=${LABELYARD_SSO_TRUST_TOKEN}" - "pangolin.public-resources.labelyard-webhooks.targets[0].path=/api/v1/webhook/" - "pangolin.public-resources.labelyard-webhooks.auth.bypass=true"Set LABELYARD_SSO_TRUST_TOKEN to the same value (openssl rand -hex 32). How sign-in through the proxy works is described under users and SSO.
Already running behind a proxy? Keep your existing router or resource name. A new name creates a new resource with a new certificate and new access rules.