# Deploying Rivet in a VPC or Air-Gapped Network > Source: `src/content/cookbook/vpc-air-gapped.mdx` > Canonical URL: https://rivet.dev/cookbook/vpc-air-gapped > Description: Run Rivet entirely inside your own perimeter: single-binary or Docker Compose install, file system storage with no database infrastructure, and no outbound telemetry by default. --- Patterns for running self-hosted Rivet inside a private network: a VPC without internet egress, an on-premises rack, or a fully air-gapped environment. The engine is one service, the recommended single-node storage backend is the local file system, and the engine makes no outbound connections by default. Self-hosting is the only Rivet deployment model that supports air-gapped networks; see the [Self-Hosting Overview](/docs/self-hosting) for the full comparison with BYOC. ## What Runs Inside the Perimeter A self-hosted deployment has three components, all of which live inside your network: | Component | Role | Inside the perimeter | | --- | --- | --- | | Your backend | Your application server, including the runner that executes actor code | Yes | | Rivet Engine | Orchestration service that manages actor lifecycle, routes messages, and serves the dashboard and APIs | Yes | | Storage | Persistence for actor state. Local file system for single-node, PostgreSQL or FoundationDB for multi-node | Yes | There is no license server, no Rivet Cloud account, and no callback to `rivet.dev`. Clients inside the perimeter reach actors through the engine's gateway over your private network. See [Architecture](/docs/self-hosting#architecture). ## Single-Binary Install The engine compiles to a single `rivet-engine` binary. Build it from source outside the perimeter, then copy the binary across the boundary: ```bash git clone https://github.com/rivet-dev/rivet.git cd rivet cargo build --release -p rivet-engine # Copy target/release/rivet-engine into the perimeter. ``` Prebuilt binaries are coming soon; see [Installing Rivet Engine](/docs/self-hosting/install) for current options. Run it with the file system backend, which stores everything on local disk and is the production-ready choice for single-node deployments. The [File System](/docs/self-hosting/filesystem) docs list air-gapped environments as a primary use case because it needs no database infrastructure: ```bash RIVET__database__file_system__path="/var/lib/rivet/data" ./rivet-engine ``` Configuration can also come from files. The engine discovers config at `/etc/rivet/config.json` on Linux (JSON, JSON5, JSONC, YAML, and YML are all supported), and `--config` overrides the path. Environment variables use the `RIVET__` prefix with `__` as the separator. See [Configuration](/docs/self-hosting/configuration). The engine serves its own dashboard on port `6420`, so inspection and namespace management work with nothing but a browser inside the perimeter. ## Docker Compose Deployment For Docker hosts without registry access, move the engine image across the boundary the standard way: ```bash # Outside the perimeter. docker pull rivetdev/engine:latest docker save rivetdev/engine:latest -o rivet-engine.tar # Inside the perimeter. docker load -i rivet-engine.tar ``` Then run the engine and your app together in one Compose file: ```yaml services: rivet-engine: image: rivetdev/engine:latest ports: - "6420:6420" volumes: - rivet-data:/data environment: RIVET__FILE_SYSTEM__PATH: "/data" restart: unless-stopped my-app: build: . environment: RIVET_ENDPOINT: "http://default:admin@rivet-engine:6420" depends_on: - rivet-engine restart: unless-stopped volumes: rivet-data: ``` `RIVET_ENDPOINT` uses the format `http://namespace:token@host:port` and tells your app to connect to the engine as a runner instead of running standalone. After both services start, register your runner with the engine through the dashboard or its API. The full walkthrough, including PostgreSQL setup for multi-node deployments, is in [Docker Compose](/docs/self-hosting/docker-compose). ## No Outbound Telemetry The engine exports traces and metrics only when you opt in with OpenTelemetry. Export is disabled unless `RIVET_OTEL_ENABLED=1` is set, and the export target defaults to a local collector at `http://localhost:4317`. With no configuration, nothing crosses the perimeter. When you want observability, keep it inside the network: - Set `RIVET_OTEL_ENABLED=1` and point `RIVET_OTEL_GRPC_ENDPOINT` at a collector you run inside the perimeter. - Adjust `RIVET_OTEL_SAMPLER_RATIO` to control trace sampling. - Use the engine's health endpoint for liveness and readiness probes. See the [Production Checklist](/docs/self-hosting/production-checklist) for monitoring guidance. ## Embedding Rivet in a Customer's Environment If you ship software that runs inside your customers' VPCs, the same setup turns Rivet into an internal component of your product rather than a service your customers must reach over the internet: - **Ship the engine next to your app.** Add `rivetdev/engine` to the Compose file or chart you already deliver. Your app finds it over the private network via `RIVET_ENDPOINT`, so one artifact deploys the whole stack. - **One namespace per install.** The endpoint URL carries the namespace and token (`http://namespace:token@host:port`), so a single image works across customer deployments. See [Endpoints](/docs/general/endpoints). - **Generate a strong admin token per install.** Replace the default token and keep it server-side. Never include the admin token in `RIVET_PUBLIC_ENDPOINT` or anywhere clients can read it. - **Public endpoint only when needed.** `RIVET_PUBLIC_ENDPOINT` with a public (`pk_`) token is only required when browser clients connect to actors in [serverless runtime mode](/docs/general/runtime-modes). Backend-only deployments can skip it entirely. - **TLS at the customer's edge.** Terminate TLS with the customer's reverse proxy or load balancer in front of the engine. ## Scaling Past One Node | Backend | Use when | Status | | --- | --- | --- | | [File System](/docs/self-hosting/filesystem) (RocksDB-based) | Single-node deployments, including air-gapped installs | Production-ready, single node only | | [PostgreSQL](/docs/self-hosting/postgres) | Multi-node deployments | Recommended for multi-node today, but experimental | | FoundationDB | Largest production deployments | [Enterprise](/sales) | For multi-node deployments, run two or more engine nodes behind a load balancer and add NATS for pub/sub, which replaces the default PostgreSQL `LISTEN`/`NOTIFY` path at high throughput. Neither is needed for a single-node file system install. See the [Production Checklist](/docs/self-hosting/production-checklist). ## Perimeter Checklist - **Admin token**: Generate a strong, random token for engine authentication and verify it is not exposed to clients. - **TLS termination**: Encrypt connections to the engine via a reverse proxy or load balancer. - **No public exposure**: Keep port `6420` reachable only from inside the perimeter unless clients outside it genuinely need access. - **Health checks**: Configure liveness and readiness probes against the engine health endpoint. - **Telemetry**: Leave OpenTelemetry export off, or point it at a collector inside the network. - **Backups**: With the file system backend, back up the data directory. With PostgreSQL, configure automated backups and failover. ## Full Configuration - [Self-Hosting Overview](/docs/self-hosting) for architecture and the self-host vs BYOC comparison - [Installing Rivet Engine](/docs/self-hosting/install) for Docker, binary, and source installs - [Docker Container](/docs/self-hosting/docker-container) and [Docker Compose](/docs/self-hosting/docker-compose) for container deployments - [Kubernetes](/docs/self-hosting/kubernetes) for cluster deployments - [Configuration](/docs/self-hosting/configuration) for every option and the full JSON schema - [Endpoints](/docs/general/endpoints) for connecting your backend and clients - [Production Checklist](/docs/self-hosting/production-checklist) before going live _Source doc path: /cookbook/vpc-air-gapped_