Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

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