Dashboard Deployment
The dashboard is deployed same-origin, path-prefixed — served under a path (e.g.
/dashboard) on the same host as the API, not a separate subdomain. This means no
reverse-proxy/BFF layer is needed in production: the browser’s session cookie and
fetch calls to /auth/..., /orgs/..., etc. resolve directly against the current
origin, and the ingress routes them to the right backend Service by path.
The dashboard has no landing, pricing or marketing pages: / sends signed-in users to
/overview and everyone else to /login. If you run your own marketing site, build with the
optional NEXT_PUBLIC_MARKETING_URL (e.g. https://example.com) and the sign-in header gains a
Pricing link and the logo a link home, while the analyzer paid-plan hint gains View plans.
Leave it unset — the default — and those links don’t appear. docker-compose.prod.yaml passes it
from WEBSITE_URL in .env.
Docker Compose
Section titled “Docker Compose”The dashboard builds as its own service, published on its own host port (3001)
rather than path-prefixed — the simplest local/demo topology:
dashboard: build: context: ./OpenTremor-dashboard args: NEXT_PUBLIC_API_BASE: http://localhost:8000 ports: - "3001:3000" environment: API_BASE: http://opentremor-core:8000NEXT_PUBLIC_API_BASE (build-time, browser-facing) points at the host-published API
port; API_BASE (runtime, server-side) points at the API over the compose network.
Domain-based deployment (this repo’s docker-compose.prod.yaml)
Section titled “Domain-based deployment (this repo’s docker-compose.prod.yaml)”docker-compose.prod.yaml / haproxy/prod.cfg use a different topology from the one
above: each app gets its own subdomain (app.opentremor.dev for the dashboard,
api.opentremor.dev for the API) instead of being path-prefixed under one
origin. NEXT_PUBLIC_API_BASE is built as the API’s absolute cross-origin URL rather
than a relative path. The main domain, opentremor.dev, goes to an operator’s own
marketing site when a website container is running on the same compose network,
and to the dashboard otherwise — haproxy/prod.cfg starts and routes correctly
either way.
Because the dashboard and API no longer share an origin, three settings — not just one — must account for the split:
- Base URLs:
server.public_base_urlandserver.dashboard_base_urlare two different origins here, and both must be set viaPATCH /admin/settings.public_base_urlis the API’s own origin (https://api.opentremor.dev) — every link built from it resolves to an API route: the GitHub App manifest’s webhook URL and redirect URL, and public report links (/reports/{token}).dashboard_base_urlis the dashboard’s origin (https://app.opentremor.dev), used only for links to a dashboard page: invite join links and the manifest flow’s post-success redirect. Settingpublic_base_urlto the dashboard origin is the common mistake — the GitHub App gets created, but its callback lands on the Next.js 404 page instead of the API, so the code is never exchanged and the App’s private key and webhook secret are never stored. See GitHub App Integration. - CORS:
opentremor-core-prod.yaml’scors.allow_originsmust list the dashboard’s real origin explicitly (a credentialed request can’t use*). Set at deploy time, file/env-driven. - Session cookie domain:
server.cookie_domainmust be set to a suffix both hosts share (e.g..opentremor.dev). Without it, the cookie set byPOST /auth/sessiondefaults to host-only onapi.opentremor.dev: the browser stores it and login appears to succeed, but the dashboard’s server-side requests (on the other host) never see it, so every subsequent page load looks logged-out. Unlikeserver_dashboard_base_url, this one doesn’t need a manualPATCH /admin/settingscall — set theSERVER_COOKIE_DOMAINenv var on theopentremor-coreservice (seedocker-compose.prod.yaml) and it’s seeded into the platform settings automatically on first boot. A laterPATCH /admin/settingsalways takes precedence if you need to change it afterwards. See the setup comment at the top ofOpenTremor-core/configs/opentremor-core-prod.yamlfor details.