docs: align the runbook Traefik routers with the live config

Priorities panel 200 / admin 100 / app 50, the admin rule scoped to
/api/v1/admin plus /health, /openapi.json and /docs, and the live
middleware names nestquest-panel-lan and nestquest-headers.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-09-24 12:34:52 -04:00
co-authored by Claude Opus 5.5
parent 13e3796d26
commit aa2548e486
+19 -14
View File
@@ -97,16 +97,18 @@ repository. What it must contain:
| Router | Rule | Middleware | Service | | Router | Rule | Middleware | Service |
| --- | --- | --- | --- | | --- | --- | --- | --- |
| panel (priority 300) | ``Host(`nestquest.cubecraftlabs.com`) && PathPrefix(`/api/v1/panel`)`` | `ipAllowList`, `sourceRange: ["10.60.1.80/32"]` (HA box only) | `http://10.60.1.14:8080` | | `nestquest-panel` (priority 200) | ``Host(`nestquest.cubecraftlabs.com`) && PathPrefix(`/api/v1/panel`)`` | `nestquest-panel-lan`: `ipAllowList`, `sourceRange: ["10.60.1.80/32"]` (HA box only) | `nestquest-api` → `http://10.60.1.14:8080` |
| admin (priority 200: `/api/*` other than the panel, `/health`, `/openapi.json`, `/docs`) | ``Host(`nestquest.cubecraftlabs.com`) && (PathPrefix(`/api`) \|\| Path(`/health`) \|\| Path(`/openapi.json`) \|\| PathPrefix(`/docs`))`` | none — public; the API itself enforces Authentik JWTs (section 4) | `http://10.60.1.14:8080` | | `nestquest-admin` (priority 100: `/api/v1/admin`, `/health`, `/openapi.json`, `/docs`) | ``Host(`nestquest.cubecraftlabs.com`) && (PathPrefix(`/api/v1/admin`) \|\| Path(`/health`) \|\| Path(`/openapi.json`) \|\| PathPrefix(`/docs`))`` | `nestquest-headers` — no source restriction; the API itself enforces Authentik JWTs (section 4) | `nestquest-api` → `http://10.60.1.14:8080` |
| app (priority 100: everything else — the admin PWA) | see section 10 | none at Traefik; nginx allow-lists the proxy | `http://10.60.1.14:8081` | | `nestquest-app` (priority 50: everything else — the admin PWA) | see section 10 | none at Traefik; nginx allow-lists the proxy | `nestquest-pwa` → `http://10.60.1.14:8081` |
All routers use the HTTPS entrypoint `websecure` with `tls.certResolver: myresolver` All routers use the HTTPS entrypoint `websecure` with `tls.certResolver: myresolver`
(HTTP is redirected to HTTPS by the shared Traefik). Priorities are set (HTTP is redirected to HTTPS by the shared Traefik). Priorities are set
explicitly so the order never depends on rule length: panel above admin, explicitly so the order never depends on rule length: panel (200) above
and the PWA's `nestquest-app` router below both. The admin router is admin (100), and the PWA's `nestquest-app` router (50) below both. The
scoped to the API's paths — a bare ``Host(...)`` rule at a higher admin router is scoped to `/api/v1/admin`, `/health`, `/openapi.json`
priority would swallow `/` and every PWA route. and `/docs` — a bare ``Host(...)`` rule at a higher priority would
swallow `/` and every PWA route. Any other `/api/*` path matches no
router (the app router excludes `/api`), so Traefik answers `404`.
Reference shape, to rebuild the file if it is ever lost (entrypoint names Reference shape, to rebuild the file if it is ever lost (entrypoint names
must match the shared Traefik's static config on nukapi-03): must match the shared Traefik's static config on nukapi-03):
@@ -116,30 +118,33 @@ http:
routers: routers:
nestquest-panel: nestquest-panel:
rule: "Host(`nestquest.cubecraftlabs.com`) && PathPrefix(`/api/v1/panel`)" rule: "Host(`nestquest.cubecraftlabs.com`) && PathPrefix(`/api/v1/panel`)"
priority: 300 priority: 200
entryPoints: [websecure] entryPoints: [websecure]
middlewares: [nestquest-panel-allowlist] middlewares: [nestquest-panel-lan]
service: nestquest-api service: nestquest-api
tls: tls:
certResolver: myresolver certResolver: myresolver
nestquest-admin: nestquest-admin:
rule: "Host(`nestquest.cubecraftlabs.com`) && (PathPrefix(`/api`) || Path(`/health`) || Path(`/openapi.json`) || PathPrefix(`/docs`))" rule: "Host(`nestquest.cubecraftlabs.com`) && (PathPrefix(`/api/v1/admin`) || Path(`/health`) || Path(`/openapi.json`) || PathPrefix(`/docs`))"
priority: 200 priority: 100
entryPoints: [websecure] entryPoints: [websecure]
middlewares: [nestquest-headers]
service: nestquest-api service: nestquest-api
tls: tls:
certResolver: myresolver certResolver: myresolver
nestquest-app: nestquest-app:
rule: "Host(`nestquest.cubecraftlabs.com`) && !PathPrefix(`/api`) && !Path(`/health`) && !Path(`/openapi.json`) && !PathPrefix(`/docs`)" rule: "Host(`nestquest.cubecraftlabs.com`) && !PathPrefix(`/api`) && !Path(`/health`) && !Path(`/openapi.json`) && !PathPrefix(`/docs`)"
priority: 100 priority: 50
entryPoints: [websecure] entryPoints: [websecure]
service: nestquest-pwa service: nestquest-pwa
tls: tls:
certResolver: myresolver certResolver: myresolver
middlewares: middlewares:
nestquest-panel-allowlist: nestquest-panel-lan:
ipAllowList: ipAllowList:
sourceRange: ["10.60.1.80/32"] sourceRange: ["10.60.1.80/32"]
nestquest-headers:
# headers middleware; copy its definition from the live file
services: services:
nestquest-api: nestquest-api:
loadBalancer: loadBalancer:
@@ -529,7 +534,7 @@ Build and start (the `api` and `litestream` services are unaffected):
| Router | Rule | Priority | Service | | Router | Rule | Priority | Service |
| --- | --- | --- | --- | | --- | --- | --- | --- |
| `nestquest-app` | ``Host(`nestquest.cubecraftlabs.com`) && !PathPrefix(`/api`) && !Path(`/health`) && !Path(`/openapi.json`) && !PathPrefix(`/docs`)`` | `100` — below `nestquest-admin` (200) and `nestquest-panel` (300) | `nestquest-pwa` → `http://10.60.1.14:8081` | | `nestquest-app` | ``Host(`nestquest.cubecraftlabs.com`) && !PathPrefix(`/api`) && !Path(`/health`) && !Path(`/openapi.json`) && !PathPrefix(`/docs`)`` | `50` — below `nestquest-admin` (100) and `nestquest-panel` (200) | `nestquest-pwa` → `http://10.60.1.14:8081` |
Same `websecure` entrypoint and `myresolver` certificate as the API Same `websecure` entrypoint and `myresolver` certificate as the API
routers; no Traefik middleware (nginx enforces the source allow-list). routers; no Traefik middleware (nginx enforces the source allow-list).