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:
services:
postgres:
image: postgres:16.14-alpine3.24@sha256:57c72fd2a128e416c7fcc499958864df5301e940bca0a56f58fddf30ffc07777
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
read_only: true
cap_drop: [ALL]
cap_add: [CHOWN, DAC_OVERRIDE, FOWNER, SETGID, SETUID]
security_opt: [no-new-privileges:true]
tmpfs:
- /tmp:rw,noexec,nosuid,nodev,size=64m
- /var/run/postgresql:rw,noexec,nosuid,nodev,size=16m,uid=70,gid=70,mode=0770
networks: [data]
api:
image: ghcr.io/identiqube/provenant-api:${PROVENANT_VERSION:?set a released tag}
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
read_only: true
cap_drop: [ALL]
security_opt: [no-new-privileges:true]
tmpfs:
- /tmp:rw,noexec,nosuid,nodev,size=64m
- /app/apps/api/data:rw,noexec,nosuid,nodev,size=16m
networks: [app, data, egress]
web:
image: ghcr.io/identiqube/provenant-web:${PROVENANT_VERSION:?set a released tag}
ports: ["${WEB_PORT:-8080}:8080"]
depends_on: [api]
restart: unless-stopped
read_only: true
cap_drop: [ALL]
security_opt: [no-new-privileges:true]
tmpfs:
- /var/cache/nginx:rw,noexec,nosuid,nodev,size=64m,uid=101,gid=101,mode=0750
- /var/run:rw,noexec,nosuid,nodev,size=8m,uid=101,gid=101,mode=0750
- /tmp:rw,noexec,nosuid,nodev,size=16m
networks: [edge, app]
networks:
edge:
app:
internal: true
data:
internal: true
egress:
volumes:
provenant-pg:2. Save this as .env in the same folder and fill in the blanks:
# Released image tag to pull (see the packages under ghcr.io/identiqube). Pin it for reproducible deploys.
PROVENANT_VERSION=v0.11.0
# 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 -dPut HTTPS in front, then create the first org
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 via | When to use |
|---|---|
| Settings → License | the normal path - an admin pastes the key; it is stored deployment-wide |
PROVENANT_LICENSE_KEY | headless / bootstrap (immutable infra); a key set in Settings takes precedence |
Renewals
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.