{
    "product": "Cenvero Stratum",
    "generated_at": "2026-08-03T07:18:09+00:00",
    "format": "cenvero-docs-v1",
    "document_count": 1,
    "documents": [
        {
            "slug": "configuration",
            "title": "Configuration",
            "category": null,
            "url": "https://www.stratum.cenvero.com/docs/configuration",
            "headings": [
                {
                    "level": 1,
                    "text": "Configuration"
                },
                {
                    "level": 2,
                    "text": "How configuration is delivered and layered"
                },
                {
                    "level": 3,
                    "text": "How the config is signed and verified"
                },
                {
                    "level": 2,
                    "text": "Launch flags"
                },
                {
                    "level": 2,
                    "text": "Identity and node fields"
                },
                {
                    "level": 2,
                    "text": "Paths"
                },
                {
                    "level": 2,
                    "text": "Ports"
                },
                {
                    "level": 2,
                    "text": "API"
                },
                {
                    "level": 2,
                    "text": "TLS"
                },
                {
                    "level": 2,
                    "text": "Cluster"
                },
                {
                    "level": 2,
                    "text": "Gateway and HA"
                },
                {
                    "level": 2,
                    "text": "Overlay (VXLAN) and load balancer"
                },
                {
                    "level": 2,
                    "text": "Intrusion detection (IDS)"
                },
                {
                    "level": 2,
                    "text": "DNS"
                },
                {
                    "level": 2,
                    "text": "DHCP"
                },
                {
                    "level": 2,
                    "text": "Metrics"
                },
                {
                    "level": 2,
                    "text": "Network services (on/off switches)"
                },
                {
                    "level": 2,
                    "text": "Operator local overrides"
                },
                {
                    "level": 3,
                    "text": "Settable keys (the local whitelist)"
                },
                {
                    "level": 3,
                    "text": "Keys that cannot be set locally"
                },
                {
                    "level": 2,
                    "text": "What is *not* in this file"
                },
                {
                    "level": 2,
                    "text": "Ports summary"
                },
                {
                    "level": 2,
                    "text": "A note on time"
                },
                {
                    "level": 2,
                    "text": "Next steps"
                }
            ],
            "word_count": 2853,
            "markdown": "# Configuration\n\nThe agent starts from sensible **built-in defaults** and, on top of those, loads\nan optional node configuration file. If the file is absent the defaults are used,\nso a freshly-installed node runs without any config at all. Point the agent at a\nspecific file with `--config <path>`.\n\n```bash\n# Run with the default config (if one is present)\ncenvero-stratum\n\n# Or an explicit path\ncenvero-stratum --config /etc/cenvero-str/config.cenvero-stratum\n```\n\nThis page is the **full reference** for every configuration field: what it is,\nits type, default, accepted values, and which command controls it. Use it\nalongside the [CLI Reference](/docs/cli).\n\n## How configuration is delivered and layered\n\nThere are three layers, applied in order — **each later layer wins**:\n\n1. **Built-in defaults.** Compiled into the agent (the table values marked\n   *default* below). A node with no config file at all runs entirely on these.\n2. **The node config file** (`config.cenvero-stratum`). A **signed** configuration\n   file the provisioning tooling and the panel produce — it is not hand-edited.\n   The panel delivers this file already signed; the agent verifies it on load (see\n   below). Distributing one signed file rolls identical settings across a fleet.\n3. **Operator local overrides** (`config.local.cenvero-stratum`). A small sidecar\n   you set on the node itself with `cenvero-str-ctl config set` / `service`. These\n   take precedence over the panel-delivered config **and survive a panel re-sync**\n   — see the *Operator local overrides* section below.\n\n> The provisioning installer writes the *initial* config file for you; you don't\n> author it by hand. Day-to-day local adjustments go through `config set` and\n> `service`, which write the override sidecar — never the main file.\n\n### How the config is signed and verified\n\nThe node config and the override sidecar are stored as signed configuration files\nthe agent loads directly — they are not hand-written text.\n\nFor production, the panel **cryptographically signs** the config it delivers, and\nthe agent **verifies that signature on load** so it refuses to boot from a forged\nor tampered file delivered over the network. The trust model is deliberately\nfail-closed where it matters and permissive where it can't hurt you:\n\n- **No file on disk** — the agent boots on built-in defaults (a fresh node still\n  comes up).\n- **A signed config** (the normal panel-delivered case) — the signature **must**\n  verify; a tampered or wrong-key file is **rejected**.\n- **An unsigned local bootstrap config** (what the installer writes on first\n  install) — accepted with a loud log warning, so a brand-new node can start,\n  register, and sync. A network attacker can't exploit this: substituting an\n  unsigned file only yields installer defaults, and the next panel-signed config\n  still must verify.\n\nYou inspect (never edit) the on-disk file with `cenvero-str-ctl config show`,\nwhich decodes and prints it; secret values are redacted unless you add\n`--include-secrets`.\n\n```bash\nsudo cenvero-str-ctl config show               # decoded, secrets redacted\nsudo cenvero-str-ctl config show --format json # machine-readable\n```\n\n## Launch flags\n\nA handful of settings can be overridden at process launch (these affect that one\nrun; persistent changes belong in the config or the override sidecar):\n\n| Flag | Type | Default | What it does |\n|------|------|---------|--------------|\n| `--config <path>` | path | (none) | Path to the node config file. If omitted, built-in defaults are used. |\n| `--bind <addr>` | IP | (from config) | Override the API bind address for this run. |\n| `--log-level <level>` | enum | `info` | Log verbosity: `debug`, `info`, `warn`, or `error`. |\n| `--allow-unsigned-config` | flag | `false` | **Dev only, insecure.** Load the config without verifying its signature. Never use in production. |\n\n## Identity and node fields\n\nThese describe the node itself. `node_id` and `license_server` are\n**panel/identity-owned**: set at install or by the panel-signed config (and, where\nnoted, refused by `config set` — see *Keys that cannot be set locally* below).\n`log_level` is the exception — it is operator-settable, per its row.\n\n| Key | Type | Default | Accepted values | What it does | Controlled by |\n|-----|------|---------|-----------------|--------------|---------------|\n| `node_id` | string | (empty) | UUID | Stable node identity; binds the license. Also the VXLAN VTEP source fallback when it parses as an IP. | Install / panel |\n| `license_server` | string (URL) | `https://license.cenvero.com` | Base URL | License/activation server. Empty falls back to the built-in default. | Install / panel |\n| `log_level` | enum | `info` | `debug`, `info`, `warn`, `error` | Agent log verbosity. | `config set log_level` |\n\n> **There is no node-mode setting any more.** Older versions carried a\n> `node_mode` field that chose between a Compute node and a Gateway node. Every\n> node now routes, the field is gone, and a node updating from an older version\n> has its configuration migrated automatically — see\n> [Nodes and Interfaces](/docs/nodes).\n\n## Paths\n\nFilesystem locations the agent uses. These follow the standard `cenvero-str`\nlayout and are set by the installer; they are not adjusted with `config set`.\n\n| Key | Type | Default | What it does |\n|-----|------|---------|--------------|\n| `data_dir` | path | `/var/lib/cenvero-str/` | Persistent state — the node's own records and supporting files. |\n| `config_dir` | path | `/etc/cenvero-str/` | Configuration directory (holds the config file and the override sidecar). |\n| `socket_path` | path | `/run/cenvero-str/cenvero-str.sock` | Unix socket `cenvero-str-ctl` uses to talk to the agent. |\n\n## Ports\n\nThe agent listens on a fixed set of ports. The defaults rarely need changing; when\nthey do, the five listen ports are settable via the local override sidecar. Open\nthese between cluster members on the **management network only**.\n\n| Key | Type | Default | Protocol | Purpose | Controlled by |\n|-----|------|---------|----------|---------|---------------|\n| `port_rest` | int (1-65535) | `7070` | HTTPS | REST management API. | `config set port_rest` |\n| `port_grpc` | int (1-65535) | `7071` | TCP | gRPC management API (node-to-node control). | `config set port_grpc` |\n| `port_websocket` | int (1-65535) | `7072` | WebSocket | Live events / streaming. | `config set port_websocket` |\n| `port_cluster` | int (1-65535) | `7073` | TCP | Cluster state replication. | `config set port_cluster` |\n| `port_ha_heartbeat` | int (1-65535) | `7074` | UDP | Gateway HA heartbeat. | `config set port_ha_heartbeat` |\n\n## API\n\nThe local management API (REST / gRPC / WebSocket). The bind address, rate limits,\nand allow-lists are settable locally; the **bearer token is a credential** and is\nrefused by `config set` (rotate it at install or via the panel).\n\n| Key | Type | Default | Accepted values | What it does | Controlled by |\n|-----|------|---------|-----------------|--------------|---------------|\n| `api_bind_address` | IP | `0.0.0.0` | Any IP (use `0.0.0.0` / `::` for all interfaces) | IP the REST/gRPC/WebSocket APIs listen on. A host:port or hostname is rejected — this is an IP only. | `config set api_bind_address` |\n| `api_rate_limit` | int (≥ 0) | `1000` | `0` disables the limiter | Requests per minute per key. | `config set api_rate_limit` |\n| `api_rate_burst` | int (≥ 0) | `100` | `0` or higher | Burst allowance above the per-minute rate. | `config set api_rate_burst` |\n| `api_allowed_ips` | list of IP/CIDR | (empty) | Comma-separated IPs/CIDRs; empty = allow all | IPs/CIDRs allowed to reach the API. | `config set api_allowed_ips` |\n| `api_allowed_origins` | list of string | (empty) | Comma-separated origins; empty = same-host only | Allowed WebSocket `Origin` values. | `config set api_allowed_origins` |\n| `api_token` | string (secret) | (empty) | Bearer token | Token required for protected REST/gRPC/WS endpoints. Empty means the local management API is **disabled**. | Install / panel (refused by `config set`) |\n\n> Set the API token at install time with\n> `cenvero-str-ctl config encode --generate-api-token` (mints a fresh random token\n> and enables the API). It is a credential, not an operational setting.\n\n## TLS\n\nTLS material for the management API. Paths are managed by the certificate manager\n(`cenvero-str-ctl tls ...`) — they are **not** set with `config set`.\n\n| Key | Type | Default | What it does | Controlled by |\n|-----|------|---------|--------------|---------------|\n| `tls_auto_generate` | bool | `true` | Auto-generate a self-signed certificate on first start. | Install / cert manager |\n| `tls_cert_path` | path | `/etc/cenvero-str/tls/server.crt` | TLS certificate. | Cert manager (refused by `config set`) |\n| `tls_key_path` | path | `/etc/cenvero-str/tls/server.key` | TLS private key. | Cert manager (refused by `config set`) |\n| `tls_pubkey_path` | path | `/etc/cenvero-str/tls/server.pub` | TLS public key file. | Cert manager (refused by `config set`) |\n| `grpc_client_ca_dir` | path | (empty) | When set, contains `ca.pem` used to require + verify gRPC client certificates (mTLS). | Provisioned (refused by `config set`) |\n\n## Cluster\n\nClustering identity and transport security. These are panel-orchestrated /\nprovisioned and are **not** set with `config set`. Cluster TLS material is\nmandatory — clustering refuses to start without it (no plain-TCP downgrade).\n\n| Key | Type | Default | What it does | Controlled by |\n|-----|------|---------|--------------|---------------|\n| `cluster_enabled` | bool | `false` | Whether this node participates in a cluster. | Panel |\n| `cluster_bind_addr` | string | (empty) | Address the cluster transport binds. | Panel (refused by `config set`) |\n| `cluster_bootstrap` | bool | `false` | Whether this node bootstraps a new cluster. | Panel |\n| `cluster_cert_dir` | path | (empty) | Directory holding `cert.pem`, `key.pem`, and `ca.pem` for cluster mTLS. | Provisioned (refused by `config set`) |\n\n## Gateway and HA\n\nThese name the two interfaces the node's forwarding path is placed on, and\nconfigure the HA pairing. Naming the interfaces is what puts NAT and routing on\nthem — there is no separate switch to turn the gateway path on. Leave them empty\nand the node still hosts workloads and serves its networks; it simply forwards\nnothing across an edge. The **HA shared key is a cluster secret** and is refused\nby `config set` (it must match the peer).\n\n| Key | Type | Default | What it does | Controlled by |\n|-----|------|---------|--------------|---------------|\n| `gateway_wan_interface` | string | (empty) | The outward-facing interface the forwarding path (NAT + routing) uses. | Install / panel |\n| `gateway_lan_interface` | string | (empty) | The inward-facing interface the forwarding path uses. | Install / panel |\n| `wan_dhcp` | bool | `false` | Run the built-in DHCP client on the WAN interface to obtain the uplink address. When false, the WAN address is static/config. | Install / panel |\n| `gateway_vip` | string (IP) | (empty) | Virtual IP the HA pair owns; the ACTIVE node assumes it and announces it via gratuitous ARP, releasing it on losing ACTIVE. Empty registers no VIP. | Install / panel |\n| `gateway_peer_addr` | string | (empty) | HA peer address (`host` or `host:port`; the HA heartbeat port is appended when absent). Empty disables HA peering (solo gateway). | Install / panel |\n| `gateway_priority` | int | `0` | Biases which node becomes ACTIVE; higher wins. `0` leaves the manager default. | Install / panel |\n| `gateway_shared_key` | string (secret) | (empty) | Shared key authenticating the HA heartbeat; **must match the peer**. | Install / panel (refused by `config set`) |\n\n## Overlay (VXLAN) and load balancer\n\n| Key | Type | Default | What it does | Controlled by |\n|-----|------|---------|--------------|---------------|\n| `vtep_local_ip` | string (IP) | (empty) | Underlay source IP for VXLAN tunnels. Empty falls back to `node_id` **only if** it parses as an IP (a hostname `node_id` is rejected with a warning). | Install / panel |\n| `lb_interface` | string | (empty) | VIP-facing interface the L4 load balancer uses. Empty leaves the load balancer unattached. Must be a **dedicated** interface — not one already used by the bridge or gateway data plane. | Install / panel |\n\n## Intrusion detection (IDS)\n\nOpt-in per-source scan/flood detection on an interface's ingress.\n\n| Key | Type | Default | What it does | Controlled by |\n|-----|------|---------|--------------|---------------|\n| `ids_interface` | string | (empty) | Interface whose ingress the IDS collector watches. Empty leaves IDS disabled. May be an interface already used by the data plane — typically the uplink/WAN or `cnv-user-br0`. | Install / panel |\n| `ids_auto_block` | bool | `false` | `false` = **alert only** (a detection raises an event but does not touch traffic). `true` adds a confirmed scanner/flooder's IPv4 source to the firewall blocklist with an auto-expiring TTL. Opt-in because a false positive would cut off a legitimate source. | Install / panel |\n\n## DNS\n\nThe built-in resolver. The listen address and client ACL are settable locally;\nDNSSEC is panel-managed.\n\n| Key | Type | Default | Accepted values | What it does | Controlled by |\n|-----|------|---------|-----------------|--------------|---------------|\n| `dns_listen_addr` | string | (empty) | IP, or `host:port`, or empty | Address the DNS server binds. Empty binds the management bridge address only (not the WAN), so the resolver isn't exposed by default. | `config set dns_listen_addr` |\n| `dns_allowed_clients` | list of IP/CIDR | (empty) | Comma-separated IPs/CIDRs; empty = local/private ranges | Clients permitted to query the resolver. Empty falls back to local/private ranges — never an open resolver. | `config set dns_allowed_clients` |\n| `dnssec_enabled` | bool | `false` | `true`/`false` | Authoritative DNSSEC signing (per-zone keys, RRSIG/DNSKEY served when the client sets the DO bit). Default off = unsigned answers (back-compat). | Install / panel |\n\n## DHCP\n\nThe built-in DHCP server. Per-network scopes are panel-managed (set as\noperational resources, not in the static config); the **DHCP service itself** is\ntoggled with `service dhcp`.\n\n| Key | Type | Default | What it does | Controlled by |\n|-----|------|---------|--------------|---------------|\n| `dhcp_scopes` | list | (empty = single default pool) | Per-network DHCP scopes: each binds a client subnet to its own IPAM pool and reply parameters (gateway / mask / DNS / lease length). Matched by `giaddr` (relayed) or the receiving interface (directly attached). | Panel / API |\n\n## Metrics\n\n| Key | Type | Default | What it does | Controlled by |\n|-----|------|---------|--------------|---------------|\n| `metrics_bind_addr` | string (host:port) | `127.0.0.1:9090` | Address the Prometheus `/metrics` endpoint binds. Defaults to loopback so it isn't exposed on `0.0.0.0`; point it at a management address to scrape it off-box. The host must be an IP, not a hostname. | `config set metrics_bind_addr` |\n\n## Network services (on/off switches)\n\nEach network service can be turned on or off. These are stored **inverted** as\n`*_disabled` keys, so the default — every service running — is preserved for any\nolder config. The friendly front door is `cenvero-str-ctl service <name> on|off`;\nthe raw equivalent is `config set <name>_disabled true|false`, and the two\nround-trip with `config show`. All default to **enabled**.\n\n| Service name | `config` key | Default | What it gates |\n|--------------|--------------|---------|---------------|\n| `rest` | `rest_disabled` | enabled | The REST management API (also serves the operator/billing API). |\n| `grpc` | `grpc_disabled` | enabled | The gRPC management API. |\n| `websocket` | `websocket_disabled` | enabled | The WebSocket management API. |\n| `metrics` | `metrics_disabled` | enabled | The Prometheus `/metrics` endpoint. |\n| `dns` | `dns_disabled` | enabled | The built-in DNS server bind (on top of the listen-address gate). |\n| `dhcp` | `dhcp_disabled` | enabled | The built-in DHCP protocol server bind (the lease table still runs). |\n\n```bash\n# Toggle a service (writes the override sidecar; applies on restart)\nsudo cenvero-str-ctl service dns off\nsudo cenvero-str-ctl service status      # ENABLED / ADDRESS / live STATE per service\n\n# Equivalent raw form\nsudo cenvero-str-ctl config set dns_disabled true\n```\n\n> The **IPC control socket is not a toggleable service** — it is how\n> `cenvero-str-ctl` talks to the agent, so it can never be disabled. Disabling the\n> REST API is allowed but warns first, because it also carries the operator/billing\n> API.\n\n## Operator local overrides\n\n`config set` and `service` never touch the main `config.cenvero-stratum` file.\nThey write a separate **operator local-overrides sidecar**\n(`config.local.cenvero-stratum`, mode `0600`) in the config directory. The agent\noverlays this on top of its config at boot, so:\n\n- A locally-set field **takes effect on the next agent restart**, and\n- it **survives a configuration re-sync from the panel** (which rebuilds the main\n  config from defaults but never touches the sidecar). Local always wins.\n\n```bash\n# The general form is: config set <key> <value>\nsudo cenvero-str-ctl config set api_rate_limit 2000\n\n# Legacy shortcut flags for the three most common API keys\nsudo cenvero-str-ctl config set --api-bind 10.0.0.5 --api-rate-limit 2000 --api-rate-burst 200\n\n# Run with no value to list every settable key\nsudo cenvero-str-ctl config set\n\n# Apply the change\nsudo systemctl restart cenvero-stratum\n```\n\n### Settable keys (the local whitelist)\n\nOnly these safe operational keys can be set locally. Everything else is refused.\n\n`log_level`, `api_bind_address`, `api_rate_limit`, `api_rate_burst`,\n`api_allowed_ips`, `api_allowed_origins`, `api_read_timeout_secs`,\n`api_write_timeout_secs`, `api_idle_timeout_secs`, `port_rest`, `port_grpc`,\n`port_websocket`, `port_cluster`, `port_ha_heartbeat`, `metrics_bind_addr`,\n`dns_listen_addr`, `dns_allowed_clients`, `dns_upstreams`,\n`heal_interval_seconds`, `heal_disabled_checks`, and the six service switches\n(`rest_disabled`, `grpc_disabled`, `websocket_disabled`, `metrics_disabled`,\n`dns_disabled`, `dhcp_disabled`).\n\n### Keys that cannot be set locally\n\nIdentity, the license server, credentials, and signing / cluster-secret / TLS\nmaterial are **refused** by `config set` with an explanation — they are panel- or\nidentity-owned and must never come from a local edit:\n\n| Refused key | Why |\n|-------------|-----|\n| `node_id` | Panel-assigned identity; binds the license. |\n| `license_server` | Panel-controlled (set at install / by the signed config). |\n| `api_token` | A credential — rotate it at install/panel, not via `config set`. |\n| `gateway_shared_key` | A cluster secret that must match the HA peer. |\n| `cluster_bind_addr` | Clustering identity/secret is panel-orchestrated. |\n| `cluster_cert_dir` | Cluster mTLS material is provisioned. |\n| `grpc_client_ca_dir` | gRPC client-mTLS CA material is provisioned. |\n| `tls_cert_path` | TLS material is managed by the cert manager. |\n| `tls_key_path` | TLS material is managed by the cert manager. |\n| `tls_pubkey_path` | TLS material is managed by the cert manager. |\n\n## What is *not* in this file\n\nOperational resources — **networks, endpoints, IP pools, firewall rules, load\nbalancers, DNS/DHCP zones** — are **not** part of the node config. They are\nmanaged at runtime through the agent's API and `cenvero-str-ctl` (and replicated\nacross a cluster), not baked into the static node config. Use the relevant\n[CLI](/docs/cli) command group for each.\n\n## Ports summary\n\nOpen these between cluster members on the management network only:\n\n| Port | Protocol | Purpose |\n|------|----------|---------|\n| 7070 | HTTPS | Management API |\n| 7071 | TCP | Node-to-node control |\n| 7072 | WebSocket | Live events / streaming |\n| 7073 | TCP | Cluster state replication |\n| 7074 | UDP | Gateway HA |\n\n## A note on time\n\nStratum works in UTC everywhere and cross-checks the host clock against NTP.\nLarge time drift is treated as a tamper signal for licensing, so keep `chronyd`\nor `systemd-timesyncd` running on every node.\n\n## Next steps\n\n- **[CLI Reference](/docs/cli)** — the full command surface.\n- **[Clustering Overview](/docs/clustering/overview)** — joining nodes into a cluster.\n- **[Licensing](/docs/licensing)** — how enforcement interacts with the agent.\n"
        }
    ]
}