Proxy & SSO auth setup
End-to-end setup guides for putting chmonitor behind a proxy that handles login. Three patterns are covered:
- Cloudflare Access + Tunnel — Zero Trust, signed JWT, no shared secret needed.
- nginx + oauth2-proxy — self-hosted OIDC login in front of nginx.
- Traefik ForwardAuth + OIDC — Traefik middleware forwarding an OIDC session.
All three use chmonitor’s trusted or proxy auth provider. See Authentication for the full comparison.
Quick comparison
Section titled “Quick comparison”| Setup | chmonitor provider | Trust mechanism |
|---|---|---|
| Cloudflare Access + Tunnel | proxy | Signed Cf-Access-Jwt-Assertion JWT — no shared secret needed |
| nginx + oauth2-proxy | trusted | Shared secret header (X-Chm-Proxy-Secret) |
| Traefik ForwardAuth + OIDC | trusted | Shared secret header or network isolation |
Cloudflare Access + Tunnel
Section titled “Cloudflare Access + Tunnel”Cloudflare Access sits in front of chmonitor and issues a signed JWT on every authenticated request. chmonitor verifies the JWT cryptographically against Cloudflare’s JWKS — no secret to share.
1. Create an Access application
Section titled “1. Create an Access application”In the Cloudflare Zero Trust dashboard:
- Access → Applications → Add application → Self-hosted.
- Set the Application domain to
your-chmonitor.example.com. - Under Session duration, pick a reasonable window (e.g. 24 hours).
- Add an Access policy (e.g. allow users in your team’s email domain).
- Note the Application Audience (AUD) tag from the application overview page — it looks like a 64-character hex string.
2. Create a Cloudflare Tunnel
Section titled “2. Create a Cloudflare Tunnel”cloudflared tunnel create chmonitorcloudflared tunnel route dns chmonitor your-chmonitor.example.comConfigure ~/.cloudflared/config.yml:
tunnel: chmonitorcredentials-file: /root/.cloudflared/<tunnel-id>.json
ingress: - hostname: your-chmonitor.example.com service: http://localhost:8080 # chmonitor container port - service: http_status:404Run the tunnel:
cloudflared tunnel run chmonitor3. Configure chmonitor
Section titled “3. Configure chmonitor”CHM_AUTH_PROVIDER=trusted # server-sideVITE_AUTH_PROVIDER=trusted # build-time client mirror
## Cloudflare Access verificationCHM_CF_ACCESS_TEAM_DOMAIN=yourteam.cloudflareaccess.comCHM_CF_ACCESS_AUD=<64-char-aud-tag>Wait — actually chmonitor’s Cloudflare Access support uses the proxy provider, not trusted. Use:
CHM_AUTH_PROVIDER=proxyVITE_AUTH_PROVIDER=proxy
CHM_CF_ACCESS_TEAM_DOMAIN=yourteam.cloudflareaccess.comCHM_CF_ACCESS_AUD=<64-char-aud-tag>The proxy provider verifies the Cf-Access-Jwt-Assertion header against the team’s JWKS automatically. No shared secret is needed — the JWT signature is the proof.
4. Verify
Section titled “4. Verify”## Should return authenticated identity from Accesscurl -H "Cf-Access-Jwt-Assertion: <token>" \ https://your-chmonitor.example.com/api/v1/auth/me | jq .Unauthenticated requests hit the Access login page (Cloudflare redirects them) before reaching chmonitor.
nginx + oauth2-proxy
Section titled “nginx + oauth2-proxy”oauth2-proxy sits alongside nginx and handles the OIDC login flow. After login it sets forwarded-identity headers that chmonitor’s trusted provider reads.
Architecture
Section titled “Architecture”Browser → nginx → oauth2-proxy (login) → nginx → chmonitornginx uses auth_request to check with oauth2-proxy on every request. If the session is valid, oauth2-proxy sets identity headers; nginx forwards them to chmonitor along with a shared secret.
1. Run oauth2-proxy
Section titled “1. Run oauth2-proxy”Example with Google OIDC (replace with your provider):
docker run -d \ -p 4180:4180 \ quay.io/oauth2-proxy/oauth2-proxy \ --provider=google \ --client-id=YOUR_CLIENT_ID \ --client-secret=YOUR_CLIENT_SECRET \ --cookie-secret=$(openssl rand -base64 32) \ --email-domain=yourcompany.com \ --upstream=http://chmonitor:8080 \ --http-address=0.0.0.0:4180 \ --set-xauthrequest \ # emits X-Auth-Request-User, X-Auth-Request-Email --pass-access-token=false--set-xauthrequest makes oauth2-proxy emit X-Auth-Request-User and X-Auth-Request-Email on authenticated requests. Those map to chmonitor’s default identity headers.
2. Configure nginx
Section titled “2. Configure nginx”server { listen 443 ssl; server_name chmonitor.yourcompany.com;
location /oauth2/ { proxy_pass http://oauth2-proxy:4180; proxy_set_header Host $host; }
location = /oauth2/auth { proxy_pass http://oauth2-proxy:4180; proxy_pass_request_body off; proxy_set_header Content-Length ""; proxy_set_header X-Original-URI $request_uri; }
location / { auth_request /oauth2/auth; error_page 401 = /oauth2/sign_in;
# Forward identity from oauth2-proxy auth_request_set $user $upstream_http_x_auth_request_user; auth_request_set $email $upstream_http_x_auth_request_email;
proxy_set_header X-Forwarded-User $user; proxy_set_header X-Forwarded-Email $email;
# Shared secret so chmonitor trusts these headers proxy_set_header X-Chm-Proxy-Secret "your-shared-secret-here";
proxy_pass http://chmonitor:8080; }}3. Configure chmonitor
Section titled “3. Configure chmonitor”CHM_AUTH_PROVIDER=trustedVITE_AUTH_PROVIDER=trusted
## Shared secret — must match the value in nginxCHM_TRUSTED_AUTH_SECRET=your-shared-secret-here
## Optional: override header names if oauth2-proxy emits different ones## CHM_TRUSTED_USER_HEADER=X-Auth-Request-User # default: X-Forwarded-User## CHM_TRUSTED_EMAIL_HEADER=X-Auth-Request-Email # default: X-Forwarded-Emailoauth2-proxy’s --set-xauthrequest emits X-Auth-Request-User and X-Auth-Request-Email. The nginx auth_request_set block copies them to X-Forwarded-User / X-Forwarded-Email, which are chmonitor’s defaults.
4. Verify
Section titled “4. Verify”## Hit chmonitor directly (bypasses nginx) — should 401 (no shared secret)curl http://chmonitor:8080/api/v1/auth/me
## Through nginx with a valid session cookie — should return authenticated principalcurl -b "session=..." https://chmonitor.yourcompany.com/api/v1/auth/me | jq .Traefik ForwardAuth + OIDC
Section titled “Traefik ForwardAuth + OIDC”Traefik’s forwardAuth middleware sends every request to an external auth server (e.g. Authelia, Authentik, or a custom endpoint) before proxying it. On success the auth server adds identity headers.
Architecture
Section titled “Architecture”Browser → Traefik → Authelia (forwardAuth) → Traefik → chmonitor1. Configure Authelia (or Authentik)
Section titled “1. Configure Authelia (or Authentik)”This example uses Authelia. Authelia adds Remote-User, Remote-Name, Remote-Groups, and Remote-Email headers on authenticated requests.
authelia/configuration.yml (relevant section):
access_control: default_policy: deny rules: - domain: chmonitor.yourcompany.com policy: one_factor2. Configure Traefik
Section titled “2. Configure Traefik”docker-compose.yml (extract):
services: traefik: image: traefik:v3 command: - --providers.docker=true - --entrypoints.websecure.address=:443
chmonitor: image: ghcr.io/duyet/chmonitor:latest labels: traefik.enable: "true" traefik.http.routers.chmonitor.rule: "Host(`chmonitor.yourcompany.com`)" traefik.http.routers.chmonitor.entrypoints: "websecure" traefik.http.routers.chmonitor.middlewares: "authelia@docker"
authelia: image: authelia/authelia:latest labels: traefik.enable: "true" traefik.http.middlewares.authelia.forwardauth.address: "http://authelia:9091/api/authz/forward-auth" traefik.http.middlewares.authelia.forwardauth.trustForwardHeader: "true" traefik.http.middlewares.authelia.forwardauth.authResponseHeaders: >- Remote-User,Remote-Groups,Remote-Name,Remote-EmailAuthelia sets Remote-User, Remote-Name, Remote-Groups, Remote-Email. Tell chmonitor to read those:
3. Configure chmonitor
Section titled “3. Configure chmonitor”CHM_AUTH_PROVIDER=trustedVITE_AUTH_PROVIDER=trusted
## Authelia headers differ from chmonitor's defaults — override themCHM_TRUSTED_USER_HEADER=Remote-UserCHM_TRUSTED_EMAIL_HEADER=Remote-EmailCHM_TRUSTED_NAME_HEADER=Remote-NameCHM_TRUSTED_GROUPS_HEADER=Remote-Groups
## Trust gate: either set a shared secret or enable network-isolation mode.## Network isolation (chmonitor only reachable via Traefik inside Docker):CHM_TRUSTED_ALLOW_INSECURE=true
## Or: set a shared secret (more secure; configure Traefik to add it)## CHM_TRUSTED_AUTH_SECRET=your-secret## CHM_TRUSTED_SHARED_SECRET_HEADER=X-Chm-Proxy-SecretIf you use CHM_TRUSTED_ALLOW_INSECURE=true, make sure chmonitor’s port (8080) is not exposed on the host — only reachable via Traefik inside the Docker network.
4. Optional: group-based access control
Section titled “4. Optional: group-based access control”Restrict chmonitor to specific Authelia groups:
## Only users in the "ops" or "admin" group can access chmonitorCHM_TRUSTED_ALLOWED_GROUPS=ops,adminAuthelia forwards groups as a comma-separated list in Remote-Groups; chmonitor checks intersection (case-insensitive).
5. Verify
Section titled “5. Verify”## Auth/me should show the identity forwarded by Autheliacurl https://chmonitor.yourcompany.com/api/v1/auth/me | jq .Trusted provider — full reference
Section titled “Trusted provider — full reference”All env vars for CHM_AUTH_PROVIDER=trusted:
Trust gate
Section titled “Trust gate”| Variable | Default | Description |
|---|---|---|
CHM_TRUSTED_AUTH_SECRET | — | Shared secret the proxy sends in the secret header. Constant-time compared. |
CHM_TRUSTED_ALLOW_INSECURE | false | Skip secret check when the worker is network-isolated behind the proxy. |
CHM_TRUSTED_SHARED_SECRET_HEADER | X-Chm-Proxy-Secret | Header name the proxy sends the secret in. |
Identity headers
Section titled “Identity headers”| Variable | Default header | Maps to |
|---|---|---|
CHM_TRUSTED_USER_HEADER | X-Forwarded-User | User subject / id |
CHM_TRUSTED_EMAIL_HEADER | X-Forwarded-Email | Email address |
CHM_TRUSTED_NAME_HEADER | X-Forwarded-Preferred-Username | Display name |
CHM_TRUSTED_AVATAR_HEADER | X-Forwarded-Avatar | Avatar URL |
CHM_TRUSTED_GROUPS_HEADER | X-Forwarded-Groups | Comma-separated group list |
CHM_TRUSTED_ROLE_HEADER | X-Forwarded-Role | Single role (merged into groups) |
CHM_TRUSTED_CUSTOM_HEADERS | — | Extra claims: field:Header-Name pairs |
Access control
Section titled “Access control”| Variable | Default | Description |
|---|---|---|
CHM_TRUSTED_ALLOWED_GROUPS | — | Comma-separated list of groups. If set, user must be in at least one. |