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