Self-hosting & licensing

Run Provenant on your own infrastructure — a dedicated deployment isolated to your organization. Anyone can self-host, on any tier. Without a license key the deployment runs the Free tier; a signed license key activates a paid plan for its validity period — get one at [email protected].

Deploy with Docker Compose

You need Docker with the Compose plugin. The images are public on ghcr.io/identiqube — no registry login required. Save the two files below in an empty folder, fill in strong secrets, and start the stack.

1. Save this as docker-compose.yml:

docker-compose.yml
services:
  postgres:
    image: postgres:16-alpine
    environment:
      POSTGRES_USER: provenant
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?set it in .env}
      POSTGRES_DB: provenant
    volumes: [provenant-pg:/var/lib/postgresql/data]
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U provenant -d provenant"]
      interval: 10s
      timeout: 5s
      retries: 10
    restart: unless-stopped

  api:
    image: ghcr.io/identiqube/provenant-api:${PROVENANT_VERSION:-latest}
    environment:
      NODE_ENV: production
      SECRET_ISOLATION: dedicated
      STORE_DRIVER: postgres
      DATABASE_URL: postgres://provenant:${POSTGRES_PASSWORD:?}@postgres:5432/provenant
      CORS_ORIGINS: ${CORS_ORIGINS:?your dashboard URL}
      TRUST_PROXY: ${TRUST_PROXY:-1}
      JWT_SECRET: ${JWT_SECRET:?}
      ACTION_SIGNING_SECRET: ${ACTION_SIGNING_SECRET:?}
      PROVENANT_LICENSE_KEY: ${PROVENANT_LICENSE_KEY:-}
      # Cooperative-SDK deployments don't broker credentials — acknowledge the mock broker.
      # (Set a real CREDENTIAL_BROKER instead if you use the enforcing gateway with minted creds.)
      PROVENANT_ALLOW_MOCK_EXECUTION: "true"
      RUN_BACKGROUND_JOBS: "true"
      DB_MIGRATE_ON_START: "true"
    expose: ["4000"]          # internal only — reached via the web proxy, never published to the host
    depends_on:
      postgres:
        condition: service_healthy
    restart: unless-stopped

  web:
    image: ghcr.io/identiqube/provenant-web:${PROVENANT_VERSION:-latest}
    ports: ["${WEB_PORT:-8080}:80"]
    depends_on: [api]
    restart: unless-stopped

volumes:
  provenant-pg:

2. Save this as .env in the same folder and fill in the blanks:

.env
# Released image tag to pull (see the packages under ghcr.io/identiqube). Pin it for reproducible deploys.
PROVENANT_VERSION=latest

# Strong secrets — generate each with:  openssl rand -hex 48
POSTGRES_PASSWORD=
JWT_SECRET=
ACTION_SIGNING_SECRET=

# Your dashboard URL(s), comma-separated. No '*'. Use HTTPS in production.
CORS_ORIGINS=https://provenant.example.com
# Proxy hops in front of the API (usually 1 behind a single TLS proxy).
TRUST_PROXY=1
# Host port the dashboard listens on (it also proxies the API at /v1).
WEB_PORT=8080

# Optional: activate a paid tier headlessly, or paste the key later in Settings -> License.
PROVENANT_LICENSE_KEY=

3. Pull the public images and start:

docker compose pull
docker compose up -d

Put HTTPS in front, then create the first org

Production sign-in uses Secure cookies, so the dashboard must be reached over HTTPS — terminate TLS at a reverse proxy (Caddy, nginx, Traefik, or a cloud load balancer) in front of WEB_PORT, and set CORS_ORIGINS to that URL. The API container (port 4000) is deliberately not published to the host; the dashboard's nginx proxies /v1 and /health to it over the internal Docker network. Open your dashboard URL — the first account you create becomes the org admin. Back up the provenant-pg volume; that is your entire datastore and audit ledger.

Dedicated deployment

A self-hosted instance runs in dedicated mode (SECRET_ISOLATION=dedicated). In this mode the deployment is yours alone, so the platform's own environment and deployment-level secret managers are available to your connectors — including env:NAME secret references, which are not available on the hosted platform (see Connectors & secrets). Configuration is covered in Environment variables.

License key

The license key is the self-hosted counterpart of a subscription: a signed key that carries your plan (any tier), its limits, and a validity period (for example one month or one year). The instance verifies it locally with a built-in public key — there is no phone-home and no network call. The key is tamper-evident: any edit invalidates its signature.

Without a valid key, nothing is blocked — the deployment simply runs at Free plan limits. An admin activates a paid plan by pasting the key in Settings → License. On expiry there is a grace period (paid limits stay in force, with a warning) before limits revert to Free — the same shape as a hosted subscription lapsing.

Provide the key viaWhen to use
Settings → Licensethe normal path — an admin pastes the key; it is stored deployment-wide
PROVENANT_LICENSE_KEYheadless / bootstrap (immutable infra); a key set in Settings takes precedence

Renewals

A renewed key replaces the old one in Settings → License with no downtime. Enter it before the grace window closes and your paid limits are never interrupted.

License terms

Self-hosted use of the software is governed by the Self-Hosting License — the LICENSE file shipped inside the container images. It grants the right to run the software on your own infrastructure (Free limits without a key; the licensed plan with one) and keeps everything else reserved. The hosted service is governed by the Terms of Service instead.