Gateway Configuration File

View as Markdown

The OpenShell gateway reads its configuration from a TOML file when --config or OPENSHELL_GATEWAY_CONFIG is set. When neither is set, the gateway reads $XDG_CONFIG_HOME/openshell/gateway.toml if that file exists. If no config file exists, the gateway starts from built-in defaults. Gateway process flags and gateway OPENSHELL_* environment variables override the file. Compute driver settings live in the driver TOML tables. See RFC 0003 for the full schema.

Source Precedence

Gateway CLI flag > gateway OPENSHELL_* env var > TOML file > built-in default

database_url is env-only. The loader rejects it when it appears in the file. When OPENSHELL_DB_URL is unset, the gateway stores its SQLite database under $XDG_STATE_HOME/openshell/gateway/openshell.db.

Package-Managed Locations

Package-managed gateways do not require a TOML file. Create one at the package’s optional config location when you need to override built-in defaults. Set OPENSHELL_GATEWAY_CONFIG in the launch environment to use a different file.

PackageOptional Gateway TOML location
Homebrew$XDG_CONFIG_HOME/openshell/gateway.toml when it exists, otherwise an existing Homebrew prefix config such as /opt/homebrew/var/openshell/gateway.toml.
Debian/Ubuntu$XDG_CONFIG_HOME/openshell/gateway.toml, usually ~/.config/openshell/gateway.toml for the systemd user service.
Fedora/RHEL RPM$XDG_CONFIG_HOME/openshell/gateway.toml, usually ~/.config/openshell/gateway.toml for the systemd user service.
Snap$SNAP_COMMON/gateway.toml, usually /var/snap/openshell/common/gateway.toml.

Layout

The file is rooted at [openshell]. Gateway-wide settings live under [openshell.gateway]. Each compute driver owns its own [openshell.drivers.<name>] table. Shared keys set at gateway scope are inherited into driver tables when not overridden.

1[openshell]
2version = 1
3
4[openshell.gateway]
5# ... gateway-wide settings ...
6
7[openshell.gateway.tls]
8# ... gateway listener TLS ...
9
10[openshell.gateway.oidc]
11# ... JWT bearer auth ...
12
13[openshell.drivers.kubernetes]
14# ... driver-specific settings ...

Full Example

A complete gateway configuration covering every section. Trim to the fields you need.

1# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
2# SPDX-License-Identifier: Apache-2.0
3
4[openshell]
5version = 1
6
7[openshell.gateway]
8bind_address = "0.0.0.0:8080"
9health_bind_address = "0.0.0.0:8081"
10metrics_bind_address = "0.0.0.0:9090"
11
12log_level = "info"
13
14# When empty the gateway auto-detects (Kubernetes -> Podman -> Docker). VM is
15# never auto-detected and requires an explicit entry here.
16compute_drivers = ["kubernetes"]
17
18sandbox_namespace = "openshell"
19
20# Subject Alternative Names baked into the gateway server certificate.
21# Wildcard DNS SANs (e.g. "*.dev.openshell.localhost") also enable sandbox
22# service URLs under that domain.
23server_sans = ["openshell", "*.dev.openshell.localhost"]
24# Allow plaintext HTTP routing for loopback sandbox service URLs.
25enable_loopback_service_http = true
26
27# Shared driver defaults — inherited into [openshell.drivers.<name>] tables
28# when the driver-specific table does not override them.
29default_image = "ghcr.io/nvidia/openshell/sandbox:latest"
30supervisor_image = "ghcr.io/nvidia/openshell/supervisor:latest"
31client_tls_secret_name = "openshell-client-tls"
32
33# Gateway listener TLS (distinct from the per-driver guest_tls_*).
34[openshell.gateway.tls]
35cert_path = "/etc/openshell/certs/gateway.pem"
36key_path = "/etc/openshell/certs/gateway-key.pem"
37client_ca_path = "/etc/openshell/certs/client-ca.pem"
38allow_unauthenticated = false
39
40[openshell.gateway.oidc]
41issuer = "https://idp.example.com/realms/openshell"
42audience = "openshell-cli"
43jwks_ttl_secs = 3600
44roles_claim = "realm_access.roles"
45admin_role = "openshell-admin"
46user_role = "openshell-user"

image_pull_policy is intentionally not a shared gateway key. Kubernetes uses Always | IfNotPresent | Never while Podman uses always | missing | never | newer. Set it inside the relevant driver table.

Per-Driver Examples

Kubernetes

The gateway runs as a Pod and creates sandbox Pods in another namespace. mTLS material for sandboxes is delivered via a Kubernetes Secret rather than host-side file paths.

1[openshell]
2version = 1
3
4[openshell.gateway]
5bind_address = "0.0.0.0:8080"
6health_bind_address = "0.0.0.0:8081"
7metrics_bind_address = "0.0.0.0:9090"
8log_level = "info"
9compute_drivers = ["kubernetes"]
10
11default_image = "ghcr.io/nvidia/openshell/sandbox:latest"
12supervisor_image = "ghcr.io/nvidia/openshell/supervisor:latest"
13client_tls_secret_name = "openshell-client-tls"
14
15[openshell.gateway.tls]
16cert_path = "/etc/openshell-tls/server/tls.crt"
17key_path = "/etc/openshell-tls/server/tls.key"
18client_ca_path = "/etc/openshell-tls/client-ca/ca.crt"
19
20[openshell.drivers.kubernetes]
21namespace = "agents"
22grpc_endpoint = "https://openshell-gateway.agents.svc:8080"
23image_pull_policy = "IfNotPresent"
24# Use the image volume on K8s >= 1.35 (GA in 1.36); switch to "init-container"
25# on older clusters or where the ImageVolume feature gate is off.
26supervisor_sideload_method = "image-volume"

Docker

Sandboxes run as containers on a local bridge network. The supervisor binary is bind-mounted from the host (no in-cluster image pull required); guest mTLS material is supplied as host paths.

1[openshell]
2version = 1
3
4[openshell.gateway]
5bind_address = "127.0.0.1:17670"
6log_level = "info"
7compute_drivers = ["docker"]
8
9supervisor_image = "ghcr.io/nvidia/openshell/supervisor:latest"
10guest_tls_ca = "/etc/openshell/certs/ca.pem"
11guest_tls_cert = "/etc/openshell/certs/client.pem"
12guest_tls_key = "/etc/openshell/certs/client-key.pem"
13
14[openshell.drivers.docker]
15default_image = "ghcr.io/nvidia/openshell/sandbox:latest"
16image_pull_policy = "IfNotPresent"
17sandbox_namespace = "docker-dev"
18grpc_endpoint = "https://host.openshell.internal:17670"
19network_name = "openshell-docker"
20# Skip the image-pull-and-extract step by pointing at a locally built binary.
21supervisor_bin = "/usr/local/libexec/openshell/openshell-sandbox"

Podman

Sandboxes run as Podman containers on a user-mode bridge network. The supervisor image is mounted read-only via Podman’s type=image mount; guest mTLS material is supplied as host paths.

1[openshell]
2version = 1
3
4[openshell.gateway]
5bind_address = "127.0.0.1:17670"
6log_level = "info"
7compute_drivers = ["podman"]
8
9default_image = "ghcr.io/nvidia/openshell/sandbox:latest"
10supervisor_image = "ghcr.io/nvidia/openshell/supervisor:latest"
11guest_tls_ca = "/etc/openshell/certs/ca.pem"
12guest_tls_cert = "/etc/openshell/certs/client.pem"
13guest_tls_key = "/etc/openshell/certs/client-key.pem"
14
15[openshell.drivers.podman]
16# Rootless socket path. For root Podman use /run/podman/podman.sock.
17socket_path = "/run/user/1000/podman/podman.sock"
18network_name = "openshell"
19stop_timeout_secs = 10
20image_pull_policy = "missing" # Podman vocabulary: always | missing | never | newer

MicroVM

Each sandbox runs inside its own libkrun microVM managed by the standalone openshell-driver-vm subprocess. Use this driver when you want stronger isolation than container namespaces alone.

1[openshell]
2version = 1
3
4[openshell.gateway]
5bind_address = "127.0.0.1:17670"
6log_level = "info"
7# VM is never auto-detected; an explicit entry here is required.
8compute_drivers = ["vm"]
9
10default_image = "ghcr.io/nvidia/openshell/sandbox:latest"
11guest_tls_ca = "/var/lib/openshell/guest-tls/ca.pem"
12guest_tls_cert = "/var/lib/openshell/guest-tls/client.pem"
13guest_tls_key = "/var/lib/openshell/guest-tls/client-key.pem"
14
15[openshell.drivers.vm]
16grpc_endpoint = "https://host.containers.internal:17670"
17state_dir = "/var/lib/openshell/vm"
18# Where the gateway looks for the openshell-driver-vm subprocess binary.
19driver_dir = "/usr/local/libexec/openshell"
20vcpus = 2
21mem_mib = 2048
22krun_log_level = 1