Skip to main content

Rolter is built to run in fully air-gapped environments with no public internet at build or run time. One outbound call is on by default, the release check, and you turn it off with ROLTER_UPDATE_CHECK=false. Every other call goes to an endpoint you configure, and this page lists each one with the setting that turns it on or off. It also shows how to install Rolter behind an internal mirror and how to verify the deployment offline.

Runtime egress#

The release check is on by default#

Left alone, two parts of Rolter ask https://api.github.com/repos/rolter-ai/rolter/releases/latest whether a newer stable release exists:

  • The control plane asks once at boot and every six hours. The answer feeds the version hint in the dashboard footer and GET /api/v1/version.
  • The rolter command asks beside whatever subcommand you run, gateway, control, easy-up and check included, and prints one line to stderr when a newer release exists. A successful answer is cached for 24 hours in ~/.cache/rolter/update-check.json. A failed one is not cached, so a host that cannot reach GitHub tries again on every invocation.

The request is one GET with a 5-second timeout and a User-Agent: rolter/<version> header. It carries no installation id, configuration or credentials. A failure is logged at debug, never delays a command and never changes an exit status, so an enclave keeps working with the check left on. The attempts still show up in a firewall or DNS log, and a policy that treats an unexpected external lookup as an incident will flag them.

Turn it off with one environment variable:

Set it on the control plane and on every host or container that runs the rolter command. With the Docker image that is every container, because its default command is rolter easy-up. The rolter-control binary carries the control plane’s check; rolter-gateway run directly has none.

With the Helm chart, control.updateCheck: false reaches the control plane and the gateway pods, including their preflight init containers, which also run rolter check:

With the check off, the dashboard footer shows the running version alone and /api/v1/version reports "enabled": false. See Update check.

Every outbound path#

The release check is the only path that is on without configuration. Each of the others stays idle until you set the setting in its row, so a deployment that never sets them makes no other outbound call.

Every operator-written URL in the table below, from a provider’s api_base to an alert channel’s endpoint, also passes the egress policy before it is called. To refuse internal ranges, turn on block_private and block_loopback and list the internal hosts the deployment must still reach in allow_hosts.

PathWhat it reachesSettingDefault
Release checkapi.github.com, described aboveROLTER_UPDATE_CHECK=false turns it offOn
Upstream providersEach provider’s api_base and the provider’s egress_proxy when set. Also the embeddings provider of a semantic cache and the Test button on the Providers screenThe providers and routes you configureNone. The built-in fake-llm makes no outbound call
PostgresThe host in ROLTER_DATABASE_URL, from the control planeROLTER_DATABASE_URLUnset: in-memory store
RedisThe host in ROLTER_REDIS_URL, from both planes: budgets, rate limits, the response cache, the sign-in throttle and config pub/subROLTER_REDIS_URL, or --redis-url on the gatewayUnset
ClickHouseRequest logs, captured payloads, provider health events and the control plane’s analytics and alert queriesCLICKHOUSE_URL or [logging].clickhouse_url. A gateway with neither inherits the control plane’sUnset: nothing is logged
Gateway to control planeConfig poll every 5 seconds, the log destination at boot and adaptive-routing telemetry, all to the snapshot URL’s host. The /admin/* proxy goes to the admin URLROLTER_SNAPSHOT_URL and ROLTER_SNAPSHOT_POLL_SECS, ROLTER_ADMIN_URLUnset: static bootstrap config
Control plane to gatewayDashboard Playground requests, sent through /gw/*. No traffic while nobody uses the PlaygroundROLTER_GATEWAY_URLhttp://localhost:4000
Alert channelsEach enabled channel’s endpoint: one JSON POST when a rule changes state. See AlertingAlerting → ChannelsNo channels
OTLP exportThe OTLP receiver, for traces, metrics and logs from both planes. See TracingOTEL_EXPORTER_OTLP_ENDPOINT, or its _TRACES_, _METRICS_ and _LOGS_ variants. ROLTER_TELEMETRY_ENABLED=false blocks every exporterUnset: no exporter is built
Connector testThe connector’s endpoint: one empty OTLP request when someone presses Test, whether or not the connector is enabled. Rolter sends nothing else to a connector. See ConnectorsObservability → ConnectorsNo connectors
Dashboard browser tracingThe OTLP/HTTP endpoint named in the served page, called from each user’s browserROLTER_UI_OTEL_ENDPOINT. ROLTER_TELEMETRY_ENABLED=false drops itUnset: the dashboard loads no tracing code
Active health probesEach provider’s api_base plus [health].path, every interval_secs (10). also_track_via_llm_call sends a one-token completion. See Health checks[health] enabledfalse
Model catalogue refreshEach provider’s model-list endpoint, every [health].catalogue_interval_secs (900), even with [health] off. It feeds GET /v1/models[health] catalogue_interval_secs. Set 0 to turn it off900
Engine metrics scrapeEach provider’s api_base plus /metrics, every interval_secs (5). See Load balancing[metrics_scrape] enabledfalse
Provider status pagesA provider’s status_page_url, every [health].status_page_interval_secs (60), even with [health] offstatus_page_url on a provider. Leave it unset, or point it at an internal mirrorUnset
Cache-aware routing signalsA provider’s kv_events.endpoint (a ZeroMQ subscription such as tcp://vllm-0:5557) and its lmcache.endpoint (an HTTP poll every refresh_secs, 2 by default). See Cache-aware routingkv_events and lmcache on a providerUnset
MCP serversThe url of each registered server, when a client calls it through /mcp/<server>. See MCP serversThe registered MCP serversNone
MCP OAuthFor a server that uses OAuth, the control plane fetches the server’s resource metadata and its authorization server’s metadata when consent starts, posts to the token endpoint when it completes, and refreshes tokens near expiry in a sweep every 60 seconds. See MCP OAuthMCP servers set to OAuthNone
Single sign-onFor each identity provider, the control plane fetches <issuer>/.well-known/openid-configuration and the jwks_uri, and posts to the token_endpoint, at each sign-in. See Single sign-onGovernance → Single Sign-OnNo providers
Guardrail webhookThe webhook URL: one POST per request, before it goes upstream. See Guardrails[guardrail_webhook] enabled, or activating a provider under Guardrails → ProvidersDisabled
PII sanitizer[pii_sanitizer].url, restore_url when restoration is on, and restore_stream_url under streaming = "restore". See PII sanitizer[pii_sanitizer] enabledDisabled
Webhook pluginsThe endpoint of each enabled plugin instance, on every matching request at its stage. See PluginsPlugins: an instance is live while it is enabledNo instances

Several rows point at services you host inside the enclave, such as a guardrail service, a Presidio sanitizer or an OpenTelemetry Collector. Rolter opens those connections too, so they are listed.

These do not make an outbound call:

  • SCIM provisioning is inbound only. Your identity provider calls /scim/v2/* on ROLTER_PUBLIC_URL, and Rolter never calls it back.
  • Invitations send no email. Rolter returns the link and you pass it on.
  • Payload capture writes to ClickHouse and nowhere else, and only when [logging.payload_capture] is enabled.
  • Prometheus metrics are scraped from /metrics by your Prometheus. Rolter pushes nothing to it.
  • Built-in guardrails and the fake-llm model run inside the gateway process.

rolter check --connect opens a TCP connection to the hosts in ROLTER_DATABASE_URL and ROLTER_REDIS_URL, and to the mail relay in ROLTER_SMTP_URL when one is set. It is a command you run, not a background task.

The dashboard and the API reference#

The interactive API reference at /docs embeds the Scalar JS bundle in the binary and sets withDefaultFonts: false, so it never reaches a CDN or fonts.scalar.com. The docs_page_is_self_contained and scalar_bundle_is_embedded tests in crates/rolter-gateway/src/openapi.rs enforce it.

The dashboard SPA is served as static assets by the control plane. Its fonts and icons are vendored in the build, and it loads no third-party scripts, fonts or styles. Its documentation links are off unless you configure a documentation host, so an enclave with no mirror of this site simply sees no links. See Documentation links. The footer’s repository and bug-report buttons point at github.com. They are ordinary links that open only when someone clicks one, and the page loads nothing from them.

Install paths through a mirroring proxy#

Air-gapped sites usually proxy public registries through an internal mirror (Sonatype Nexus, JFrog Artifactory, Harbor, …). Pick the path that matches how you ship Rolter.

Pull through a registry that proxies GHCR/Docker Hub:

Or transfer a fully offline image with docker save / docker load:

Operator checklist#

Set before you deploy:

  • ROLTER_UPDATE_CHECK=false on the control plane and wherever the rolter command runs. In Helm, control.updateCheck: false covers both Deployments.

Must be reachable inside the enclave:

  • Every configured provider api_base (your internal model servers or a proxied provider endpoint).
  • Postgres, Redis, and ClickHouse hosts, only for the features you enable.
  • The control plane, if the gateway runs with --snapshot-url.
  • Every endpoint you chose to configure from the table above, such as an alert webhook, an identity provider, an MCP server or a collector.

Must NOT be required:

  • Public package registries at run time (only at install/build time, through the mirror).
  • CDNs (cdn.jsdelivr.net, fonts.scalar.com, npm/unpkg). Rolter references none.
  • api.github.com. With ROLTER_UPDATE_CHECK=false the release check is not attempted.
  • Telemetry endpoints, unless you deliberately set OTEL_* to an internal collector.
  • Provider status pages. Leave status_page_url unset.

Offline smoke test#

Verify a running gateway with zero external providers using the built-in fake-llm model (deterministic, no upstream or secrets needed):

A 200 with a lorem-ipsum completion confirms the gateway serves traffic with no outbound calls. Open http://localhost:4000/docs and confirm the API reference renders with no network requests leaving the host.