neuron-explorer
Qwen3.5‑4B 전용 조향형 뉴런 탐색기, 모든 MLP 뉴런을 밀어 결과를 보관·탐색
Ferrum Edge - API Gateway / AI Gateway / Mesh
저장소 README에서 가져옴
README 전체를 불러오는 중입니다. 아래는 저장된 발췌입니다.
A high-performance edge proxy built in Rust
Active build-out: Breaking changes are expected. Core database changes
are folded into the initial schema; recreate development databases when it
changes. See the build-out policy.
Ferrum Edge is a lightweight, extensible edge proxy designed for modern microservice architectures. It provides dynamic routing, multi-protocol support, a robust plugin system, and multiple deployment topologies — from single-node file-based setups to distributed Control Plane / Data Plane architectures.README 전문 보기 ↗Active build-out: Breaking changes are expected. Core database changes are folded into the initial schema; recreate development databases when it changes. See the build-out policy.
Ferrum Edge is a lightweight, extensible edge proxy designed for modern microservice architectures. It provides dynamic routing, multi-protocol support, a robust plugin system, and multiple deployment topologies — from single-node file-based setups to distributed Control Plane / Data Plane architectures.
Key highlights:
ArcSwap or DashMap without a mutex; on a cache miss, request-driven connection creation may briefly coalesce on a creation lock so concurrent misses share one dial/metrics/runtime JSON snapshot with system/process state, HTTP status windows, error classes, DNS outcomes, backend pool churn, TCP resets, log counters, and overload stateferrum-gateway chart ships Prometheus alerts and Grafana dashboards, and every alert links a first-response procedure in docs/runbooks/gateway.mdFor the full feature list, see FEATURES.md.
| Mode | Env Var | Description | Admin API | Proxy |
|---|---|---|---|---|
| Database | FERRUM_MODE=database | Single-instance, DB-backed (PostgreSQL/MySQL/SQLite/MongoDB) | Read/Write | Yes |
| File | FERRUM_MODE=file | Single-instance, YAML/JSON config, SIGHUP reload | Read-only | Yes |
| Control Plane | FERRUM_MODE=cp | Centralized config authority, gRPC distribution to DPs | Read/Write | No |
| Data Plane | FERRUM_MODE=dp | Horizontally scalable traffic processing nodes | Read-only | Yes |
| Mesh | FERRUM_MODE=mesh | Service-mesh data plane consuming native MeshSubscribe, xDS ADS, or a localized config file with six topologies | Read-only | Yes |
| Injector | FERRUM_MODE=injector | Kubernetes admission webhook that injects Ferrum mesh sidecars/init capture | No | No |
| Node Agent | FERRUM_MODE=node_agent | Per-node eBPF capture manager for ambient mesh; no proxy listeners. See docs/node_agent.md | Optional (read-only) | No |
| Migrate | FERRUM_MODE=migrate | Runs DB schema migrations then exits (explicit CLI / external K8s Job; not a Helm chart mode) | No | No |
See docs/cp_dp_mode.md for distributed deployment details. On Kubernetes, map each mode to its chart or external contract in docs/kubernetes_deployment.md.
channel = "stable" via rust-toolchain.toml; rustup will auto-install on first cargo invocation). CI runs clippy with -D warnings against the current stable, so local toolchains MUST be at parity.protobuf-compiler or set PROTOC to the executable path.cargo/config.toml; complete the
one-time bootstrap before building. The
bootstrap also installs sccache and enables it as your user-level rustc wrapper
(recommended, not required).rdkafka-sys to compile
librdkafka from source (kafka_logging vendored TLS). The bootstrap script
installs cmake plus libcurl4-openssl-dev (Debian/Ubuntu), libcurl-devel
(Fedora/RHEL), or Homebrew curl (macOS). A missing curl/curl.h still fails
the native build even with -DWITH_CURL=0.A full-debuginfo codegen-units=1 dev build can OOM rustc on a 15 GiB host
with no swap. If rustc is killed for memory, retry with CARGO_PROFILE_DEV_DEBUG=0
and more codegen units (for example CARGO_PROFILE_DEV_CODEGEN_UNITS=16). That is
host sizing, not a missing package; do not change [profile.dev] for it.
The bootstrap below requires Homebrew on macOS or apt- or dnf-based Linux. The fast-linker configuration covers x86_64 and ARM64 GNU/Linux and macOS. For other platforms, manual installation, or building without sccache and fast linkers, follow the platform limits and fallback instructions.
git clone https://github.com/ferrum-edge/ferrum-edge.git
cd ferrum-edge
./scripts/install-build-deps.sh
cargo build --release
# Install to PATH
sudo cp target/release/ferrum-edge /usr/local/bin/
ferrum-edge version
Download from GitHub Releases for Linux x86_64/ARM64 and macOS x86_64/ARM64. Releases ship raw platform binaries plus adjacent .sha256 checksum files (for example ferrum-edge-linux-x86_64 and ferrum-edge-linux-x86_64.sha256).
Pin an explicit release tag in download URLs. Binaries are published only for version tags; main does not publish a moving latest binary release. GitHub's /releases/latest endpoint skips prereleases. Use /releases/download/<tag>/… or gh release download <tag> instead. Pick the current immutable vX.Y.Z semver tag from the Releases page, and pin deployments to that version.
Feature availability by release: resource labels (labels / ResourceLabels on Proxy, Consumer, Upstream, and PluginConfig, #5483) require v0.9.5 or later; artifacts through v0.9.4 reject labels with unknown field `labels` . See the upgrade guidance for database and CP/DP rollout requirements. Companion clients that inject labels.provisioned-by require matching gateway builds: Git Forge Ops ≥ #218, Nexus ≥ #245, and Foundry ≥ #340.
# Example: Linux x86_64
set -euo pipefail
TAG='<published-tag>' # from GitHub Releases / container registry (not a chart default)
BASE="https://github.com/ferrum-edge/ferrum-edge/releases/download/${TAG}"
curl -fsSLO "${BASE}/ferrum-edge-linux-x86_64"
curl -fsSLO "${BASE}/ferrum-edge-linux-x86_64.sha256"
sha256sum -c ferrum-edge-linux-x86_64.sha256
chmod +x ferrum-edge-linux-x86_64
sudo install -m 0755 ferrum-edge-linux-x86_64 /usr/local/bin/ferrum-edge
ferrum-edge version
Published Linux GNU artifacts (ferrum-edge-linux-x86_64, ferrum-cni-linux-x86_64, and the ARM64 pair) are dynamically linked against glibc. The declared runtime floor is GLIBC_2.34 (RHEL 9 / Rocky Linux 9 / AlmaLinux 9, which also covers Ubuntu 22.04 and Debian 12). The x86_64 GNU binaries are built in a digest-pinned AlmaLinux 8.10 sysroot (glibc 2.28) by the same job that checksums and uploads them, and that job ABI-scans and smoke-tests the exact staged bytes before publishing them, so the released artifact is the artifact that was verified. ARM64 GNU artifacts come from the isolated Cross build, already target an older glibc, and are re-checked as published. Beyond glibc, the remaining dynamic libraries are libgcc_s.so.1 and, when the Kafka stack does not static-link zlib, libz.so.1. Any GNU artifact whose GLIBC version-need records exceed 2.34, whose DT_NEEDED set is outside that allowlist, whose e_machine does not match the advertised *-x86_64 / *-aarch64 architecture, or that embeds a DT_RPATH / DT_RUNPATH, fails the release.
Choose a completed published version, not a source tag or chart appVersion
that is still in release preparation. The container tag latest moves forward
to the newest main commit that passed CI and was built and signed (each built
commit also gets a main-<sha> tag; intermediate commits may be skipped): a
moving development channel for evaluation, not a release. Omitting a tag
also selects latest, so for production always specify a published version or
image digest.
Versioned releases publish vX.Y.Z, X.Y.Z, and the moving X.Y series alias
(for example, 0.9). Pin the full version or digest for reproducible deployments;
the series alias can change when another release in that series is published.
Images are published to Docker Hub (docker.io/ferrumedge/ferrum-edge, anonymously
pullable) and to GitHub Container Registry (ghcr.io/ferrum-edge/ferrum-edge). Use the
Docker Hub path unless you have confirmed the GHCR package is visible to you: a GHCR
package that is not public returns 401 Unauthorized to an anonymous docker pull.
# Replace with a version whose image has completed publication.
TAG='<published-tag>'
docker pull "docker.io/ferrumedge/ferrum-edge:${TAG}"
docker run -d --name ferrum-edge \
-p 8000:8000 \
-e FERRUM_MODE=database \
-e FERRUM_DB_TYPE=sqlite \
-e FERRUM_DB_URL="sqlite:////data/ferrum.db?mode=rwc" \
-e FERRUM_ADMIN_JWT_SECRET="please-change-me-to-a-32+character-secret" \
-e FERRUM_ADMIN_BIND_ADDRESS=127.0.0.1 \
-v ferrum_data:/data \
"docker.io/ferrumedge/ferrum-edge:${TAG}"
Admin API exposure. The admin API is a management plane. Both admin listeners (HTTP and HTTPS) bind to loopback (
127.0.0.1) by default, so the example does not publish port 9000 and admin is not reachable from the network. In the writabledatabase/cpmodes the gateway refuses to start if the plaintext admin listener is bound to a non-loopback address (0.0.0.0, a public IP, or a private/VPC interface IP) with noFERRUM_ADMIN_ALLOWED_CIDRSallowlist. To make admin reachable from outside the container you must setFERRUM_ADMIN_BIND_ADDRESS=0.0.0.0(or::) — loopback alone is not reachable through a published port. Then either: (a) serve it over TLS (FERRUM_ADMIN_TLS_CERT_PATH/FERRUM_ADMIN_TLS_KEY_PATH, publish9443, setFERRUM_ADMIN_HTTP_PORT=0to disable plaintext) and/or setFERRUM_ADMIN_ALLOWED_CIDRS; or (b) for throwaway local testing only, setFERRUM_ALLOW_INSECURE_ADMIN_HTTP=trueand publish127.0.0.1:9000:9000.
See docs/docker.md for Docker Compose examples and production deployment.
# Using the CLI (recommended)
ferrum-edge run --spec tests/config.yaml -v
# Using environment variables
FERRUM_MODE=file \
FERRUM_FILE_CONFIG_PATH=tests/config.yaml \
FERRUM_LOG_LEVEL=info \
cargo run --release -- run
With smart defaults, if ./ferrum.conf and ./resources.yaml exist in the current directory:
ferrum-edge run
See docs/cli.md for the full CLI reference.
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 \
cargo run --release -- 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 \
cargo run --release -- 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 \
cargo run --release -- run
The CP→DP gRPC channel carries Data Plane authentication JWTs and the full
gateway configuration, so it is TLS-first and secure-by-default: the CP
refuses to bind a plaintext gRPC listener on a non-loopback address, and the DP
refuses a non-loopback http:// CP URL, unless TLS is configured (or plaintext
is explicitly permitted — see below). The loopback quickstart below runs as-is;
any networked deployment must use TLS.
# Control Plane (loopback + plaintext — local development only; secrets must be 32+ chars)
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" \
cargo run --release -- run
# Data Plane (single CP, loopback — local development only; its read-only
# Admin API is on http://127.0.0.1:9001 so it does not collide with the CP's
# admin listener on 9000 on the same host)
FERRUM_MODE=dp \
FERRUM_DP_CP_GRPC_URLS="http://localhost:50051" \
FERRUM_ADMIN_JWT_SECRET="change-me-dev-admin-secret-min-32-chars" \
FERRUM_ADMIN_HTTP_PORT=9001 \
FERRUM_CP_DP_GRPC_JWT_SECRET="change-me-dev-cp-dp-secret-min-32-chars" \
cargo run --release -- run
# 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_ADMIN_JWT_SECRET="change-me-dev-admin-secret-min-32-chars" \
FERRUM_CP_DP_GRPC_JWT_SECRET="change-me-dev-cp-dp-secret-min-32-chars" \
cargo run --release -- run
For production CP/DP with TLS/mTLS, see docs/cp_dp_mode.md. To intentionally run plaintext config sync on a networked address (trusted network, with compensating controls), set FERRUM_CP_DP_GRPC_ALLOW_PLAINTEXT=true on both the CP and the DP. For multi-region high availability, see docs/multi_region_ha.md.
| Port | Protocol | Purpose |
|---|---|---|
8000 | HTTP | Proxy traffic |
8443 | HTTPS | Proxy traffic (TLS) |
9000 | HTTP | Admin API |
9443 | HTTPS | Admin API (TLS) |
50051 | gRPC | Control Plane → Data Plane sync |
All ports are configurable via environment variables (FERRUM_PROXY_HTTP_PORT, FERRUM_PROXY_HTTPS_PORT, FERRUM_ADMIN_HTTP_PORT, FERRUM_ADMIN_HTTPS_PORT, FERRUM_CP_GRPC_LISTEN_ADDR). Set any plaintext port to 0 to disable its listener entirely for TLS-only deployments.
Ferrum Edge is configured through environment variables, with an optional ferrum.conf file for defaults. Environment variables take precedence.
| Variable | Required | Default | Description |
|---|---|---|---|
FERRUM_MODE | Yes | — | database, file, cp, dp, mesh, injector, node_agent, migrate |
FERRUM_LOG_LEVEL | No | warn | error, warn, info, debug, trace |
FERRUM_LOG_BUFFER_CAPACITY | No | 4096 | Per-sink hard record limit; aggregate bytes are separately bounded by FERRUM_LOG_BUFFER_BYTES |
FERRUM_PROXY_HTTP_PORT | No | 8000 | HTTP proxy port (0 = disabled) |
FERRUM_PROXY_HTTPS_PORT | No | 8443 | HTTPS proxy port |
FERRUM_ACCEPT_THREADS | No | 0 (auto-detect) | Parallel accept loops on duplicated fds of one exclusive listen socket (0 = CPU cores; Unix only, non-Unix falls back to one loop) |
FERRUM_ADMIN_HTTP_PORT | No | 9000 | Admin API HTTP port (0 = disabled) |
FERRUM_ADMIN_JWT_SECRET | DB/CP | — | HS256 secret for Admin API (min 32 chars) |
FERRUM_DB_TYPE | DB/CP | — | postgres, mysql, sqlite, mongodb |
FERRUM_DB_URL | DB/CP | — | Database connection string |
FERRUM_FILE_CONFIG_PATH | File mode | — | Path to YAML/JSON config file |
For the full list of environment variables, see docs/configuration.md.
Operational note: all logging flows through bounded non-blocking writers (fixed record and byte admission → dedicated background threads → stdout/stderr), so log calls never block request-processing threads. Keep application logs on stdout/stderr by default. In containers, let the container runtime or platform collect and rotate the stream. On VMs, prefer running Ferrum Edge under systemd or another supervisor and let journald, rsyslog, logrotate, or a host log agent handle retention and rotation. Only add application-level file logging if you have a specific requirement for local log files. Under extreme throughput, size FERRUM_LOG_BUFFER_CAPACITY and FERRUM_LOG_BUFFER_BYTES together; increasing the record limit alone cannot increase admission when the byte budget is already full. New events are dropped and counted when either bound is reached so collector backpressure cannot stall the gateway.
version: "1"
proxies:
- id: "my-api"
listen_path: "/api/v1"
backend_scheme: http
backend_host: "backend-service"
backend_port: 3000
strip_listen_path: true
consumers:
- id: "user-1"
username: "alice"
credentials:
keyauth:
- key: "alice-api-key-0123456789"
acl_groups:
- "engineering"
plugin_configs:
- id: "log-plugin"
plugin_name: "stdout_logging"
config: {}
scope: global
enabled: true
See docs/configuration.md for stream proxy config, service discovery, and the ferrum.conf reference.
JWT-protected REST API for managing proxies, consumers, plugins, and upstreams at runtime.
The examples below use
http://localhost:9000, matching the local quick-start (admin bound to loopback, plaintext). In production, serve the admin API over HTTPS (FERRUM_ADMIN_TLS_CERT_PATH/FERRUM_ADMIN_TLS_KEY_PATH, thenhttps://host:9443) and disable plaintext withFERRUM_ADMIN_HTTP_PORT=0, or restrict callers withFERRUM_ADMIN_ALLOWED_CIDRS. Bearer tokens sent over plaintexthttp://traverse the network in the clear. Indatabase/cpmodes the gateway refuses to start a public plaintext admin listener without an allowlist (see docs/configuration.md).
# Liveness probe (no auth) — always {"status":"ok"}
curl http://localhost:9000/live
# Readiness/health (no auth returns status+ready; full diagnostics need auth)
curl http://localhost:9000/health
# List proxies
curl -H "Authorization: Bearer $TOKEN" http://localhost:9000/proxies
# Create a proxy
curl -X POST -H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"listen_path": "/api", "backend_scheme": "http", "backend_host": "backend", "backend_port": 3000}' \
http://localhost:9000/proxies
# Backup / Restore
curl -H "Authorization: Bearer $TOKEN" http://localhost:9000/backup > backup.json
curl -X POST -H "Authorization: Bearer $TOKEN" -d @backup.json "http://localhost:9000/restore?confirm=true"
Submit an OpenAPI/Swagger spec to atomically provision a proxy, upstream, and plugins in one call — see docs/api_specs.md.
See docs/admin_api.md for the full endpoint reference, including first-create minimal requests, and openapi.yaml for the OpenAPI specification.
Ferrum ships a large built-in plugin set for request preflight, authentication, authorization and backend admission, request/response transformation, AI/agent gateway policy, protocol bridging, stream/WebSocket/UDP handling, and observability. Plugins execute in a deterministic priority pipeline (lower priority runs first) and are protocol-aware, so the gateway skips plugins that do not apply to the current protocol.
The canonical plugin registry and ordering live outside the README to avoid drift: see docs/plugins.md for detailed configuration of each plugin, and docs/plugin_execution_order.md for the full execution order and protocol support matrix.
Plugins for AI and agent gateway use cases — transcript audit, cost visibility, budget enforcement, semantic policy, request policy, PII protection, output guardrails, prompt compression, streaming and non-streaming provider routing, MCP tool routing, and response caching:
ai_token_metrics — Extract token usage from LLM responses for observability only (streamed SSE / AWS event-stream responses are metered incrementally without buffering; optional per-model pricing)ai_request_guard — Enforce model whitelists, token limits, and request policyai_rate_limiter — Enforce token budgets with pre-request reservation and response reconciliation (HTTP-only; native gRPC is unsupported) (supports centralized Redis mode; compatible with any RESP-protocol server: Redis, Valkey, DragonflyDB, KeyDB, Garnet)ai_prompt_shield — Scan for PII and reject, redact, or warnai_prompt_compressor — Bounded model-free compression for admitted OpenAI Chat/Text Completions requests, plus opt-in OpenAI Responses and Anthropic Messages families, with aggregate token budgets, observe mode, and sampling (no external models or services); preserves matching-backtick code, URLs, Unicode numbers, common identifiers, and negations, with bounded fail-safe preserve_tag marker cleanupai_semantic_firewall — Semantic prompt/response firewall for prompt injection, jailbreaks, data exfiltration intent, tool abuse, and topic allow/deny policyai_semantic_cache — LLM response caching with normalized exact-match keys, optional embedding-based semantic similarity, and local or Redis exact-response storageai_response_guard — Output-side content guardrails: PII detection, blocked phrases, response format validation, and descriptor-based native gRPC response inspection for explicitly enrolled methodsai_tool_governor — Deterministic allow/deny/redact/approval policy for AI tool/function calls by name, arguments, JSON Schema, regex, risk, and identity; screens request tool definitions, buffered and streaming response tool calls (held until cleared, then released or cut), and optional MCP/A2A methods, with an optional approval webhookai_transcript_audit — Controlled AI payload capture for compliance: redacted request/response excerpts, keyed HMAC-SHA256 hashes of the exact observed body bytes (never unkeyed or canonicalized), model/provider, token/guardrail/tool/cache metadata, sampling, and async batched HTTP export; never blocks the hot path unless configured fail-closedai_stream_router — Streaming counterpart to ai_federation: claims "stream": true OpenAI Chat Completions, route-overrides to the matched provider, and normalizes provider-native SSE (e.g. Anthropic) to OpenAI SSE without bufferingAuto-detects OpenAI, Anthropic, Google Gemini, Cohere, Mistral, and AWS Bedrock response formats. See docs/plugins.md for configuration and a composition example.
rate_limiting and ai_rate_limiter support centralized mode via sync_mode: "redis" for coordinated limits across multiple gateway instances. When the centralized store cannot be consulted, redis_failure_policy decides: for rate_limiting the default local_fallback keeps enforcing the configured quota in each pod's memory, while explicit fail_closed refuses with 503; the other rate-limit plugins default to fail_closed. Redis Cluster is not supported and is screened at connect — see docs/plugins.md. ws_rate_limiting also supports sync_mode: "redis"; in its default per-connection mode this only serves to externalize per-connection frame counters under a per-plugin/gateway-instance Redis namespace — those budgets are not shared across instances or portable across reconnects/rebuilds. Its aggregate limit_by budgets (consumer, ip, service) are keyed by that identity and shared by every replica of the policy. Compatible with any RESP-protocol server (Redis, Valkey, DragonflyDB, KeyDB, Garnet). Redis TLS uses gateway-level FERRUM_TLS_CA_BUNDLE_PATH and FERRUM_TLS_NO_VERIFY settings.
Drop-in custom plugins via custom_plugins/ directory — auto-discovered at build time. Custom plugins can declare their own database migrations via plugin_migrations() for creating and managing private tables, tracked independently from core migrations. See CUSTOM_PLUGINS.md.
listen_path with unique path enforcement*.example.com)listen_path on HTTP proxies to match any path under the specified hosts~)allowed_methods per-proxy (405 on mismatch)strip_listen_path (default: true; no-op on host-only proxies), optional backend_path prefixSee docs/routing.md for detailed routing behavior.
| Protocol | Config | Notes |
|---|---|---|
| HTTP/1.1 | backend_scheme: http / https | Default, with connection pooling |
| HTTP/2 | ALPN-negotiated on https | Automatic via pool_enable_http2: true; startup capability classification decides when the direct H2 pool is used; body-size limits are enforced in-path on that pool |
| HTTP/3 | backend_scheme: https | Startup capability classification probes HTTPS backends for H3 support; ordinary (non-gRPC, non-WebSocket) requests to targets classified as H3-capable use QUIC automatically |
| WebSocket | Runtime-detected from Upgrade: websocket (H1.1) or :protocol=websocket Extended CONNECT (H2 RFC 8441, H3 RFC 9220) on any HTTP-family proxy | backend_scheme: http → ws:// upstream; https → wss://. Same plugin pipeline across all three frontends; H3 sessions controlled by FERRUM_HTTP3_WEBSOCKET_ENABLED (default on) |
| gRPC | Runtime-detected from content-type: application/grpc* on any HTTP-family proxy | HTTP/2 with trailer support on both http (h2c) and https (ALPN) schemes |
| TCP | backend_scheme: tcp / tcps | Dedicated-port stream proxy (plaintext or TLS) |
| UDP | backend_scheme: udp / dtls | Datagram proxy with session tracking (plaintext or DTLS) |
See docs/tcp_udp_proxy.md for TCP/UDP/DTLS proxy configuration.
dp mode, a data plane serves its last applied CP snapshot during outages, but when every control plane is unreachable and that snapshot ages past FERRUM_DP_CONFIG_MAX_STALE_SECONDS (default 3600), the pod becomes unready and, by default (FERRUM_DP_CONFIG_STALE_ACTION=fail_closed), refuses new traffic on every protocol while existing connections drain. Partial CP loss and successful failover do not trigger the fence. See docs/cp_dp_mode.mdFERRUM_DB_CONFIG_BACKUP_PATH for DB outage recovery in KubernetesFERRUM_DB_FAILOVER_URLS for database high availabilitySee docs/load_balancing.md, docs/retry.md, and docs/error_classification.md.
Lock-free connection reuse with per-proxy pool keys and HTTP/2 flow control tuning. Hybrid configuration with global defaults and per-proxy overrides. Startup pool warmup pre-establishes backend connections after DNS warmup to eliminate first-request cold-start latency.
See docs/connection_pooling.md for sizing guidance, pool warmup, and configuration.
Secure originating IP detection via trusted proxy configuration with X-Forwarded-For right-to-left walk. See docs/client_ip_resolution.md.
In-memory async DNS cache with startup warmup, stale-while-revalidate, per-proxy TTL overrides, and static overrides. See docs/dns_resolver.md.
Historical small-payload multi-protocol benchmark results from
tests/performance/multi_protocol/ (local macOS Apple Silicon run, 200
concurrent, 10s, 64-byte payload; run date not recorded in this summary):
| Protocol | Gateway RPS | Gw P50 | Gw P99 | Direct RPS | Direct P50 | Direct P99 | Overhead |
|---|---|---|---|---|---|---|---|
| HTTP/1.1 | 102,183 | 1.89ms | 3.85ms | 209,910 | 939μs | 1.81ms | ~51% |
| HTTP/1.1+TLS | 101,317 | 1.90ms | 3.84ms | 209,361 | 941μs | 1.81ms | ~52% |
| HTTP/2 | 108,138 | 1.67ms | 6.38ms | 355,544 | 486μs | 1.53ms | ~70% |
| HTTP/3 (QUIC) | 53,085 | 3.51ms | 5.87ms | 83,592 | 2.38ms | 2.80ms | ~37% |
| gRPC | 68,352 | 2.53ms | 12.02ms | 205,927 | 821μs | 3.15ms | ~67% |
| WebSocket | 103,830 | 1.88ms | 3.15ms | 207,507 | 952μs | 1.72ms | ~50% |
| TCP | 108,841 | 1.83ms | 2.59ms | 214,113 | 928μs | 1.65ms | ~49% |
| TCP+TLS | 107,340 | 1.84ms | 2.68ms | 207,103 | 949μs | 1.78ms | ~48% |
| UDP | 82,042 | 2.46ms | 2.93ms | 276,526 | 682μs | 1.27ms | ~70% |
| UDP+DTLS | 76,107 | 2.61ms | 3.69ms | 101,839 | 1.96ms | 2.47ms | ~25% |
Adaptive buffer sizing (enabled by default) dynamically tunes TCP/WebSocket tunnel copy buffers and UDP batch limits per proxy based on observed traffic patterns. Small-message proxies get smaller buffers (saves memory), bulk transfer proxies get larger buffers (reduces syscalls). See FERRUM_ADAPTIVE_BUFFER_* env vars for tuning.
Linux socket tuning: (TCP_FASTOPEN, IP_BIND_ADDRESS_NO_PORT), thread-local Date header caching, lazy timeout initialization, frequency-aware router cache eviction (Count-Min Sketch), RED-style adaptive load shedding, and a cacheability predictor for the response cache plugin. See FEATURES.md for details.
For current suite methodology and dated result tables, see
tests/performance/ and
tests/performance/multi_protocol/README.md.
File descriptor limit. On Unix, Ferrum Edge calls setrlimit(RLIMIT_NOFILE, rlim_cur=rlim_max) once at startup, raising the soft cap to whatever the hard cap allows. The call never asks for privileges the process does not already have, so a sandboxed/seccomp-restricted run is a silent no-op rather than a failure. The hard cap must be set externally — Ferrum Edge cannot raise it. Recommended floor for production: 65,536.
| Environment | How to raise the hard cap |
|---|---|
| systemd unit | LimitNOFILE=1048576 in the [Service] section |
| Docker / Podman | --ulimit nofile=1048576:1048576 |
| Kubernetes | Configure nofile on the node/container runtime (for example containerd/runc or the kubelet/systemd service); Pod securityContext does not expose ulimit/nofile. |
| Bare shell (dev) | ulimit -n 1048576 before launching the binary |
/etc/security/limits.conf | * hard nofile 1048576 (and matching soft line) |
When the effective soft cap after startup is below 65,536, Ferrum Edge emits one structured warn! line at startup (greppable as "soft FD limit") and continues. Below the floor, the gateway will still serve, but its 95% FD-critical threshold will trigger earlier under load.
Concurrency planning. Each inbound TCP/TLS connection consumes ~1 FD; HTTP/2 multiplexes many requests onto one. Linux splice(2) adds 2 pipe FDs per TCP relay. Plan for ~2–4× the target concurrent-connection count when sizing nofile.
Historical local comparison summary (macOS Apple Silicon, 100 concurrent, 30s; run date not recorded in this summary):
All gateways run in Docker containers for apples-to-apples comparison:
| Gateway | Key-Auth req/s | Key-Auth Latency | vs Ferrum |
|---|---|---|---|
| Ferrum Edge | 27,979 | 3.44 ms | — |
| Envoy 1.37 (Lua filter) | 26,787 | 3.64 ms | Ferrum 4% faster |
| Kong 3.14 | 25,009 | 3.91 ms | Ferrum 12% faster |
| Tyk v5.12 | 19,186 | 5.08 ms | Ferrum 46% faster |
Ferrum also won the E2E TLS /api/users test outright — 29,808 req/s, the highest throughput of any gateway in any scenario, beating Envoy by 13%. Ferrum's authentication adds effectively zero overhead — authenticated requests match unauthenticated throughput thanks to the pre-computed ConsumerIndex with Arc<Consumer> zero-copy credential resolution and lock-free ArcSwap reads. See comparison/README.md and comparison/run_comparison.sh for the reproducible Docker gateway comparison harness, which checks for port and Docker name conflicts and cleans up only resources it creates, and tests/performance/README.md for the benchmark provenance checklist.
| Issue | Solution |
|---|---|
Invalid FERRUM_MODE "" | Set FERRUM_MODE (or pass --mode). File mode is inferred only when a spec path is available; see docs/cli.md |
duplicate listen_path(s) found | Ensure all proxy listen_path values are unique |
Database connection failed | Verify FERRUM_DB_TYPE and FERRUM_DB_URL |
401 on Admin API | Check JWT is signed with FERRUM_ADMIN_JWT_SECRET |
404 on proxy request | Verify request path matches a configured listen_path |
502 Bad Gateway | Backend unreachable or returned an invalid response — check X-Gateway-Error header for details |
503 Service Unavailable | Gateway-side capacity refusal (overload, open circuit breaker, DestinationRule maxConnections) — check X-Gateway-Error |
504 Gateway Timeout | Backend did not answer in time: X-Gateway-Error: backend_timeout → raise backend_read_timeout_ms; connection_failure → the connect timed out (backend_connect_timeout_ms) |
429 Too Many Requests | Rate limit exceeded — check plugin config |
| DP not receiving config | Verify FERRUM_CP_DP_GRPC_JWT_SECRET matches on both CP and DP |
Start at the documentation index — every document under
docs/, grouped by audience.
| Topic | Link |
|---|---|
| Documentation index | docs/README.md |
| Production hardening checklist | docs/hardening.md |
| Threat model | docs/threat_model.md |
| Support, versioning & deprecation policy | docs/support_policy.md |
| Full configuration reference | docs/configuration.md |
| Plugin reference | docs/plugins.md |
| Transaction log schema customization | docs/log_schema.md |
| Admin API | docs/admin_api.md |
| Connection pooling | docs/connection_pooling.md |
| Load balancing | docs/load_balancing.md |
| CP/DP distributed mode | docs/cp_dp_mode.md |
Ferrum Edge owns five shared vocabularies — gateway errors, gateway headers,
provisioned-by, the plugin catalog, and the gateway diagnostic reference — and
publishes them in
ferrum-edge/ferrum-contracts.
Consumers (Nexus, Foundry, Anvil, Alloy, GitForgeOps) pin the
contracts-edge-<edge-version> tags from that repository rather than reading
Edge source. The current published Edge release is v0.9.19. Its matching
Contracts tag is
contracts-edge-0.9.19
at d96b0292a0f87647f7552f25e0e5ce1b4ae30f8b, published on
2026-10-27 for Edge release commit
510ce7121c3d9754110d330a30a3bd9b7a7b278e. No contracts-edge-0.9.18 tag
exists because Edge v0.9.18 was tagged but never published. Earlier contract
tags remain unchanged.
v0.9.19 carries the plugin production-launch hardening from tagged but
unpublished v0.9.18 and adds the ARM64 OOM
recovery. Consumers move their pins
to contracts-edge-0.9.19 when they adopt Edge v0.9.19. See the
upgrade guide.
v0.9.17 carries the changes from tagged but unpublished v0.9.16. It adds
the loop_detected gateway-error token, the
X-Ferrum-Hops request header, and rejection phases for hop admission and
cancelled uploads. Namespace-bounded admin tokens gain a tenant health tier
and cannot read fleet-wide routes or /metrics. Admin cached-fallback misses
return 503 CachedReadUnavailable, and plugin trust follows registered types.
Consumers move their pins to contracts-edge-0.9.17 when they adopt Edge
v0.9.17. See the
upgrade guide.
Changing any of the Edge source files below changes an Edge-owned contract and requires a matching ferrum-contracts PR that refreshes the vocabulary from the new release tag:
| Contract | Edge sources |
|---|---|
gateway-errors | src/retry.rs (ErrorClass, OBS_*, x_gateway_error_token_for_class, token_for_rejection_phase), docs/error_classification.md |
gateway-headers | src/proxy/headers.rs, docs/admin_api.md, openapi.yaml |
provisioned-by | src/admin/provisioning.rs, docs/admin_api.md |
plugin-catalog | src/plugins/mod.rs (BUILTIN_PLUGIN_REGISTRATIONS, REMOVED_PLUGIN_REGISTRATIONS), src/plugins/builtin_parity.rs, and the PluginConfigBase if/then blocks in openapi.yaml |
diagnostic-ref | src/diagnostic_ref.rs, openapi.yaml (DiagnosticRefLookup family of component schemas) |
On every push to main: format check, clippy, and unit, integration, and functional (E2E) tests. Pull requests run the validation selected by their diff — the full Rust checks in the selected Rust lane, and light CI for ordinary documentation-only changes. Performance regression suites run on a schedule rather than per PR. Version tags trigger multi-platform release builds with Docker images.
See docs/ci_cd.md for pipeline details.
git checkout -b feature/my-feature)cargo test, plus cargo test -- --ignored for functional tests)cargo clippy --all-targets -- -D warnings and cargo fmt --allDo not use --all-features: the crypto-ring and fips features are mutually
exclusive. See CONTRIBUTING.md for the full workflow.
Copyright (c) 2026 Ferrum Edge LLC
Licensed under the PolyForm Noncommercial License 1.0.0.
TL;DR: Permitted noncommercial use is defined by LICENSE (PolyForm Noncommercial 1.0.0). For-profit infrastructure use and evaluation with anticipated commercial application require a commercial license. See LICENSE and LICENSE-COMMERCIAL.md for the controlling terms and use-case table.
chat.completion.chunkai_federation — HTTP-only AI gateway routing final transformed Chat Completions JSON to supported providers with bounded responses, replay-safe fallback, strict endpoint policy, and provider-native tool/content normalization; the opt-in streaming block adds a non-buffering path that commits ONE provider pre-first-byte and relays OpenAI-contract provider SSE incrementally (fallback only before commit, never a spliced second provider), while ineligible providers and disabled streaming keep returning 501mcp_gateway — MCP / Agent Tool Gateway for HTTP JSON-RPC MCP traffic: transparent proxying, aggregate discovery, namespaced tool/resource/prompt routing, session mediation, tool argument validation, and mcp.* metadata for downstream Ferrum pluginsa2a_gateway — Transparent Agent-to-Agent gateway for HTTP/HTTPS JSON-RPC, HTTP+JSON/REST, and gRPC/grpcs traffic: method detection, lightweight method policy, HTTP Agent Card URL rewriting, streaming-safe pass-through, and a2a.* metadata| Kubernetes deployment |
| docs/kubernetes_deployment.md |
| SPIRE deployment for mesh identity | docs/spire_deployment.md |
| TCP/UDP/DTLS proxy | docs/tcp_udp_proxy.md |
| Frontend TLS/mTLS | docs/frontend_tls.md |
| Backend mTLS | docs/backend_mtls.md |
| Database TLS | docs/database_tls.md |
| DNS resolver | docs/dns_resolver.md |
| Routing | docs/routing.md |
| Request path canonicalization | docs/request_path_canonicalization.md |
| Retry logic | docs/retry.md |
| Response streaming | docs/response_body_streaming.md |
| Plugin execution order | docs/plugin_execution_order.md |
| Infrastructure sizing | docs/infrastructure_sizing.md |
| Docker deployment | docs/docker.md |
| CI/CD pipeline | docs/ci_cd.md |
| Database migrations | docs/migrations.md |
| Upgrade procedure (build-out) | docs/upgrade_guide.md |
| Custom plugins | CUSTOM_PLUGINS.md |
| Feature list | FEATURES.md |
| OpenAPI spec | openapi.yaml |
| Gateway API conformance | docs/gateway_api_conformance.md (canonical) — indexed from CONFORMANCE.md |
| Istio + xDS conformance matrix | CONFORMANCE.md (run cargo test --test conformance_tests to refresh target/conformance/coverage.md) |