Configuration
The agent starts from sensible built-in defaults and, on top of those, loads
an optional node configuration file. If the file is absent the defaults are used,
so a freshly-installed node runs without any config at all. Point the agent at a
specific file with --config <path>.
# Run with the default config (if one is present)
cenvero-stratum
# Or an explicit path
cenvero-stratum --config /etc/cenvero-str/config.cenvero-stratum
This page is the full reference for every configuration field: what it is, its type, default, accepted values, and which command controls it. Use it alongside the CLI Reference.
How configuration is delivered and layered
There are three layers, applied in order — each later layer wins:
- Built-in defaults. Compiled into the agent (the table values marked default below). A node with no config file at all runs entirely on these.
- The node config file (
config.cenvero-stratum). A signed configuration file the provisioning tooling and the panel produce — it is not hand-edited. The panel delivers this file already signed; the agent verifies it on load (see below). Distributing one signed file rolls identical settings across a fleet. - Operator local overrides (
config.local.cenvero-stratum). A small sidecar you set on the node itself withcenvero-str-ctl config set/service. These take precedence over the panel-delivered config and survive a panel re-sync — see the Operator local overrides section below.
The provisioning installer writes the initial config file for you; you don't author it by hand. Day-to-day local adjustments go throughconfig setandservice, which write the override sidecar — never the main file.
How the config is signed and verified
The node config and the override sidecar are stored as signed configuration files the agent loads directly — they are not hand-written text.
For production, the panel cryptographically signs the config it delivers, and the agent verifies that signature on load so it refuses to boot from a forged or tampered file delivered over the network. The trust model is deliberately fail-closed where it matters and permissive where it can't hurt you:
- No file on disk — the agent boots on built-in defaults (a fresh node still comes up).
- A signed config (the normal panel-delivered case) — the signature must verify; a tampered or wrong-key file is rejected.
- An unsigned local bootstrap config (what the installer writes on first install) — accepted with a loud log warning, so a brand-new node can start, register, and sync. A network attacker can't exploit this: substituting an unsigned file only yields installer defaults, and the next panel-signed config still must verify.
You inspect (never edit) the on-disk file with cenvero-str-ctl config show,
which decodes and prints it; secret values are redacted unless you add
--include-secrets.
sudo cenvero-str-ctl config show # decoded, secrets redacted
sudo cenvero-str-ctl config show --format json # machine-readable
Launch flags
A handful of settings can be overridden at process launch (these affect that one run; persistent changes belong in the config or the override sidecar):
| Flag | Type | Default | What it does |
|---|---|---|---|
--config <path> | path | (none) | Path to the node config file. If omitted, built-in defaults are used. |
--bind <addr> | IP | (from config) | Override the API bind address for this run. |
--log-level <level> | enum | info | Log verbosity: debug, info, warn, or error. |
--allow-unsigned-config | flag | false | Dev only, insecure. Load the config without verifying its signature. Never use in production. |
Identity and node fields
These describe the node itself. node_id and license_server are
panel/identity-owned: set at install or by the panel-signed config (and, where
noted, refused by config set — see Keys that cannot be set locally below).
log_level is the exception — it is operator-settable, per its row.
| Key | Type | Default | Accepted values | What it does | Controlled by |
|---|---|---|---|---|---|
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 |
license_server | string (URL) | https://license.cenvero.com | Base URL | License/activation server. Empty falls back to the built-in default. | Install / panel |
log_level | enum | info | debug, info, warn, error | Agent log verbosity. | config set log_level |
There is no node-mode setting any more. Older versions carried a
node_mode field that chose between a Compute node and a Gateway node. Every
node now routes, the field is gone, and a node updating from an older version
has its configuration migrated automatically — see
Nodes and Interfaces.
Paths
Filesystem locations the agent uses. These follow the standard cenvero-str
layout and are set by the installer; they are not adjusted with config set.
| Key | Type | Default | What it does |
|---|---|---|---|
data_dir | path | /var/lib/cenvero-str/ | Persistent state — the node's own records and supporting files. |
config_dir | path | /etc/cenvero-str/ | Configuration directory (holds the config file and the override sidecar). |
socket_path | path | /run/cenvero-str/cenvero-str.sock | Unix socket cenvero-str-ctl uses to talk to the agent. |
Ports
The agent listens on a fixed set of ports. The defaults rarely need changing; when
they do, the three management API ports can be moved with config set (restart
the agent to apply; service status shows the port in use). The cluster and HA
heartbeat ports cannot: the other nodes connect to them, so they are the same on
every node. Open them only on the management network, and only between the
nodes that use them. Nothing listens on the cluster port on a node that is not
in a cluster (see Clustering Overview), nor on the
heartbeat port without a high-availability pair.
| Key | Type | Default | Protocol | Purpose | Controlled by |
|---|---|---|---|---|---|
port_rest | int (1-65535) | 7070 | HTTPS | REST management API. | config set port_rest |
port_grpc | int (1-65535) | 7071 | TCP | gRPC health check (for load balancers and orchestration). | config set port_grpc |
port_websocket | int (1-65535) | 7072 | WebSocket | Live events / streaming. | config set port_websocket |
port_cluster | — | 7073 | TCP | Between the members of a cluster. | Fixed (refused by config set) |
port_ha_heartbeat | — | 7074 | UDP | HA heartbeat between the two nodes of an HA pair. | Fixed (refused by config set) |
If you move an API port, open the new one wherever you opened the default, and point your clients and health checks at it.
API
The local management API (REST / gRPC / WebSocket). The bind address, rate limits,
and allow-lists are settable locally; the bearer token is a credential and is
refused by config set — set it with cenvero-str-ctl api-token.
| Key | Type | Default | Accepted values | What it does | Controlled by |
|---|---|---|---|---|---|
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 |
api_rate_limit | int (≥ 0) | 1000 | 0 disables the limiter | Requests per minute from each source IP address. | config set api_rate_limit |
api_rate_burst | int (≥ 0) | 100 | 0 or higher | Burst allowance above the per-minute rate. | config set api_rate_burst |
api_allowed_ips | list of IP/CIDR | (empty) | Comma-separated IPs/CIDRs; empty = allow all | IPs/CIDRs allowed to reach the API. On a cluster member it also judges the original client of a request another member passes on. | config set api_allowed_ips |
api_allowed_origins | list of string | (empty) | Comma-separated origins; empty = same-host only | Allowed WebSocket Origin values. | config set api_allowed_origins |
api_token | string (secret) | (empty) | Bearer token | Token required for protected REST/gRPC/WS endpoints. Empty means the local management API is disabled. | cenvero-str-ctl api-token (refused by config set) |
Set the API token on a running node withcenvero-str-ctl api-token generate(mints a strong random token and prints it once) orprintf '%s' "$TOKEN" | cenvero-str-ctl api-token set(stores yours, read from stdin so it stays out of shell history);api-token statusandapi-token clearcheck and remove it. It is kept in the local-overrides sidecar, so a panel re-sync does not discard it, and takes effect at the next agent restart. The installer can also mint one withCENVERO_API_TOKEN=auto.
TLS
TLS material for the management API. Paths are managed by the certificate manager
(cenvero-str-ctl tls ...) — they are not set with config set.
| Key | Type | Default | What it does | Controlled by |
|---|---|---|---|---|
tls_auto_generate | bool | true | Auto-generate a self-signed certificate on first start. | Install / cert manager |
tls_cert_path | path | /etc/cenvero-str/tls/server.crt | TLS certificate. | Cert manager (refused by config set) |
tls_key_path | path | /etc/cenvero-str/tls/server.key | TLS private key. | Cert manager (refused by config set) |
tls_pubkey_path | path | /etc/cenvero-str/tls/server.pub | TLS public key file. | Cert manager (refused by config set) |
grpc_client_ca_dir | path | (empty) | When set, contains ca.pem used to require + verify gRPC client certificates. | Provisioned (refused by config set) |
Cluster
A cluster is not set up in this file. You form or join one on the node
itself — in its web console, or with cenvero-str-ctl cluster create and
cluster join --code (agent 1.0.0-rc.81 or later; see
Clustering Overview) — and the node keeps its
membership with its own state under /var/lib/cenvero-str/, so back that up as
you already do.
Earlier versions read clustering from the keys below. They are still listed in
config show, are not set with config set, and are always delivered off;
they have no effect on a node that forms or joins a cluster.
| Key | Type | Default | What it does | Controlled by |
|---|---|---|---|---|
cluster_enabled | bool | false | Always false in a delivered configuration. Whether a node is in a cluster does not depend on it. | Delivered configuration (refused by config set) |
cluster_bind_addr | string | (empty) | Unused. A member's cluster address is the one given to cluster create or cluster join with --bind. | Delivered configuration (refused by config set) |
cluster_bootstrap | bool | false | Unused. A cluster's first member is the node that runs cluster create. | Delivered configuration (refused by config set) |
cluster_cert_dir | path | (empty) | Unused. A member's identity is issued by its cluster. | Delivered configuration (refused by config set) |
Gateway and HA
These name the two interfaces the node's forwarding path is placed on, and
configure the HA pairing. Naming the interfaces is what puts NAT and routing on
them — there is no separate switch to turn the gateway path on. Leave them empty
and the node still hosts workloads and serves its networks; it simply forwards
nothing across an edge. The HA shared key is a secret shared by the pair and is refused
by config set (it must match the peer). The HA keys (gateway_vip,
gateway_peer_addr, gateway_priority, gateway_shared_key) cannot be set by
you yet — see Gateway High Availability.
| Key | Type | Default | What it does | Controlled by |
|---|---|---|---|---|
gateway_wan_interface | string | (empty) | The outward-facing interface the forwarding path (NAT + routing) uses. | Install / panel |
gateway_lan_interface | string | (empty) | The inward-facing interface the forwarding path uses. | Install / panel |
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 |
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. A VIP that cannot be installed at that moment is retried about every 2 seconds while the node stays ACTIVE. Empty registers no VIP. | Install / panel |
gateway_peer_addr | string | (empty) | HA peer address (host or host:port; the HA heartbeat port is appended when absent). Empty disables HA peering: the node runs on its own, is ACTIVE, and holds gateway_vip itself. | Install / panel |
gateway_priority | int | 0 | Biases which node becomes ACTIVE; higher wins. 0 leaves the manager default. | Install / panel |
gateway_shared_key | string (secret) | (empty) | Shared key authenticating the HA heartbeat; must match the peer. With a peer set but no usable key there is no heartbeat, and the node never takes gateway_vip on its own. | Install / panel (refused by config set) |
Overlay (VXLAN) and load balancer
| Key | Type | Default | What it does | Controlled by |
|---|---|---|---|---|
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 |
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 |
Intrusion detection (IDS)
Opt-in per-source scan/flood detection on an interface's ingress.
| Key | Type | Default | What it does | Controlled by |
|---|---|---|---|---|
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 |
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. In a cluster the block reaches every member and ends at the same moment on each, and a cluster member's address is never blocked (see Firewall). | Install / panel |
DNS
The built-in resolver. The listen address and client ACL are settable locally; DNSSEC is panel-managed.
| Key | Type | Default | Accepted values | What it does | Controlled by |
|---|---|---|---|---|---|
dns_listen_addr | string | (empty) | IP, IP:port / [IPv6]:port, or empty | Address the DNS server listens on (UDP). A bare IP means port 53. Empty uses port 53 on the management bridge's IPv4 address, else the workload bridge's, else loopback — never every interface. On a single-card server the management bridge holds the host's own address. | config set dns_listen_addr |
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 |
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 |
DHCP
The built-in DHCP server. Scopes can be set here, in the node configuration, or
added over the API (POST /api/v1/dhcp/scopes), where they last until the agent
restarts. The DHCP service itself is toggled with service dhcp.
| Key | Type | Default | What it does | Controlled by |
|---|---|---|---|---|
dhcp_scopes | list | (empty — no addresses are offered) | Per-network DHCP scopes: each binds a client subnet to its own address pool and reply parameters (server identity / gateway / mask / DNS / lease length). A request is matched to a scope by the node's address on the interface it arrived on, or by its relay address (giaddr); see DHCP & DNS. Applied at every agent start. | Node configuration |
Metrics
| Key | Type | Default | What it does | Controlled by |
|---|---|---|---|---|
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 |
Network services (on/off switches)
Each network service can be turned on or off. These are stored inverted as
*_disabled keys, so the default — every service running — is preserved for any
older config. The friendly front door is cenvero-str-ctl service <name> on|off;
the raw equivalent is config set <name>_disabled true|false, and the two
round-trip with config show. All default to enabled.
| Service name | config key | Default | What it gates |
|---|---|---|---|
rest | rest_disabled | enabled | The REST management API (also serves the operator/billing API). |
grpc | grpc_disabled | enabled | The gRPC management API. |
websocket | websocket_disabled | enabled | The WebSocket management API. |
metrics | metrics_disabled | enabled | The Prometheus /metrics endpoint. |
dns | dns_disabled | enabled | The built-in DNS server bind (on top of the listen-address gate). |
dhcp | dhcp_disabled | enabled | The built-in DHCP protocol server bind (the lease table still runs). |
# Toggle a service (writes the override sidecar; applies on restart)
sudo cenvero-str-ctl service dns off
sudo cenvero-str-ctl service status # ENABLED / ADDRESS / live STATE per service
# Equivalent raw form
sudo cenvero-str-ctl config set dns_disabled true
The IPC control socket is not a toggleable service — it is how
cenvero-str-ctl talks to the agent, so it can never be disabled. Disabling the
REST API is allowed but warns first, because it also carries the operator/billing
API.
Operator local overrides
config set and service never touch the main config.cenvero-stratum file.
They write a separate operator local-overrides sidecar
(config.local.cenvero-stratum, mode 0600) in the config directory. The agent
overlays this on top of its config at boot, so:
- A locally-set field takes effect on the next agent restart, and
- it survives a configuration re-sync from the panel (which rebuilds the main config from defaults but never touches the sidecar). Local always wins.
# The general form is: config set <key> <value>
sudo cenvero-str-ctl config set api_rate_limit 2000
# Legacy shortcut flags for the three most common API keys
sudo cenvero-str-ctl config set --api-bind 10.0.0.5 --api-rate-limit 2000 --api-rate-burst 200
# Run with no value to list every settable key
sudo cenvero-str-ctl config set
# Apply the change
sudo systemctl restart cenvero-stratum
Settable keys (the local whitelist)
Only these safe operational keys can be set locally. Everything else is refused.
log_level, api_bind_address, api_rate_limit, api_rate_burst,
api_allowed_ips, api_allowed_origins, api_read_timeout_secs,
api_write_timeout_secs, api_idle_timeout_secs, port_rest, port_grpc,
port_websocket, metrics_bind_addr,
dns_listen_addr, dns_allowed_clients, dns_upstreams,
heal_interval_seconds, heal_disabled_checks, interface_reconcile_mode,
interface_hard_block, allow_untranslated_private_egress, and the six service switches (rest_disabled,
grpc_disabled, websocket_disabled, metrics_disabled, dns_disabled,
dhcp_disabled).
| Key | What it does |
|---|---|
interface_reconcile_mode | What happens when a managed cnv- interface is changed outside Stratum: detect (the default) logs and alerts; enforce also puts the interface back. A managed interface that has disappeared is recreated in both modes. |
interface_hard_block | true makes the kernel refuse an outside attempt to delete a managed cnv- interface, where the running kernel is configured to allow it. Off by default; where it is not available the node falls back to detect-and-repair. The management bridge is never blocked. Needs a restart. |
allow_untranslated_private_egress | true lets traffic from a private network that no masquerade rule translates leave on the uplink with its private source address. Off by default: such traffic is dropped on the uplink (see Gateway NAT). Only for a provider that routes private ranges to an upstream NAT router. Needs a restart. |
Keys that cannot be set locally
Identity, the license server, credentials, TLS material and the cluster_* keys
are refused by config set with an explanation — they are panel- or
identity-owned and must never come from a local edit. A cluster key's refusal
says what to run instead, and adds that a cluster set up by hand with an earlier
version reads the setting from the node's configuration file, which
config set never changes:
| Refused key | Why |
|---|---|
node_id | Panel-assigned identity; binds the license. |
license_server | Panel-controlled (set at install / by the signed config). |
api_token | A credential — set it with cenvero-str-ctl api-token, not config set. |
gateway_shared_key | A secret shared with the HA peer; it must match on both nodes. |
cluster_enabled | A node is in a cluster once it forms or joins one (cluster create, or cluster join --code with a code from cluster join-code create on a member), and cluster leave takes it out. |
cluster_bootstrap | A cluster's first member is the node that runs cluster create; the others join it with cluster join --code. |
cluster_bind_addr | A member's cluster address is set when it forms or joins a cluster (--bind). |
cluster_cert_dir | A member's identity is issued by its cluster, never set by hand. |
grpc_client_ca_dir | The certificate authority for gRPC client certificates is provisioned. |
tls_cert_path | TLS material is managed by the cert manager. |
tls_key_path | TLS material is managed by the cert manager. |
tls_pubkey_path | TLS material is managed by the cert manager. |
port_cluster (older name port_raft) | Cluster members connect to each other on the fixed port 7073. A value set by an older version is ignored. |
port_ha_heartbeat | The two nodes of an HA pair send heartbeats to each other on the fixed port 7074. A value set by an older version is ignored. |
What is not in this file
Operational resources — **networks, endpoints, IP pools, firewall rules, load
balancers, DNS zones — are not** part of the node config. They are managed at
runtime through the agent's API and cenvero-str-ctl, and each belongs to the
node it was created on. Use the relevant CLI command group for each.
Ports summary
Open these on the management network only:
| Port | Protocol | Purpose |
|---|---|---|
| 7070 | HTTPS | Management API |
| 7071 | TCP | gRPC health check |
| 7072 | WebSocket | Live events / streaming |
| 7073 | TCP | Between cluster members |
| 7074 | UDP | HA heartbeat |
A note on time
Stratum works in UTC everywhere and cross-checks the host clock against NTP.
Large time drift is treated as a tamper signal for licensing, so keep chronyd
or systemd-timesyncd running on every node.
Next steps
- CLI Reference — the full command surface.
- Clustering Overview — forming a cluster and managing every node from any of them.
- Licensing — how enforcement interacts with the agent.