Skip to content

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.


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:8000

NEXT_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_url and server.dashboard_base_url are two different origins here, and both must be set via PATCH /admin/settings. public_base_url is 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_url is 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. Setting public_base_url to 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’s cors.allow_origins must 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_domain must be set to a suffix both hosts share (e.g. .opentremor.dev). Without it, the cookie set by POST /auth/session defaults to host-only on api.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. Unlike server_dashboard_base_url, this one doesn’t need a manual PATCH /admin/settings call — set the SERVER_COOKIE_DOMAIN env var on the opentremor-core service (see docker-compose.prod.yaml) and it’s seeded into the platform settings automatically on first boot. A later PATCH /admin/settings always takes precedence if you need to change it afterwards. See the setup comment at the top of OpenTremor-core/configs/opentremor-core-prod.yaml for details.