Guides / Running Modes

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.

ModeFERRUM_MODEDescriptionAdmin APIProxies Traffic
DatabasedatabaseSingle instance, DB-backed (PostgreSQL/MySQL/SQLite/MongoDB)Read/WriteYes
FilefileSingle instance, YAML/JSON config, SIGHUP reloadRead-onlyYes
Control PlanecpCentralized config authority, gRPC distribution to DPsRead/WriteNo
Data PlanedpHorizontally scalable traffic processorsRead-onlyYes
MeshmeshService-mesh data plane with six topologiesRead-onlyYes
InjectorinjectorKubernetes webhook injecting mesh sidecarsNoNo
Node Agentnode_agentPer-node eBPF capture manager for ambient meshOptional (read-only)No
MigratemigrateRuns DB migrations or config upgrades, then exitsNoNo
ℹ️
Default ports: 8000 (HTTP proxy), 8443 (HTTPS proxy), 9000 (Admin HTTP, loopback by default), 9443 (Admin HTTPS), 50051 (CP→DP gRPC). All configurable; set a plaintext port to 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.

bash
# 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
yaml — minimal config.yaml
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.

bash — SQLite (simplest)
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
bash — PostgreSQL
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
bash — MongoDB
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
⚠️
Admin API security: admin listeners bind to loopback by default, and writable modes refuse to start with a public plaintext admin listener unless you set 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.

bash — Control Plane (local development)
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
bash — Data Plane (single CP, loopback)
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
bash — Data Plane (multi-CP failover over TLS, production shape)
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.

bash — sidecar consuming native MeshSubscribe
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
bash — control-plane-free mesh from a local file
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.

bash — migrate mode actions
# 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

bash
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.