Running Every Operating Mode
One binary, eight modes, selected with FERRUM_MODE. This guide gives you a working
command for each mode, what it's for, and the variables it requires.
| Mode | FERRUM_MODE | Description | Admin API | Proxies Traffic |
|---|---|---|---|---|
| Database | database | Single instance, DB-backed (PostgreSQL/MySQL/SQLite/MongoDB) | Read/Write | Yes |
| File | file | Single instance, YAML/JSON config, SIGHUP reload | Read-only | Yes |
| Control Plane | cp | Centralized config authority, gRPC distribution to DPs | Read/Write | No |
| Data Plane | dp | Horizontally scalable traffic processors | Read-only | Yes |
| Mesh | mesh | Service-mesh data plane with six topologies | Read-only | Yes |
| Injector | injector | Kubernetes webhook injecting mesh sidecars | No | No |
| Node Agent | node_agent | Per-node eBPF capture manager for ambient mesh | Optional (read-only) | No |
| Migrate | migrate | Runs DB migrations or config upgrades, then exits | No | No |
0 to disable it.
File Mode — the Quickest Start
A YAML or JSON file defines everything. No database, no admin writes — great for development and GitOps.
# Using the CLI (recommended) — --spec auto-infers file mode
ferrum-edge run --spec config.yaml -v
# Or with environment variables
FERRUM_MODE=file \
FERRUM_FILE_CONFIG_PATH=config.yaml \
FERRUM_LOG_LEVEL=info \
ferrum-edge run
# Zero-config: if ./ferrum.conf and ./resources.yaml exist, just:
ferrum-edge run
# Hot-reload after editing the config (Unix)
ferrum-edge reload # sends SIGHUP
proxies:
- id: "my-api"
listen_path: "/api/v1"
backend_scheme: http
backend_host: "backend-service"
backend_port: 3000
strip_listen_path: true
plugins:
- plugin_config_id: "log-plugin"
consumers:
- id: "user-1"
username: "alice"
credentials:
keyauth:
- key: "alice-api-key"
acl_groups:
- "engineering"
plugin_configs:
- id: "log-plugin"
plugin_name: "stdout_logging"
config: {}
scope: global
enabled: true
Database Mode — Dynamic Configuration
Config lives in a database and is fully manageable at runtime through the Admin API. Pick the backend that fits your operations.
FERRUM_MODE=database \
FERRUM_DB_TYPE=sqlite \
FERRUM_DB_URL="sqlite://ferrum.db?mode=rwc" \
FERRUM_ADMIN_JWT_SECRET="change-me-dev-admin-secret-min-32-chars" \
FERRUM_ADMIN_BIND_ADDRESS=127.0.0.1 \
FERRUM_LOG_LEVEL=info \
ferrum-edge run
FERRUM_MODE=database \
FERRUM_DB_TYPE=postgres \
FERRUM_DB_URL="postgres://user:pass@localhost/ferrum" \
FERRUM_ADMIN_JWT_SECRET="change-me-dev-admin-secret-min-32-chars" \
FERRUM_ADMIN_BIND_ADDRESS=127.0.0.1 \
ferrum-edge run
FERRUM_MODE=database \
FERRUM_DB_TYPE=mongodb \
FERRUM_DB_URL="mongodb://user:pass@localhost:27017/ferrum?authSource=admin" \
FERRUM_MONGO_DATABASE=ferrum \
FERRUM_ADMIN_JWT_SECRET="change-me-dev-admin-secret-min-32-chars" \
FERRUM_ADMIN_BIND_ADDRESS=127.0.0.1 \
ferrum-edge run
FERRUM_ADMIN_ALLOWED_CIDRS. For remote admin access, serve TLS
(FERRUM_ADMIN_TLS_CERT_PATH/FERRUM_ADMIN_TLS_KEY_PATH) and disable plaintext with
FERRUM_ADMIN_HTTP_PORT=0.
Control Plane + Data Plane — Distributed Scale
One CP owns the config; any number of DPs serve traffic. The CP→DP gRPC channel is TLS-first and secure by default — plaintext is only permitted on loopback.
FERRUM_MODE=cp \
FERRUM_DB_TYPE=sqlite \
FERRUM_DB_URL="sqlite://ferrum.db?mode=rwc" \
FERRUM_ADMIN_JWT_SECRET="change-me-dev-admin-secret-min-32-chars" \
FERRUM_CP_GRPC_LISTEN_ADDR="127.0.0.1:50051" \
FERRUM_CP_DP_GRPC_JWT_SECRET="change-me-dev-cp-dp-secret-min-32-chars" \
ferrum-edge run
FERRUM_MODE=dp \
FERRUM_DP_CP_GRPC_URLS="http://localhost:50051" \
FERRUM_CP_DP_GRPC_JWT_SECRET="change-me-dev-cp-dp-secret-min-32-chars" \
ferrum-edge run
FERRUM_MODE=dp \
FERRUM_DP_CP_GRPC_URLS="https://cp1:50051,https://cp2:50051,https://cp3:50051" \
FERRUM_DP_GRPC_TLS_CA_CERT_PATH="/certs/ca.pem" \
FERRUM_CP_DP_GRPC_JWT_SECRET="your-production-cp-dp-secret-min-32-chars" \
ferrum-edge run
DPs list CPs in priority order and fail over automatically, preferring the primary when it recovers. For production mTLS between CP and DP, see the CP/DP deployment docs.
Mesh Mode — Service Mesh Data Plane
Runs as a sidecar, ambient/waypoint proxy, east-west gateway, or egress gateway. Config arrives from a Ferrum CP (native MeshSubscribe), any standard xDS control plane, or a local file.
FERRUM_MODE=mesh \
FERRUM_MESH_TOPOLOGY=sidecar \
FERRUM_DP_CP_GRPC_URLS="https://ferrum-cp:50051" \
FERRUM_DP_GRPC_TLS_CA_CERT_PATH="/certs/ca.pem" \
FERRUM_CP_DP_GRPC_JWT_SECRET="your-mesh-secret-min-32-chars" \
ferrum-edge run
FERRUM_MODE=mesh \
FERRUM_MESH_CONFIG_PROTOCOL=file \
FERRUM_MESH_FILE_CONFIG_PATH=/etc/ferrum/mesh.yaml \
ferrum-edge run
# Edit mesh.yaml, then hot-apply with SIGHUP
On Kubernetes you typically don't run mesh mode by hand — the Injector adds it to your pods. Topologies, SPIFFE identity, HBONE, and authorization policy are covered in the mesh documentation and on the architecture page.
Injector, Node Agent & Migrate
Injector
Kubernetes admission webhook. Deployed via the Helm chart / manifests; pods opt in with an annotation and receive Ferrum mesh sidecars and init capture containers (iptables or eBPF), with SPIFFE IDs derived from their service accounts.
Node Agent
Runs as a DaemonSet for the ambient mesh. Programs per-node eBPF socket-cookie and original-destination maps and enrolls pod identities — no proxy listeners. See the node agent docs.
Migrate
Runs a one-shot action and exits — perfect for CI/CD steps and Kubernetes Jobs ahead of a rollout.
# Apply pending database schema migrations, then exit
FERRUM_MODE=migrate \
FERRUM_MIGRATE_ACTION=up \
FERRUM_DB_TYPE=postgres \
FERRUM_DB_URL="postgres://user:pass@localhost/ferrum" \
ferrum-edge run
# Report pending migrations without applying
FERRUM_MODE=migrate FERRUM_MIGRATE_ACTION=status \
FERRUM_DB_TYPE=postgres FERRUM_DB_URL="postgres://user:pass@localhost/ferrum" \
ferrum-edge run
# Rewrite a YAML/JSON config file to the current schema (no DB involved)
FERRUM_MODE=migrate FERRUM_MIGRATE_ACTION=config \
FERRUM_FILE_CONFIG_PATH=./resources.yaml \
ferrum-edge run
CLI Commands You'll Use Daily
ferrum-edge run # start (smart defaults: ./ferrum.conf + ./resources.yaml)
ferrum-edge run --spec config.yaml # start in file mode with a specific config
ferrum-edge validate --spec config.yaml # check a config without starting
ferrum-edge reload # SIGHUP a running file/mesh-file gateway
ferrum-edge health # query the health endpoint
ferrum-edge version # print version info
Configuration precedence: CLI flag > environment variable > ferrum.conf > smart defaults.
Full details on the CLI reference page.