Install & deploy¶
How to run Deployment Dashboard for a real team. For a zero-config local trial, see the Quickstart.
Concepts in one minute¶
-
Push-first ingestion
Your CI/CD pipeline
POSTs a deployment event toPOST /api/deploymentsโ one extra step. Integrate your CI/CD. -
Pull mode is optional
The Fetcher can poll a CI/CD API (GitHub Actions today) and post through the same endpoint โ see the
-pullprofiles. -
One published port
The gateway (
:8080) is the only exposed surface. API, frontend, and PostgreSQL stay internal. -
Stateless backend
Scale API instances behind the gateway; SSE fan-out works across them via PostgreSQL
LISTEN/NOTIFY.
Deployment shapes¶
Two independent axes pick your profile:
-
Database
fullbundles PostgreSQL in a Docker volume;standaloneconnects to an external managed PostgreSQL (e.g. Azure Database for PostgreSQL) and scales the app tier behind the gateway. -
Ingestion
The base profile is push-only; the
-pullvariant adds the Fetcher for pull-mode ingestion.
1. Get the stack¶
Fetch the compose file and env template โ no clone, images pull from GHCR. Safe to paste as one block:
curl -fsSLO https://raw.githubusercontent.com/kostiantyn-matsebora/deployment-dashboard/main/compose/docker-compose.yaml
curl -fsSLO https://raw.githubusercontent.com/kostiantyn-matsebora/deployment-dashboard/main/compose/.env.example
cp .env.example .env
PowerShell
Replace the trailing \ line-continuations with backticks (`).
Pin a release
Replace main in the URLs with the tag (e.g. .../v0.12.1/compose/...) โ see Pinning a release version.
2. Configure & run¶
Pick the tab for your profile, set the listed variables in .env, then run its command.
โ ๏ธ Set every variable in the table before starting. Compose substitutes empty strings for missing values, so the containers crash-loop instead of failing fast.
-
Single host ยท bundled PostgreSQL
The simplest production shape โ the stack owns its database in a Docker volume.
Variable Set to API_KEYWrite-endpoint secret ( X-Api-Key)POSTGRES_USERBundled DB user POSTGRES_PASSWORDBundled DB password
Then point your CI/CD at http://<host>:8080/api/deployments โ see Integrate your CI/CD.
-
App tier ยท external managed PostgreSQL
Connects to an external managed PostgreSQL (e.g. Azure Database for PostgreSQL) and scales the app tier behind the gateway.
Variable Set to API_KEYWrite-endpoint secret ( X-Api-Key)POSTGRES_USERExternal DB user POSTGRES_PASSWORDExternal DB password POSTGRES_HOSTExternal DB hostname
Then point your CI/CD at http://<host>:8080/api/deployments โ see Integrate your CI/CD.
-
full + Fetcher ยท pull-mode ingestion
- How โ polls the GitHub Deployments API and posts to the dashboard's internal ingest. Outbound-only โ nothing accepts inbound traffic.
- When โ you can't add a push step to pipelines, or the network forbids inbound WAN traffic.
Variable Set to API_KEYWrite-endpoint secret ( X-Api-Key)POSTGRES_USERBundled DB user POSTGRES_PASSWORDBundled DB password GITHUB_TOKENRead-only GitHub PAT โ see token scope below GITHUB_REPOSowner/repo,owner/repoto poll
First start runs a bounded backfill, so the matrix fills after a poll cycle or two. Other fetcher options have sane defaults โ see Configuration โ Fetcher.
GitHub token scope โ read-only; the Fetcher never writes
| Repos | Classic PAT | Fine-grained PAT |
|---|---|---|
| Public | no scopes | Public repositories โ read-only |
| Private | repo scope |
Contents ยท Deployments ยท Actions: Read |
- Classic
repoover-grants โ it grants full read/write to every private repo, far beyond what the Fetcher uses. Prefer a fine-grained PAT where org policy allows. - Org repos with SAML SSO โ after creating a classic
repoPAT, click Configure SSO โ Authorize, then re-authorize after every rotation. An unauthorized token returns HTTP 403 (X-GitHub-SSOheader), not 401.
-
standalone + Fetcher ยท pull-mode ingestion
- How โ polls the GitHub Deployments API and posts to the dashboard's internal ingest. Outbound-only โ nothing accepts inbound traffic.
- When โ you can't add a push step to pipelines, or the network forbids inbound WAN traffic.
Variable Set to API_KEYWrite-endpoint secret ( X-Api-Key)POSTGRES_USERExternal DB user POSTGRES_PASSWORDExternal DB password POSTGRES_HOSTExternal DB hostname GITHUB_TOKENRead-only GitHub PAT โ see token scope below GITHUB_REPOSowner/repo,owner/repoto poll
First start runs a bounded backfill, so the matrix fills after a poll cycle or two. Other fetcher options have sane defaults โ see Configuration โ Fetcher.
GitHub token scope โ read-only; the Fetcher never writes
| Repos | Classic PAT | Fine-grained PAT |
|---|---|---|
| Public | no scopes | Public repositories โ read-only |
| Private | repo scope |
Contents ยท Deployments ยท Actions: Read |
- Classic
repoover-grants โ it grants full read/write to every private repo, far beyond what the Fetcher uses. Prefer a fine-grained PAT where org policy allows. - Org repos with SAML SSO โ after creating a classic
repoPAT, click Configure SSO โ Authorize, then re-authorize after every rotation. An unauthorized token returns HTTP 403 (X-GitHub-SSOheader), not 401.
Running from local source¶
Building from a clone is a contributor workflow โ see CONTRIBUTING.md โ Local setup.
Production checklist¶
- Set a strong
API_KEY. Writes are rejected401without it. - Set
CONTROL_API_KEY(distinct fromAPI_KEY) only if you need the reset surface; leave it unset to hidePOST /api/control/reset. - Front the stack with TLS and keep it on your internal network โ reads are unauthenticated by design (Architecture).
- Set
HISTORY_RETENTION_DAYS(minimum 90; 365 recommended). - Scale the API horizontally behind the gateway as needed โ it's stateless.
See Configuration for every environment variable.
Pinning a release version¶
By default the stack pulls latest (tracks main). For a reproducible deploy, pin in .env:
No leading v
The git tag v0.12.1 publishes images as 0.12.1. Each GitHub Release also attaches a compose bundle (deployment-dashboard-compose-vX.Y.Z.zip). Full process: RELEASING.md.
Hosting notes¶
The reference target is Azure (โค $30/month, container-based โ SAD ยง5โ6), but nothing is Azure-specific: every component is a standard OCI container. Terraform modules for Azure are planned (infrastructure/, not yet present).