Air-gap install

An air-gapped install of Ithura is one that runs with no outbound network access to the internet. This guide walks through the constraints that apply, the images and assets you need to bring in from a connected network, and the configuration that keeps a running instance from attempting an outbound call it will never complete.

What "air-gapped" means for Ithura

The Ithura binary itself does not need internet access to run. It reads and writes to Postgres, Valkey, and RustFS (all local to the deployment), and serves the SPA. There is no license check, no telemetry endpoint, no model-download step, and no update-check callback.

The features that DO need outbound access are the ones that talk to a third party by design: SSO to an external Identity Provider, outbound email via an external SMTP relay, Slack notifications, GitHub or GitLab webhooks, Stripe billing, Google Drive or Dropbox picker. If you disable these integrations, Ithura runs indefinitely with zero outbound traffic beyond OS-level DNS, TLS, and NTP.

Things you need to bring in

Ithura is packaged as OCI images and a single Helm chart / Docker compose file. To install into an air-gapped environment you need:

  1. The Ithura API image. Published to the public registry with a tagged version, e.g. ithura/api:v1.42.0.
  2. The Ithura web image. The static SPA server, tagged ithura/web:v1.42.0.
  3. The Yjs sidecar image. ithura/live:v1.42.0.
  4. Standard backing images you likely already have in your internal registry: postgres:16, valkey/valkey:8, rustfs/rustfs:latest (pin a specific tag), livekit/livekit-server:latest. Choose the pinned versions from the reference compose or Helm chart.
  5. The signed SBOM for each image, so your security team can review it before the image lands in the internal registry.

Pull each image on a connected machine, verify signature and SBOM, docker save it to a tar file, transfer to the air-gapped side, and docker load into your internal registry.

Configuration for zero egress

The following environment variables and settings prevent Ithura from attempting an outbound call it cannot complete.

Disable optional integrations

Leave every integration OAuth client secret unset. On startup Ithura will simply not expose the integration in the admin UI, so no user can accidentally attach a Slack workspace that will never send a message.

  • SLACK_CLIENT_ID, SLACK_CLIENT_SECRET unset
  • GITHUB_CLIENT_ID, GITHUB_CLIENT_SECRET unset
  • GITLAB_CLIENT_ID, GITLAB_CLIENT_SECRET unset
  • GOOGLE_DRIVE_CLIENT_ID, GOOGLE_DRIVE_CLIENT_SECRET unset
  • DROPBOX_CLIENT_ID, DROPBOX_CLIENT_SECRET unset
  • STRIPE_SECRET_KEY, STRIPE_WEBHOOK_SECRET unset

Outbound email

If you have an internal SMTP relay, point Ithura at it via the admin UI (instance configurations). If you have none, leave EMAIL_HOST unset; Ithura will log outbound email attempts as failures and continue. Users will not receive invite emails or password-reset emails and must be provisioned via the admin API instead.

SSO to an internal IdP

If you have an internal SAML IdP reachable from the Ithura host, wire it up normally (see the SSO overview). The IdP's certificate and endpoints are the only outbound information; no callback to Ithura's authors is made.

If your organisation has no SAML IdP, users authenticate with local usernames and passwords or with local TOTP 2FA.

Metrics and observability

  • Prometheus. Set METRICS_TOKEN=<random-32-byte-string> and point your internal Prometheus at https://<api-host>/metrics. Ithura does not push metrics anywhere; scrape-only.
  • OpenTelemetry. Leave the OTEL variables unset. If you have an internal collector, set them; the collector must itself be air-gapped or you have re-introduced egress.

What still tries to reach the internet on a stock install

Nothing from Ithura's own code. The following are OS-level activities you may still see and can decide about at your network policy:

  • DNS lookups for the hostnames you configured (mail relay, IdP, etc.)
  • NTP clock sync (needed for TLS certificate validity)
  • TLS certificate revocation checks (OCSP), depending on your TLS terminator
  • Docker image pulls if a container restart triggers a re-pull; use a local registry mirror to keep this in-network
  • Let's Encrypt ACME challenges if you use the reference Traefik setup; swap in an internal PKI or a pre-issued certificate to avoid this

None of these originate from Ithura's binary.

Verification checklist

Before declaring the install air-gapped, run these commands from a shell inside the Ithura API container.

# 1. The Ithura API binary itself has no outbound TCP:
ss -pant | grep ithura | grep ESTAB
# Expect: only connections to postgres, valkey, rustfs, livekit.

# 2. DNS is only asking about your configured hosts:
tcpdump -i any -n port 53 for 30 seconds
# Expect: only your mail relay, IdP, and internal registry.

# 3. No unexpected TLS handshakes:
tcpdump -i any -n port 443 for 60 seconds
# Expect: silence, or only your explicitly configured integrations.

If any of these show unexpected traffic, open a security advisory and investigate the source. Ithura's default configuration does not generate outbound traffic on its own.