HTTP Gateway
The HTTP gateway exposes a webhook endpoint for external services to send messages into Zeph. It provides bearer token authentication, per-IP rate limiting, body size limits, and a health check endpoint.
Activation
GatewayServer starts automatically when the gateway feature is enabled and [gateway] is present in the config. No manual startup code is required.
# Daemon mode — starts agent + gateway server
cargo run --features gateway,a2a -- --daemon
# Custom config
cargo run --features gateway,a2a -- --daemon --config path/to/config.toml
The server is wired via src/gateway_spawn.rs into both daemon.rs and runner.rs. Incoming webhook payloads are logged; full agent loopback forwarding is planned as a follow-up.
Feature Flag
Enable with --features gateway at build time:
cargo build --release --features gateway
Configuration
Add the [gateway] section to config/default.toml:
[gateway]
enabled = true
bind = "127.0.0.1"
port = 8090
auth_token = "secret" # required; set from vault via ZEPH_GATEWAY_TOKEN
rate_limit = 120 # max requests/minute per IP (0 = unlimited)
max_body_size = 1048576 # 1 MB
Set bind = "0.0.0.0" to accept connections from all interfaces. The gateway logs a warning when binding to 0.0.0.0 to prevent accidental exposure.
Authentication
auth_token is required. The gateway fails to start if auth_token is missing or blank, protecting against unauthenticated webhook injection.
All requests to /webhook must include a bearer token:
Authorization: Bearer <token>
Token comparison uses constant-time hashing (blake3 + subtle) to prevent timing attacks. The /health endpoint is always unauthenticated.
To set the token:
Option 1: Store in age vault (recommended):
zeph vault set ZEPH_GATEWAY_TOKEN "your-secret-token"
Option 2: Environment variable (dev only):
export ZEPH_GATEWAY_TOKEN="your-secret-token"
zeph --daemon
Option 3: Direct config (not recommended):
[gateway]
auth_token = "your-secret-token" # prefer vault
The --init wizard now explicitly prompts for the gateway token and instructs you to store it in the vault.
Endpoints
GET /health
Returns the gateway status and uptime. No authentication required.
{
"status": "ok",
"uptime_secs": 3600
}
POST /webhook
Accepts a JSON payload and forwards it to the agent loop.
{
"channel": "discord",
"sender": "user1",
"body": "hello from webhook"
}
On success, returns 200 with {"status": "accepted"}. Returns 401 if the token is missing or invalid, 429 if rate-limited, and 413 if the body exceeds max_body_size.
Rate Limiting
The gateway tracks requests per source IP with a 60-second sliding window. When a client exceeds the configured rate_limit, subsequent requests receive 429 Too Many Requests until the window resets. The rate limiter evicts stale entries when the tracking map exceeds 10,000 IPs.
Metrics Endpoint
When [metrics] enabled = true (requires the prometheus feature), the gateway also mounts a /metrics route (path configurable via [metrics] path) that returns OpenMetrics 1.0.0 text for Prometheus scraping. This applies to the CLI/TUI-driven gateway (src/runner.rs) only — zeph --daemon (src/daemon.rs) does not currently wire a metrics registry into its gateway, so /metrics (and require_auth) has no effect in daemon mode.
By default ([metrics] require_auth = false), /metrics is unauthenticated and unthrottled — the same posture as /health. This matches the common deployment where the gateway’s port is only reachable from a trusted scrape network (a private VPC, a sidecar, or behind a reverse proxy that itself enforces access control). If the gateway is reachable from an untrusted network, set:
[metrics]
require_auth = true
to require the same Authorization: Bearer <token> header as /webhook. This also gives /metrics its own independent per-IP rate-limit counter, with the same limit and the same middleware ordering as /webhook (rate limit outside auth, so a failed-auth request still counts toward the limit). Without this, /metrics would give the bearer token an unthrottled brute-force surface even though /webhook throttles it.
Architecture
The gateway is built on axum with tower-http middleware:
- Auth middleware – validates bearer tokens on protected routes
- Rate limit middleware – per-IP counters with automatic eviction
- Body limit layer –
tower_http::limit::RequestBodyLimitLayer - Graceful shutdown – listens on the global
watch::Receiver<bool>shutdown signal