Last updated September 16, 2026
Self-Hosted Deployment
A self-hosted deployment runs the same product as cloud in a Docker Compose stack on servers you control. Your users still sign in through the portal, and the stack checks in with the portal for licensing. Boards, sources, chat, and the database stay inside your network.
Self-hosting is available on the Enterprise plan. Once your organization is on Enterprise, our team provisions and approves an on-premises deployment for it. That approval is what unlocks the Self-hosted page in the portal and lets your servers pull images. Use the button above to start the conversation.
How it works
The container images live in a private registry. Your host trades its deployment credentials for 12 hours of pull access, pulls the release the portal names, and runs it. Once running, the stack sends the portal an hourly heartbeat and keeps working for up to 24 hours if the portal is unreachable.
Pull access is tied to your subscription. If the subscription lapses, running containers keep running, but the next sign-in is refused and you cannot pull a new release until billing is resolved.
What you'll need
Images are built for linux/amd64. Docker Desktop on Apple Silicon runs them under emulation, which is fine for evaluation. Linux ARM64 servers are not supported.
PostgreSQL is bring-your-own. The compose file does not run a database for you. Before starting the stack, prepare a reachable managed or self-run instance and its credentials.
Outbound access
The host needs HTTPS (port 443) to all three of these. Enterprise firewalls routinely allow the first two and forget the third, and the symptom is a pull that stalls at 0%.
The pre-flight script in the install steps checks all three before you download anything.
Get your deployment credentials
- Our team provisions an on-premises deployment for your organization and approves it. Until then, the portal's Self-hosted page shows a contact card instead of the installer.
- Sign in to portal.provenmap.com as an organization admin and open Self-hosted.
- Select Create Secret. Copy the App ID and the secret into your secrets manager.
The secret is shown once. Recreate Secret on the same page invalidates the old one for both the heartbeat and registry sign-in. After recreating it, update .env and run the sign-in script again.
Install
The steps below take about ten minutes on a host that meets the requirements.
1. Check the host. The script verifies Docker, memory, disk, port 80, jq, and reachability of all three outbound hosts.
2. Download the kit. This creates ~/provenmap with the compose file, nginx.conf, .env.template, and the sign-in script.
3. Configure. Copy the template if the installer didn't, then set the three required values.
4. Sign in to the image registry. The script trades your credentials for 12 hours of pull access and, on first run, pins PMAP_VERSION to the current release.
5. Start the stack.
The first start downloads roughly 1 GB of images and takes two to three minutes.
Pull access lasts 12 hours. Run the sign-in script again before any docker compose pull. Starting or restarting containers you already have does not need it.
Verify the installation
All three containers (provenmap-proxy, provenmap-web, and provenmap-server) report Up (healthy). The health check returns {"status":"ok"}, and the status endpoint reports "license": { "status": "active" } after the server checks in with the portal.
Open http://localhost (or your configured port), select Sign In, and sign in with your portal account. Every user needs a portal account and membership in your organization.
Configuration
Settings live in .env next to the compose file. Restart the affected container after a change: docker compose -f docker-compose.production.yml up -d --force-recreate server.
Required
There is no latest tag. Releases are immutable, your deployment runs exactly the release named here, and nothing changes it but you.
Database
Migrations run automatically when the server starts. They are forward-only and hold an advisory lock, so several restarts in a row are safe.
Connection pool and platform behavior
Optional
Chat and in-app insight generation use a model provider, connected once from Settings → Connectors. Plugin commands such as /analyze, /sync, and /insights do not require one. Icon storage can be moved from the local filesystem to S3 — see Organization Settings. Plugins and MCP clients point at your instance with PMAP_BASE_URL and PMAP_MCP_URL — see Authentication.
Trial credits to fund early usage before you connect your own model provider are available on request. They are billed to you, not your users.
Upgrade and roll back
The Self-hosted page in the portal shows the current release and whether your deployment is up to date. Upgrading is a decision you make, one line in .env.
Back up the database first (below). Expect one to two minutes of downtime while containers restart.
To roll back, set PMAP_VERSION to the previous release and run the same pull and start. Database migrations do not roll back; if a release's migration fails, restore your pre-upgrade backup, pin the previous release, and contact us.
We keep recent releases in the registry, not every release ever shipped. A deployment pinned to a release that has aged out cannot pull it onto a new host — upgrade before you migrate hosts, or contact support.
Back up
Two things hold state: your PostgreSQL database and the provenmap-data volume (sessions, cache, and the cached license).
Back the database up with your usual PostgreSQL process. From the host:
Back the data volume up as a tar archive:
The volume is rebuilt from the portal on the next start if you lose it; the database is not. Back the database up daily and before every upgrade.
SSL and reverse proxies
The stack ships with an nginx container on port 80. You have two options for HTTPS:
- Terminate TLS on your load balancer and forward to port 80. Nothing in the stack changes.
- Replace
nginx.confwith your own configuration, or route straight to the containers from your existing proxy (Traefik, Caddy, HAProxy). Use this routing table:
Keep ports 3000 and 3001 off the public internet; only the proxy should reach them.
Troubleshooting
The sign-in script prints FAIL … [code]
The portal refused registry access. The code in brackets says why.
Invalid deployment credentials means PMAP_APP_ID or PMAP_APP_SECRET is wrong — or the secret was recreated in the portal. Too many requests means more than ten sign-ins a minute from one address; wait a minute.
denied: Your authorization token has expired
Pull access lasts 12 hours from sign-in. Sign in again and retry:
… did not answer as the Portal API
PMAP_PORTAL_URL points at https://portal.provenmap.com, which is the web app. Remove the line from .env so the default applies, or set it to the API host from the outbound access table. Then recreate the server container so it picks up the change:
Pull stalls at 0% after a successful sign-in
The registry answered, but image layers download from S3 and your firewall blocks it. Allow HTTPS to *.s3.us-east-1.amazonaws.com — the regional pattern, not only *.s3.amazonaws.com. Confirm from the host; any HTTP status is fine, a connection error is the problem:
The server exits at startup with "Portal unreachable"
The server needs the portal API on its first start and whenever its cached license is older than PMAPP_OFFLINE_TTL. Check outbound access to the API host from inside the container:
A 200 means the network is fine and the credentials are the problem. Anything else is a firewall or proxy rule.
Port 80 is already in use
Set PMAP_PORT in .env to a free port and run docker compose -f docker-compose.production.yml up -d. The stack is then at http://localhost:<port>.
What's next
Enterprise SSO
Connect Okta, Entra ID, or any SAML/OIDC provider for your self-hosted users.
Authentication
Point the plugins and MCP clients at your instance with PMAP_BASE_URL and PMAP_MCP_URL.
Organization Settings
Roles, archetypes, and the S3 icon storage backend for self-hosted deployments.
Permissions & Access
Control who can view and edit boards once your team is signed in.







