
A security-first reverse proxy built to guard the free web.
A reverse proxy on Cloudflare Pingora with explicit limits, predictable failure modes and security logic in crash-isolated agents, for operators who want to sleep.
Website · Docs · Playground · All repositories
Zentinel is a reverse proxy built on Cloudflare Pingora. It ships bounded resources, deterministic timeouts and an explicit fail-open or fail-closed choice per route, and keeps parsing-heavy or risky security logic (WAF, auth, policy) out of the dataplane in external agents, so a buggy agent cannot take the proxy down with it.
In the benchmarks on zentinelproxy.io Zentinel had the lowest p99 of five proxies (Zentinel, Envoy, HAProxy, Nginx, Caddy) at 10,000 req/s, and a 1-hour, 1,000,000-request soak test finished with a 99.95% success rate and no memory leak detected.
The core (proxy, routing, TLS, caching, load balancing) is production-ready. Agents are versioned separately; each one's status is on its registry page.
curl -fsSL https://get.zentinelproxy.io | sh
Save this as zentinel.kdl. It proxies localhost:8080 to a backend on port 8081:
system {
worker-threads 0 // auto-detect CPU cores
}
listeners {
listener "http" {
address "0.0.0.0:8080"
protocol "http"
}
}
routes {
route "default" {
matches {
path-prefix "/"
}
upstream "backend"
}
}
upstreams {
upstream "backend" {
target "127.0.0.1:8081"
}
}
zentinel test -c zentinel.kdl # validate the config and exit
zentinel -c zentinel.kdl # run
The system block is required. More examples in config/examples/
(API gateway, load balancing, WebSocket, caching, inference routing, ACME,
namespaces and more), or build a config interactively with the
config builder.
# Install script (binary only)
curl -fsSL https://get.zentinelproxy.io | sh
# Install and start as a systemd service (Linux, root or sudo)
curl -fsSL https://get.zentinelproxy.io | sh -s -- --enable-service
# From crates.io (the crate is zentinel-proxy, the binary is zentinel).
# --locked builds with the tested dependency versions; without it a fresh
# resolve can pick tokio 1.54, which the current Pingora fork cannot run on (#624).
cargo install --locked zentinel-proxy
# Docker
docker run -p 8080:8080 -v $(pwd)/zentinel.kdl:/etc/zentinel/zentinel.kdl \
ghcr.io/zentinelproxy/zentinel -c /etc/zentinel/zentinel.kdl
On systemd hosts the install script also writes /etc/systemd/system/zentinel.service,
a sysusers snippet and a starter config at /etc/zentinel/zentinel.kdl.
Enabling and starting the service is opt-in (--enable-service). See
crates/proxy/docs/deployment.md.
Configuration is KDL. zentinel test -c <file> parses and validates it and
rejects unknown keys, so a typo fails loudly instead of being ignored.
Proxying to an HTTPS backend? Add a tls block to the upstream. Without it,
Zentinel connects with plaintext HTTP regardless of the port.
upstreams {
upstream "backend" {
target "api.example.com:443"
tls {
sni "api.example.com"
}
}
}
Full reference: docs.zentinelproxy.io.
| Feature | What it does |
|---|---|
| Service types | web, api, static, builtin and inference (LLM/AI) routes |
| Load balancing | 14 algorithms, including round-robin, weighted, least connections, consistent hash, Maglev, Peak EWMA and least-tokens-queued |
| Security | TLS and mTLS, per-SNI certificates, ACME, rate limiting, GeoIP filtering, decompression (zip bomb) limits |
| Agentic protocols | MCP and A2A awareness: per-method and per-tool allow/deny, resolved from the JSON-RPC body |
| Agents | External processors for WAF, auth and custom logic over agent protocol v2 (UDS or gRPC), crash-isolated, any language |
| HTTP caching | Pingora-based response caching with stampede prevention and memory, disk or hybrid backends |
| WebSocket | RFC 6455 proxying with per-frame agent inspection |
| Observability | Prometheus metrics and structured logging; OpenTelemetry tracing when built with --features opentelemetry (the released binaries are built without it) |
| Hot reload | SIGHUP reloads routes, upstreams and agents after validation, with an atomic swap; listener changes need a restart |
Full breakdown: zentinelproxy.io/features.
gpt-4*, claude-*), and prompt-injection and PII filtering through agents.Example configs for each: config/examples/.
Zentinel understands MCP (Model Context Protocol) and A2A (Agent2Agent). A route declares which methods and tools are permitted, and the proxy enforces that by reading the JSON-RPC envelope:
route "mcp" {
matches { path-prefix "/mcp" }
upstream "mcp-server"
mcp {
tools {
allow "get_weather" "search_docs"
deny "execute_sql"
}
}
}