---
title: "Deploy and operate"
---

# Deploy and operate

Ways to run Neural Inverse Govern on your own infrastructure, what it needs, and the checks and settings every installation shares.

Neural Inverse Govern (Keystone) runs on infrastructure you control. The control plane is a single Go binary, `ni-auth`, with PostgreSQL as its only required dependency. Optional planes handle telemetry intake, data-plane traffic and compliance ingestion.

## Choose a deployment

| Option | Use it for | Guide |
|---|---|---|
| Docker Compose | A single host: evaluation, development, or a small installation | [Docker Compose](https://neuralinverse.com/docs/deploy/docker-compose/) |
| Kubernetes with Helm | Production on your own clusters, on premises or in your own cloud account | [Kubernetes](https://neuralinverse.com/docs/deploy/kubernetes/) |
| Air-gapped | Networks with no internet access | [Air-gapped installation](https://neuralinverse.com/docs/deploy/air-gapped/) |

In your own cloud, Govern runs on your Kubernetes cluster with the `keystone` Helm chart, a managed PostgreSQL service, and your object storage and secret store.

## Requirements

- **PostgreSQL.** The Docker Compose stack ships PostgreSQL 17. If you bring your own database, it must be PostgreSQL 15 or later; on an older server the migrations stop with "Keystone requires PostgreSQL 15 or later" before changing anything.
- **Three database roles.** Govern never runs as the PostgreSQL superuser. `keystone_owner` owns the schema and runs migrations, `keystone_app` serves every tenant request under row-level security, and `keystone_platform` serves a short list of named cross-organisation tasks. Both deployment methods create them for you; each needs its own password of at least 16 characters.
- **Docker Compose**: Docker 24.0 or later and Docker Compose v2.20 or later.
- **Kubernetes**: Kubernetes 1.29 or later and Helm 3.
- **TLS.** The server does not terminate TLS in the Docker Compose stack; put a reverse proxy in front of it. On Kubernetes, use your Ingress or load balancer.
- **Connection pooling.** If you use PgBouncer, use session mode. Transaction mode is not supported, because the tenant of each connection is a session setting.

## Planes

| Plane | Binary | Port | Purpose |
|---|---|---|---|
| Control | `ni-auth` | 8080 (API), 9090 (internal worker API) | API, sign-in, policy, gateways, audit |
| Console | Next.js | 3000 | Administration UI |
| Telemetry | `keystone-ingest` | 8081 | Event and telemetry intake |
| Data | `keystone-bridge` | 8082, 3129 | Data-plane traffic and the vault egress proxy |
| Compliance | `keystone-comply` | 9093 | Polling of third-party vendor audit APIs |

The Docker Compose stack runs the control plane, PostgreSQL and a web dashboard. The Helm chart runs every plane as its own Deployment.

## Secrets every installation needs

Govern refuses to start in production without its keys, and refuses placeholder or development values unless `NI_AUTH_DEPLOY_ENV` is set to `development`, `dev`, `local` or `test`. Generate each key separately and keep it in your secret store.

| Key | Purpose | Generate |
|---|---|---|
| `KMS_MASTER_KEY` | Seals the encryption keys, the audit signing keys and the manifest signing keys | `openssl rand -hex 32` |
| `NI_AUTH_AUDIT_HMAC_KEY` | Keys the audit log hash chain | `openssl rand -base64 48` |
| `NI_OBSERVABILITY_SIGNING_KEY` | Keys the compliance evidence chain | `openssl rand -base64 48` |
| `NI_AUTH_API_KEY_PEPPER`, `NI_AUTH_OAUTH2_PEPPER`, `NI_AUTH_EMAIL_TOKEN_PEPPER` | Peppers for credential digests | `openssl rand -base64 48` |
| `NI_AUTH_TOTP_ENCRYPTION_KEY`, `NI_AUTH_LDAP_ENCRYPTION_KEY`, `NI_AUTH_SOCIAL_ENCRYPTION_KEY`, `NI_AUTH_WEBHOOK_ENCRYPTION_KEY` | AES-256-GCM keys for secrets at rest | `openssl rand -base64 32` |
| `NI_AUTH_VAULT_ENCRYPTION_KEY`, `NI_AUTH_SECRETS_ENCRYPTION_KEY` | Encrypt AI provider keys and governed secrets | `openssl rand -base64 48` |
| `NI_AUTH_PASSPORT_KEY`, `NI_AUTH_APPROVAL_SECRET` | Sign Model Passports and approval tokens | `openssl rand -base64 48` |

Keep `KMS_MASTER_KEY`, `NI_AUTH_AUDIT_HMAC_KEY` and `NI_OBSERVABILITY_SIGNING_KEY` stable for the life of the installation: keys sealed under the master key cannot be opened with another, and a changed HMAC key makes every existing chain fail verification. The vault, secrets and DLP token keys can be rotated by moving the old value to the matching `*_RETIRED_KEYS` variable.

## Outbound connections

Govern refuses to send requests to tenant-supplied URLs that point at internal addresses: loopback, private networks, link-local, carrier-grade NAT and cloud metadata addresses. The check runs when the connection is made, so host names that resolve to an internal address, and redirects to one, are refused as well. It covers webhooks, approval channels, SIEM integrations, model provider upstreams, inference servers and every LDAP connection.

To reach your own internal services (an on-premises inference server, LDAP or Active Directory, a SIEM collector), list their networks in `NI_AUTH_OUTBOUND_ALLOW_PRIVATE_CIDRS`, as narrowly as possible.

## Health and metrics

- `GET /healthz` reports the server and its database: `{"status": "ok", "database": "ok"}`.
- `GET /readyz` reports readiness; the Helm chart's server readiness probe uses `/readyz/selfguard`. See [Monitoring and self-healing](https://neuralinverse.com/docs/deploy/monitoring/).
- `GET /metrics` serves Prometheus metrics. It covers every organisation, so only a super admin or a request carrying the scrape token in `NI_AUTH_METRICS_TOKEN` (at least 32 bytes) can read it.

## Upgrades

1. Read the release notes for steps a release requires before it starts.
2. Back up the database.
3. Apply the migrations as `keystone_owner` (`DATABASE_OWNER_URL`). Docker Compose does this on every start; the Helm chart does it in a pre-upgrade hook.
4. Start the new version. The server refuses to start on a runtime role that is a superuser, has `BYPASSRLS` or owns objects, or while any tenant table is not isolated.

Take a backup and restore it rather than migrating down in production. The full procedure is in [Upgrades and migrations](https://neuralinverse.com/docs/deploy/upgrades/).

## Operate

| Task | Page |
|---|---|
| Upgrade and run migrations | [Upgrades and migrations](https://neuralinverse.com/docs/deploy/upgrades/) |
| Back up and restore | [Backup and restore](https://neuralinverse.com/docs/deploy/backup-restore/) |
| Look up an environment variable | [Configuration reference](https://neuralinverse.com/docs/deploy/configuration/) |
| Send email | [Email](https://neuralinverse.com/docs/deploy/email/) |
| Run behind proxies or a CDN | [Client IP addresses and proxies](https://neuralinverse.com/docs/deploy/client-ip/) |
| Monitor, and let Govern heal itself | [Monitoring and self-healing](https://neuralinverse.com/docs/deploy/monitoring/) |
| Collect agent and service telemetry | [Telemetry pipeline](https://neuralinverse.com/docs/deploy/telemetry-pipeline/) |
| Run workers in your own cloud account (hosted service) | [BYOC compute workers](https://neuralinverse.com/docs/deploy/byoc/) |
| Fix a problem | [Troubleshooting](https://neuralinverse.com/docs/deploy/troubleshooting/) |
| Prove the audit record | [Evidence](https://neuralinverse.com/docs/evidence/) |
