Skip to content

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 to POST /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 -pull profiles.

  • 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


    full bundles PostgreSQL in a Docker volume; standalone connects 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 -pull variant 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_KEY Write-endpoint secret (X-Api-Key)
    POSTGRES_USER Bundled DB user
    POSTGRES_PASSWORD Bundled DB password
docker compose --profile full up -d

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_KEY Write-endpoint secret (X-Api-Key)
    POSTGRES_USER External DB user
    POSTGRES_PASSWORD External DB password
    POSTGRES_HOST External DB hostname
docker compose --profile standalone up -d

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_KEY Write-endpoint secret (X-Api-Key)
    POSTGRES_USER Bundled DB user
    POSTGRES_PASSWORD Bundled DB password
    GITHUB_TOKEN Read-only GitHub PAT โ€” see token scope below
    GITHUB_REPOS owner/repo,owner/repo to 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 repo over-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 repo PAT, click Configure SSO โ†’ Authorize, then re-authorize after every rotation. An unauthorized token returns HTTP 403 (X-GitHub-SSO header), not 401.
docker compose --profile full-pull up -d
  • 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_KEY Write-endpoint secret (X-Api-Key)
    POSTGRES_USER External DB user
    POSTGRES_PASSWORD External DB password
    POSTGRES_HOST External DB hostname
    GITHUB_TOKEN Read-only GitHub PAT โ€” see token scope below
    GITHUB_REPOS owner/repo,owner/repo to 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 repo over-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 repo PAT, click Configure SSO โ†’ Authorize, then re-authorize after every rotation. An unauthorized token returns HTTP 403 (X-GitHub-SSO header), not 401.
docker compose --profile standalone-pull up -d

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 rejected 401 without it.
  • Set CONTROL_API_KEY (distinct from API_KEY) only if you need the reset surface; leave it unset to hide POST /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:

DASHBOARD_VERSION=0.12.1

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).