5.4 KiB
CannaManage — now LIVE & public, auth blocker fixed (2026-06-22)
TL;DR
https://cannamanage.plate-software.de is live in production over HTTPS. The
9-day systemic missing-token auth blocker (flagged 2026-06-13 / 2026-06-18) is
fixed and verified end-to-end through the public chain. Push→deploy→tunnel
now mirrors inspectflow. End of alpha.
What shipped (2 commits on main)
- a686957
feat(deploy): public hosting + fix systemic auth-token bug - 83b46c8
harden(deploy): db internal-only + robust container-loopback frontend verify
1. The auth fix (the important one)
Root cause (unchanged from prior notes): the frontend used a static
next.config.mjs rewrites() to proxy /api/backend/* → backend, which cannot
inject the user's bearer token, so every authenticated server call hit the API
unauthenticated and the UI silently fell back to mock data.
Fix — replaced the static rewrite with a server-side catch-all Route Handler:
cannamanage-frontend/src/app/api/backend/[...path]/route.ts(new) — reads the NextAuth session viaauth(), injectsAuthorization: Bearer <accessToken>, streams request/response bodies (duplex: "half") for uploads/downloads, strips hop-by-hop headers, GET/POST/PUT/PATCH/DELETE.src/lib/auth.ts—session()callback now exposessession.accessToken.src/types/next-auth.d.ts— addedaccessToken?: stringtoSession.next.config.mjs— removed the staticrewrites().
Why auth() not getToken(): getToken() autodetects the __Secure-
cookie prefix, which breaks across the public-HTTPS → internal-HTTP proxy
boundary. auth() resolves the session reliably behind the frp/Apache chain.
Accepted tradeoff: accessToken is now readable at /api/auth/session
(client-visible). Fine for alpha; revisit if we want it httpOnly-only.
2. Public hosting wiring (mirrors inspectflow)
Chain: browser →HTTPS→ IONOS Apache (82.165.206.45, LE TLS) →ProxyPass→
VPS frps (85.214.154.199:30010) →frp tunnel→ TrueNAS frpc → frontend:3000.
The frontend proxies /api/backend/* to backend:8080 server-side, so only
the frontend port is tunnelled (no Caddy needed, unlike inspectflow).
docker-compose.truenas.yml— publicNEXTAUTH_URL/AUTH_URL,AUTH_TRUST_HOST, rotated prod secrets,BACKEND_URL=http://backend:8080, db internal-only (ports: !override []), backend remapped 8081→8080 (host 8080 taken by searxng)..gitea/workflows/deploy.yml— injectsAUTH_SECRET/JWT_SECRET/DB_PASSWORDfrom Gitea repo secrets; new "reconcile DB role password" step (ALTER USER — POSTGRES_PASSWORD only applies on first volume init, the persistentcannamanage_pgdatavolume kept the old password); hardened frontend verify (probes container loopback via bundlednode, not host wget — fixes a transient false-failure when polling mid-recreate).- frpc.toml on TrueNAS: added
cannamanageproxy localPort 3000 → remotePort 30010. - IONOS: Let's Encrypt cert via acme.sh +
:443vhost ProxyPass → VPS:30010.
Port map (NO collision with inspectflow — explicitly verified)
| layer | inspectflow | cannamanage |
|---|---|---|
| VPS frps remotePort | 30009 | 30010 |
| TrueNAS host publish | 8090→80 (caddy) | 3000 (frontend), 8081→8080 (backend) |
| db / internal | internal-only | internal-only (5432/tcp, no host bind) |
Verified live (end-to-end, public HTTPS)
GET /→ 307 →/login(correct NextAuth redirect), valid LE TLS.- Login
admin@test.de→ 302; session = role ADMIN, accessToken present. GET /api/backend/members→ HTTP 200 through the full public chain. ✅- db: no host listener on :5432 after hardened deploy. ✅
- Deploy run #59 (deploy.yml) = success with hardened verify. ✅
Flags / follow-ups for Work Lumen
- PII / GDPR: this is a German cannabis-club app (KCanG) now public. Members table is empty today, but before real data lands we need: backups (deploy/backup.sh exists — wire a cron), retention enforcement, and a documented restore drill.
- Secret rotation: prod secrets live only in Gitea repo secrets + the running
containers. They are NOT in git (verified). Document them in a vault; rotating
JWT_SECRETinvalidates all tokens,AUTH_SECRETall sessions,DB_PASSWORDneeds the ALTER USER reconcile (already automated in deploy.yml). - accessToken client-exposure tradeoff (see above) — revisit post-alpha.
- ci.yml is red (separate workflow): backend
mvn test+ frontendpnpm lintfail in CI but pass locally; local type-check shows only TEST-file errors (missing vitest globals / stale assertions). deploy.yml does NOT depend on ci.yml (tests are a local-only gate per its header — nested-DinD can't volume-mount). Worth fixing ci.yml separately so the badge is honest. - HTTP→apex redirect cosmetic quirk:
http://cannamanage…301s to apexplate-software.de(Apache*:80vsplate-software.de:80vhost ordering) — same as inspectflow, harmless since the site is HTTPS, but tidy it if it bugs you. - acme.sh default CA was ZeroSSL and stalled (retryafter=86400). Switched the box
default to Let's Encrypt (
--set-default-ca --server letsencrypt) — matches inspectflow. Auto-renew cron inherits this now.
Test creds (alpha)
admin@test.de / Test1234! (hash was reset during smoke testing).