Deployment
Getting Hoziron into production means picking an environment, provisioning a carrier licence, configuring networking, and wiring up observability. This section covers every supported deployment model — from a single binary on a VM to a Docker container, including air-gapped environments where nothing touches the internet. There is no supported Kubernetes/Helm deployment path today.
The right starting point depends on your constraints: team size, existing infrastructure, compliance requirements, and whether your models run locally or in the cloud.
Every deployment needs a carrier licence
hoziron-server refuses to boot any surface (API, Registry, MCP, or Dashboard — they all share one HozironPlatform instance) without a valid, Ed25519-signed carrier licence at $HOZIRON_HOME/licence.json. There is no environment variable, test flag, or config toggle that bypasses this — it is a hard error at platform init. This applies even to a registry-only deployment; the registry surface still boots the shared platform and hits the same check.
Every guide in this section includes the licence step. Skip it and the process starts, logs the surfaces it's trying to boot, then exits with No carrier licence found at .../licence.json. A valid licence file is required to start the platform.
Jump to Bare metal § Carrier licence for the mechanics, or Air-gapped § Licence provisioning is fully offline if you're deploying somewhere with no network access at all.
What you'll find here
| Guide | Description |
|---|---|
| Bare metal / VM | Install the binaries, provision a licence, configure systemd, create a dedicated service user |
| Docker Compose | The repo's actual docker-compose.yml, volume mounts, the --version-based healthcheck, optional Caddy reverse proxy |
| Air-gapped | Disconnected environments: local models, fully offline licence verification, offline package transfer |
| TLS and networking | Per-surface [surfaces.<name>] networking config — real in-process TLS, IP allowlist, request limits, Unix sockets — and the main-route/mount listener topology |
| Observability | Structured logging, Prometheus metrics, and the workflow_step/llm_call tracing spans |
| Backup and restore | hoziron-cli backup create/list/restore, what's actually in the archive, and the API equivalents |
Which guide should I start with?
Common tasks
- Get running in under 5 minutes (dev/eval) → Docker Compose § Quick start
- Provision a carrier licence → Bare metal § Carrier licence
- Set up in-process TLS termination → TLS and networking § TLS termination
- Set up Prometheus scraping → Observability § Prometheus metrics
- Transfer packages to a disconnected network → Air-gapped § Offline package transfer
- Back up before an upgrade → Backup and restore § Create a backup
Key defaults
| Setting | Default | Override |
|---|---|---|
| API surface listen address | 127.0.0.1:4200 | --api-listen flag or [surfaces.api].listen in config.toml |
| Registry surface | Disabled | --surfaces api,registry flag or [surfaces.registry].enabled = true |
| Active surfaces | api only | --surfaces api,registry,mcp,dashboard flag, or the enabled flag under each [surfaces.*] table |
| Carrier licence path | $HOZIRON_HOME/licence.json | licence_path at the top level of config.toml |
| TLS | Disabled per surface by default | [surfaces.<name>.tls] (main route only) for real in-process termination (axum-server + rustls), or terminate at a reverse proxy, load balancer, or ingress controller instead |
/metrics (Prometheus) | Always on when the API surface is active — no config toggle | N/A |
| Unified health check | /__server/health on every listener, regardless of which surfaces are active | Always on |
| Logs | Text format to stderr + $HOZIRON_HOME/logs/server.log (daily rotation) | HOZIRON_LOG filter directives; HOZIRON_LOG_FORMAT=json switches both sinks to structured JSON |
Related
- Security — hardening your deployment once it's running
- Providers — connecting to models (cloud or local)
- Data integration — network configuration affecting external connectivity