Deploying
How to deploy Nexus
This directory contains the Compose stack used for local development and self-hosting, plus a first Helm chart for Kubernetes.
- Compose —
compose/docker-compose.yml(release images) withcompose/docker-compose.dev.ymllayered on for hot-reload development. The rootREADME.mdquickstart and../docs/onboarding.mdwalk through bringing it up withjust dev. - Helm —
helm/nexusfor a single-node Kubernetes deployment.
For image verification before you run anything, see
../docs/ops/releases.md. Operator deployment
automation (image bundling, hardened server stack, backup/restore scripts)
is host-provisioning tooling and lives outside this repository.
Operator responsibilities
Section titled “Operator responsibilities”The stack in this repository does not manage TLS, public exposure, or secret material for you:
- TLS is operator-supplied. The Compose stack serves plain HTTP on localhost; put your own TLS-terminating reverse proxy in front of anything publicly reachable.
- Ports: the stock Compose stack publishes the gateway (
14450), several service health/debug ports, the console (14449), MinIO (9000/9001), Grafana (14470), and the OTel collector’s self-metrics (18888) to the host. Postgres, ClickHouse, NATS, and Valkey stay inside the compose network. See../docs/reference/ports.mdfor the full table before exposing a host to a network you do not trust. - Secrets: the committed defaults are development-only. For anything
beyond a laptop, change every secret (
NEXUS_SERVICE_TOKEN,AUTH_JWT_SECRET, the*_PASSWORDvalues, S3 keys) and render.envfrom a real secret manager. See../docs/ops/secrets.md. - Object storage: production audit archives need S3 Object Lock/WORM semantics. The bundled MinIO exercises the integration locally; supply your own object storage with retention enforcement for production.
Self-hosting with Compose
Section titled “Self-hosting with Compose”# From the repository root:cp .env.example .env # edit secrets and hostnamesjust dev # dev stack (hot reload)# or, release images only:just dev-releaseHealth checks:
just status # /healthz across services + infra probescurl -fsS http://127.0.0.1:14450/healthzBackup
Section titled “Backup”For a self-hosted Compose stack, snapshot Postgres with pg_dumpall:
mkdir -p backups/$(date +%F)docker compose --env-file .env -f compose/docker-compose.yml exec -T postgres \ pg_dumpall -U vortex | gzip > backups/$(date +%F)/postgres.sql.gzClickHouse analytics data and object-storage contents (request bodies, artifacts, audit archive) need their own backup strategy; retention for the audit archive is part of the operator’s object-storage configuration. Always verify a backup by restoring it into a fresh environment before relying on it.
Helm (Kubernetes)
Section titled “Helm (Kubernetes)”A thin single-node chart lives in helm/nexus. It is intended
for small deployments; the chart does not configure HPA, NetworkPolicies, or
PodSecurity hardening.
helm install nexus deploy/helm/nexus \ --namespace nexus --create-namespace \ --set ingress.host=nexus.example.com \ --set ingress.consoleHost=console.example.com \ --set existingSecret=nexus-secrets # a Secret you created with strong valuesThe chart declares no ordering between pods, so an upgrade must roll ingest
before query. ingest owns the ClickHouse schema: it applies pending
migrations before it serves /healthz, and exits if they fail. query selects
columns those migrations add, so a query pod that starts against a schema
ingest has not yet migrated answers request list, detail, and session reads
with an error until ingest catches up. The webhook exporter runs inside
query and selects the same columns, so exporter polls fail for that window
too and deliveries are deferred rather than lost. The Compose deployment expresses this
with depends_on; on Kubernetes it is the operator’s to sequence.
See helm/nexus/values.yaml for image tags, ingress,
storage sizes, and the secret contract. The chart deploys the eight Rust
services and the console, plus optional single-replica data-plane helpers.
MinIO and the Redis-compatible cache are disabled by default; provide external
object storage with Object Lock/WORM support and a Redis-compatible endpoint
for production.
