1 Configuration
Kyle Mendell edited this page 2026-10-27 15:06:39 -05:00

The control plane's configuration is file-based and lives in two layers:

  • overpass.yaml — hand-authored, never written by the server. Anything declared here is authoritative and shows as read-only in the web UI.
  • The config directory (<data_dir>/overpass.d by default; relocate with config_dir:) — owned and written by the server. Everything created or edited through the web UI or API — cluster settings, roles, SSO connectors, desktop credentials and endpoints — is persisted here as YAML (settings.yaml, roles.yaml, connectors.yaml, desktop.yaml) and applied immediately, no restart needed. Secrets entered in the UI are stored encrypted with the cluster master key. Hand edits belong in overpass.yaml, not here.

Users, nodes, and join tokens are runtime state and live in the database, managed with opctl or the web UI. Clusters upgraded from a release that kept configuration in the database are migrated automatically on first boot: the old rows are written into the config directory (secrets stay encrypted) and the legacy tables are dropped.

Config file

overpass server and opctl read /etc/overpass.yaml (or /etc/overpass.yml) by default, or the path given with --config. A full example:

cluster_name: acme
data_dir: /var/lib/overpass
audit_retention_days: 90   # days to keep audit events; 0 keeps them forever

proxy:
  web_addr: 0.0.0.0:8443    # HTTPS: web UI + browser terminal + /api/v1 + /oidc
  ssh_addr: 0.0.0.0:3023    # client SSH routing
  tunnel_addr: 0.0.0.0:3024 # node reverse tunnels
  grpc_addr: 0.0.0.0:3025   # gRPC API: auth, node enrollment, admin
  public_addr: gate.acme.com   # external host clients dial for SSH/gRPC + cert SANs
  public_url: https://gate.acme.com  # external base URL (set behind a reverse proxy)
  trusted_proxies: [127.0.0.1/32] # proxies allowed to supply X-Forwarded-* headers
  tls_routing: false           # advertise the web port as the single endpoint (TLS ALPN routing)

# Process logging. --debug, --log-level and --log-format override these.
logging:
  level: info     # debug, info, warn, error or fatal
  format: text    # text (styled for a terminal), json or logfmt
  # caller: false     # source file and line; defaults to on at debug level
  # timestamp: true   # turn off under journald or `docker logs -t`

# Everything from the settings page; field names mirror the API. A field set
# here is locked in the UI. All optional.
settings:
  default_logins: [ubuntu]
  agent_tls: mldsa

# Declarative roles. Built-ins `admin` and `access` always exist; a same-name
# entry here overrides the built-in.
roles:
  - name: sre
    logins: [root, deploy]
    node_labels: { env: prod }
    rules: { manage_nodes: true, manage_tokens: true, terminal: true }

auth:
  default_oidc: okta
  oidc:
    - name: okta
      issuer_url: https://acme.okta.com
      client_id: 0oaEXAMPLE
      client_secret_env: OVERPASS_OKTA_SECRET
      claims_to_roles:
        - claim: groups
          value: sre
          roles: [admin]

# Browser desktop bridges plus declarative desktop targets (credentials and
# endpoints; see examples/overpass.yaml for the full shape). Probe state and
# enablement stay runtime actions in the UI.
desktop:
  web_rdp_enabled: false

Connectors, roles, settings fields, desktop credentials and endpoints declared in overpass.yaml are authoritative: the UI shows them with a config badge (or as locked fields) and refuses edits until the file changes. Entities of the same kind created through the UI live in the config directory and stay fully editable; on a name collision the main file wins.

Precedence

An explicitly defined overpass.yaml value is authoritative, including false, "", and []. The complete precedence order is:

  1. Explicit values in the selected overpass.yaml
  2. The server-managed config directory (UI/API-made configuration)
  3. Explicit command-line flags, then environment fallbacks
  4. Built-in defaults

To manage a setting from the web UI, omit that field from overpass.yaml instead of setting it to an empty value.

Upgrading from database-managed configuration

Releases before the file-based model kept cluster settings, roles, SSO connectors, and desktop credentials in the database. The first boot of a file-based release migrates them automatically: every customized row is written into the config directory (secrets stay encrypted under the same master key), the fleet target version moves to its own table, and the legacy tables are dropped. The startup log lists exactly what moved where. Entities that are also declared in overpass.yaml are skipped with a warning — the file wins. Nothing is required of you beyond backing up the data directory before upgrading, as with any release.

Ports

Port Setting Purpose
8443 web_addr HTTPS — web UI, REST API, OIDC endpoints, browser terminal
3023 ssh_addr Client SSH routing (op ssh connects here)
3024 tunnel_addr Node reverse tunnels (nodes dial out here)
3025 grpc_addr gRPC API — login, node enrollment, admin

All four default to 0.0.0.0. With tls_routing: false, clients and nodes need to reach 3023/3025 (and 3024 for nodes) directly.

Alternatively, with tls_routing: true only the web port needs to be reachable: direct connections use TLS ALPN, while clients behind a normal TLS-terminating HTTP reverse proxy automatically carry the same routed TLS connection inside a WebSocket. The web address is advertised to clients and nodes as the single endpoint. See single-port TLS routing.

TLS uses private fallback certificates: an ECDSA web leaf issued by the local tls-ca.crt, plus a self-signed ML-DSA leaf for Overpass agents. See TLS certificates.

Public address vs. public URL

These cover the two ways the outside world reaches overpass:

  • public_addr — the external host and optional port clients dial for SSH, tunnels, and gRPC. With TLS routing this may be the same HTTP reverse proxy hostname on port 443. The host is also baked into the fallback ECDSA TLS certificate's SANs.
  • public_url — the external base URL the browser and your IdP use to reach the web UI (e.g. https://gate.acme.com). It drives absolute links such as the OIDC redirect URI. Set it when running behind a reverse proxy; when unset, overpass infers it from the request. Forwarded headers are honored only when the direct peer is listed in trusted_proxies.

Flags

overpass server flags provide fallbacks for values omitted from the file:

Flag Maps to
--config path to the YAML file (default /etc/overpass.yaml)
--cluster-name cluster_name
--data-dir data_dir
--web-addr / --ssh-addr / --tunnel-addr / --grpc-addr proxy.*_addr
--public-addr proxy.public_addr
--public-url proxy.public_url
--trusted-proxies proxy.trusted_proxies
--tls-routing proxy.tls_routing
--debug / --log-level logging.level
--log-format logging.format

Environment fallbacks

For container deployments, these optional variables cover the two public addresses without requiring a Compose command: override:

Variable Fallback for Purpose
OVERPASS_PUBLIC_ADDR proxy.public_addr Host clients use for SSH/gRPC and the TLS certificate SAN.
OVERPASS_PUBLIC_URL proxy.public_url Browser-facing base URL used for links and OIDC redirects.

These variables do not override a value explicitly present in YAML. When public_url is empty, Overpass infers the browser address from the request (and only trusts forwarded headers from trusted_proxies). YAML-defined values are reapplied on every startup; values omitted from YAML can be managed through the web UI, which persists them in the config directory.

Deployment mode and runtime

Overpass inspects its environment on startup to decide whether in-place binary self-update and fleet updates are permitted:

Variable Values Purpose
OVERPASS_RUNTIME binary, container, package Declares how Overpass is deployed. binary allows in-place self-update. container and package disable self-update so updates are managed by image pulls or package rebuilds.
OVERPASS_CONTAINER 1, 0 Legacy container override. 1 forces container mode; 0 forces binary mode. OVERPASS_RUNTIME takes precedence when set.

Docker, Podman, and Kubernetes default to container image deployments (OVERPASS_RUNTIME=container). Persistent system containers (LXC, Incus, systemd-nspawn) run systemd over a persistent rootfs and default to binary deployment mode.

Initial setup

On a new data directory, Overpass prints a one-time setup claim code in the startup log. Open /setup in the browser, enter that code, and create the first administrator. The setup flow creates a full admin account, starts a browser session, and points to server enrollment, CLI installation, Unix login access, HTTPS, and SSO. The claim code is encrypted at rest until it is used; after the first user is created, setup cannot be reopened, even if that user is later deleted.

Data directory

data_dir (default /var/lib/overpass) holds the SQLite database (overpass.db), the CA private keys, the ECDSA tls-ca.crt and tls.crt / tls.key, plus the self-signed tls-mldsa.crt / tls-mldsa.key (ML-DSA-44, the default for Go agents). Browsers and older agents always use the ECDSA pair. Back it up — losing the CA keys invalidates every issued certificate — and back up the config directory (overpass.d/) with it: it holds UI-made configuration, and its secrets are encrypted with the master.key from the data directory. The server creates the configured directory when needed and restricts it to mode 0700 on startup. In a container it is exposed as a volume; the process runs as a non-root user, so a bind-mounted or named-volume directory must already be owned or writable by the configured container uid (default 65532; see PUID/PGID in the Docker guidance). The process cannot repair ownership of a root-owned mount.