diff --git a/backend/internal/adminconsole/templates/layout.gohtml b/backend/internal/adminconsole/templates/layout.gohtml index 8634190..8dd6676 100644 --- a/backend/internal/adminconsole/templates/layout.gohtml +++ b/backend/internal/adminconsole/templates/layout.gohtml @@ -17,6 +17,8 @@ Games Operators Mail + Grafana + Mailpit {{.Username}} diff --git a/tools/dev-deploy/Caddyfile.dev b/tools/dev-deploy/Caddyfile.dev index bd485bf..462b9fe 100644 --- a/tools/dev-deploy/Caddyfile.dev +++ b/tools/dev-deploy/Caddyfile.dev @@ -29,28 +29,34 @@ reverse_proxy galaxy-api:8080 } - # Operator console. Shares the gateway public listener with `/api`; the - # gateway applies the admin anti-abuse class and reverse-proxies to the - # backend `/_gm` surface, which enforces Basic Auth and renders the pages. + # Operator console + observability behind one Basic Auth gate. The gate + # credential equals the admin-console account (dev: gm / gm-dev-password), + # so Caddy forwards the same Authorization header to the backend `/_gm` + # surface (its own Basic Auth) and to Grafana/Mailpit — one prompt covers + # all three. The gateway applies the admin anti-abuse class to the console. @gm path /_gm /_gm/* handle @gm { - reverse_proxy galaxy-api:8080 - } - - # Grafana (observability UI) under /grafana/ — Caddy sub-path mode - # (Grafana set with GF_SERVER_SERVE_FROM_SUB_PATH); its own login. - handle /grafana/* { - reverse_proxy galaxy-grafana:3000 - } - - # Mailpit captured-mail UI under /mailpit/. Shows every message the - # backend sent (relayed or not); basic-auth (dev: gm / gm-dev-password) - # guards the OTP codes it exposes. Mailpit runs with MP_WEBROOT=/mailpit. - handle /mailpit/* { basic_auth { gm "$2a$14$xVh1TLaZxh8fazlKrI9Mx.NQMQlMarYWtr3FRELmZIXuac/DeeTRO" } - reverse_proxy galaxy-mailpit:8025 + + # Grafana under /_gm/grafana/ (sub-path mode; anonymous Admin, so the + # /_gm gate is the only barrier — GF_AUTH_BASIC_ENABLED=false makes it + # ignore the forwarded Authorization header). + handle /_gm/grafana/* { + reverse_proxy galaxy-grafana:3000 + } + + # Mailpit captured-mail UI under /_gm/mailpit/ (MP_WEBROOT). Shows + # every message the backend sent, relayed or not. + handle /_gm/mailpit/* { + reverse_proxy galaxy-mailpit:8025 + } + + # The operator console itself (gateway -> backend /_gm surface). + handle { + reverse_proxy galaxy-api:8080 + } } # Bare `/game` (no trailing slash) -> `/game/` so the SPA root diff --git a/tools/dev-deploy/docker-compose.yml b/tools/dev-deploy/docker-compose.yml index d9cf40e..cdb647d 100644 --- a/tools/dev-deploy/docker-compose.yml +++ b/tools/dev-deploy/docker-compose.yml @@ -74,9 +74,10 @@ services: command: - "--smtp-relay-config=/etc/mailpit/relay.conf" - "--smtp-relay-matching=${GALAXY_DEV_MAIL_RELAY_MATCH:-nobody@invalid.example}" - # Serve the capture UI under /mailpit so the host Caddy can expose it - # at https://galaxy.lan/mailpit/ (behind basic-auth); SMTP is unaffected. - - "--webroot=/mailpit" + # Serve the capture UI under /_gm/mailpit so the host Caddy can expose + # it at https://galaxy.lan/_gm/mailpit/ behind the shared /_gm gate; + # SMTP is unaffected. + - "--webroot=/_gm/mailpit" labels: galaxy.stack: dev-deploy networks: @@ -84,7 +85,7 @@ services: volumes: - galaxy-dev-mailpit-config:/etc/mailpit:ro healthcheck: - test: ["CMD", "wget", "-q", "-O-", "http://localhost:8025/mailpit/livez"] + test: ["CMD", "wget", "-q", "-O-", "http://localhost:8025/_gm/mailpit/livez"] interval: 3s timeout: 3s retries: 30 @@ -412,8 +413,15 @@ services: - galaxy-tempo environment: GF_SECURITY_ADMIN_PASSWORD: ${GALAXY_DEV_GRAFANA_ADMIN_PASSWORD:-admin} - GF_SERVER_ROOT_URL: https://galaxy.lan/grafana/ + GF_SERVER_ROOT_URL: https://galaxy.lan/_gm/grafana/ GF_SERVER_SERVE_FROM_SUB_PATH: "true" + # No own login: the /_gm Basic Auth gate is the only barrier, so + # serve everyone as anonymous Admin and ignore the forwarded + # Authorization header (basic auth off, login form off). + GF_AUTH_ANONYMOUS_ENABLED: "true" + GF_AUTH_ANONYMOUS_ORG_ROLE: Admin + GF_AUTH_DISABLE_LOGIN_FORM: "true" + GF_AUTH_BASIC_ENABLED: "false" GF_USERS_ALLOW_SIGN_UP: "false" GF_ANALYTICS_REPORTING_ENABLED: "false" GF_ANALYTICS_CHECK_FOR_UPDATES: "false"