Conduit
Production-grade reverse proxy and API gateway built on Cloudflare Pingora.
A single binary, single config file that handles proxying, static files, auth, rate limiting, caching, scripting, and TLS — with a 14 MB footprint, ~28 ms cold start, and zero runtime dependencies.
npx @lopatnov/conduit init # generate config interactively
npx @lopatnov/conduit # start
Table of Contents
- Quick Start
- What Conduit does
- Installation
- Building from Source ↗
- CLI Commands
- Configuration
- Recipes
- Admin API
- Docker
- Editor Integration
- Benchmarks ↗
- Contributing
- License
Quick Start
# 1. Generate a config
conduit init # interactive wizard
conduit init --yes # non-interactive, accept defaults → conduit.yaml
# 2. Validate before starting
conduit validate
# 3. Start
conduit
# Listening on http://0.0.0.0:8080
Minimal hand-written config — YAML and JSON are equivalent:
# conduit.yaml
port: 8080
static: ./dist
proxy:
/api: http://localhost:4000
GET / → ./dist/index.html
GET /logo.png → ./dist/logo.png
GET /api/users → http://localhost:4000/api/users
Verify it’s running:
curl http://localhost:8080/__health__
# {"status":"ok"}
curl http://localhost:8080/api/users
# proxied to http://localhost:4000/api/users
→ Full examples: examples/ · → Configuration reference: docs/configuration.md
What Conduit does
| Proxying | Reverse proxy with 8 load-balancing strategies, health checks, outlier detection, circuit breaker, sticky sessions, failover |
| Static files | ETag, Range, pre-compressed .br/.gz, Cache-Control, SPA fallback |
| TLS | Manual certificates, auto-TLS via Let's Encrypt (ACME), mTLS client certificates, HTTP/2 |
| Auth | Basic Auth, API key, JWT (HS256/RS256/ES256 + JWKS), Forward Auth, Consumer model |
| Rate limiting | Token-bucket per IP or header, burst capacity, Redis for multi-instance, per-route limits |
| Caching | In-memory, Redis, disk — stale-while-revalidate, stale-if-error, thundering-herd lock |
| Reliability | Retry with budget + jitter, per-try timeout, body buffering for replay, priority load-shedding, traffic mirroring |
| Routing | Path glob, method, header regex, cookie, query params — ordered route table |
| Middleware | Rhai scripting, WebAssembly plugins (Wasmtime), request/response header transforms, CORS, compression, fault injection |
| Observability | Prometheus metrics (11 metrics), OpenTelemetry OTLP tracing, structured JSON access log, X-Request-ID |
| Operations | Hot config reload (zero dropped connections), Admin API, IP deny-list, TCP proxy mode, file upload |
| Deployment | Single binary, Docker FROM scratch, Kubernetes CRD, systemd, YAML/JSON config, env var secrets |
When to choose Conduit
Conduit is a good fit when you want everything in one tool — routing, auth, rate limiting, caching, and scripting — without separate sidecars, plugins, or configuration DSLs. One binary, one config file, one process to operate.
| Capability | Conduit |
|---|---|
| Config format | Plain YAML or JSON — readable, diff-friendly, version-controlled |
| JWT validation | Built-in (HS256 / RS256 / ES256 + JWKS rotation) |
| Rate limiting | Built-in — per IP, per header, per route, Redis for multi-instance |
| Scripting middleware | Rhai (embedded, sandboxed) + WebAssembly (Wasmtime, any language) |
| Binary size | 14 MB standard · 29 MB full (all 14 optional features) |
| Memory (idle) | ~8 MB |
| Hot reload | Zero dropped connections |
| Auto-TLS | ACME / Let’s Encrypt built-in |
| WASM plugins | ✅ — bring your own logic, any compile-to-WASM language |
Installation
Standard vs full: the standard binary covers the vast majority of use cases. Add
--featureswhen you need JWT auth, scripting (Rhai/WASM), OTLP tracing, auto-TLS (ACME), Redis, TCP proxy, file upload, or Kubernetes CRD mode. See the full features table.
npx — no installation needed
npx @lopatnov/conduit init # generate config
npx @lopatnov/conduit # start server
npx @lopatnov/conduit validate # validate config
Downloads and caches the platform binary on first run. Always standard build.
npm global
npm install -g @lopatnov/conduit
conduit validate
conduit
Pre-built binaries
Download from GitHub Releases:
| Platform | Standard | Full (all 14 features) |
|---|---|---|
| Linux x86-64 | conduit-x86_64-unknown-linux-gnu.tar.gz |
conduit-x86_64-unknown-linux-gnu-full.tar.gz |
| Linux x86-64 musl | conduit-x86_64-unknown-linux-musl.tar.gz |
conduit-x86_64-unknown-linux-musl-full.tar.gz |
| Linux ARM64 | conduit-aarch64-unknown-linux-gnu.tar.gz |
conduit-aarch64-unknown-linux-gnu-full.tar.gz |
| Linux RISC-V 64 | conduit-riscv64gc-unknown-linux-gnu.tar.gz |
— |
| macOS Intel | conduit-x86_64-apple-darwin.tar.gz |
conduit-x86_64-apple-darwin-full.tar.gz |
| macOS Apple Silicon | conduit-aarch64-apple-darwin.tar.gz |
conduit-aarch64-apple-darwin-full.tar.gz |
| Windows x86-64 | conduit-x86_64-pc-windows-msvc.exe.zip |
conduit-x86_64-pc-windows-msvc-full.exe.zip |
# Linux x86-64 — standard
curl -L https://github.com/lopatnov/conduit/releases/latest/download/conduit-x86_64-unknown-linux-gnu.tar.gz \
| tar xz && ./conduit --version
# Linux x86-64 — full
curl -L https://github.com/lopatnov/conduit/releases/latest/download/conduit-x86_64-unknown-linux-gnu-full.tar.gz \
| tar xz && ./conduit --version
cargo install
cargo install lopatnov-conduit # standard
cargo install lopatnov-conduit --features full # all features
Optional features
| Feature | What it enables |
|---|---|
jwt |
JWT Bearer-token auth + JWKS URL (jwtAuth) |
consumers |
Named API clients with per-consumer credentials and rate limits |
forward-auth |
Delegate auth to an external HTTP service (forwardAuth) |
rhai |
Rhai scripting middleware (type: "script") |
wasm |
WebAssembly plugin middleware (type: "wasm") via Wasmtime |
tcp |
Raw TCP proxy mode (type: "tcp" site) |
upload |
Multipart file upload handler (upload: site config) |
redis |
Redis-backed rate limiting and caching |
cache |
Response caching (proxy.*.cache) |
disk-cache |
Disk-backed cache store (cache.store: "disk:/path") |
acme |
Auto-TLS via Let’s Encrypt (tls.acme) |
fault-injection |
Fault injection for chaos testing |
otlp |
OpenTelemetry OTLP distributed tracing (global.otlp) |
kubernetes |
Kubernetes CRD config provider (--kubernetes-namespace) |
full |
All of the above |
For build instructions, cross-compilation, and troubleshooting see docs/building.md.
CLI Commands
conduit [-c FILE] start server (default config: conduit.yaml/json)
conduit validate [-c FILE] validate config — exit 0 = ok, exit 1 = errors
conduit fmt [-c FILE] [--write] pretty-print / normalise config in place
conduit init [--yes] [-o FILE] interactive setup wizard (--yes = non-interactive)
conduit probe [-c FILE] ping all configured upstreams, show latency
conduit reload [--admin ADDR] hot-reload config (zero dropped connections)
conduit status [--admin ADDR] version, uptime, in-flight requests
conduit status [--admin ADDR] --upstream upstream health table (latency, ejected, 5xx)
conduit shutdown [--admin ADDR] graceful shutdown
conduit upstreams [--admin ADDR] list upstream health + latency
conduit upstreams add --route PATH --target URL [--weight N]
conduit upstreams remove --route PATH --target URL
conduit upstreams weight --route PATH --target URL --weight N
conduit completions bash|zsh|fish|power-shell|elvish shell completion script
conduit man generate man page (roff)
Full flag reference and exit codes: docs/cli.md
Configuration
Config is a single YAML or JSON file. Conduit reads conduit.yaml (or conduit.json)
by default; pass -c path/to/file to use another.
All string values support environment variable substitution: "$VAR" is replaced at
startup. Never hard-code secrets — use env vars or a secrets manager.
# conduit.yaml — annotated overview of common fields
port: 443
host: example.com # virtual host (omit for catch-all)
tls:
acme: # auto-TLS via Let's Encrypt (--features acme)
email: admin@example.com
http2: true
compression: true
securityHeaders: true
proxy:
/api:
targets:
- http://api-1:4000
- http://api-2:4000
strategy: least-conn
healthCheck: { path: /health }
retry: { attempts: 2, conditions: [5xx, connection_error] }
cache: { store: memory, ttlSecs: 60 }
rateLimit:
windowSecs: 60
limit: 300
jwtAuth: # --features jwt
jwksUrl: https://auth.example.com/.well-known/jwks.json
audience: [my-api]
logging: json
metrics: { path: /__metrics__ }
healthCheck: true
→ All fields with examples: docs/configuration.md
→ Ready-to-run configs: examples/
Recipes
Local dev server
port: 3000
logging: dev
cors: true
hotReload: true
static: ./src
proxy:
/api: http://localhost:4000
fallback: { file: ./src/index.html, status: 200 }
JWT API gateway
port: 8080
jwtAuth: # --features jwt
jwksUrl: https://auth.example.com/.well-known/jwks.json
requestTransform:
setHeaders:
X-User-ID: "" # inject claim into upstream request
proxy:
/users: http://users-svc:4001
/orders: http://orders-svc:4002
rateLimit: { windowSecs: 60, limit: 500 }
maskErrors: true
metrics: { path: /__metrics__ }
Multi-site (one process, multiple domains)
sites:
- host: app.example.com
port: 443
tls: { acme: { email: admin@example.com } }
static: ./dist
proxy: { /api: http://api:4000 }
- host: admin.example.com
port: 443
tls: { acme: { email: admin@example.com } }
basicAuth: { users: { admin: "$ADMIN_PASSWORD" } }
proxy: http://admin-backend:5000
→ 30+ more scenarios: docs/recipes.md — HTTPS, load balancing, failover, circuit breaker, caching, security hardening, observability, Kubernetes.
Admin API
Optional local management server. Runs on loopback only — never exposed publicly.
global:
admin:
bind: "127.0.0.1:2019"
token: "$ADMIN_TOKEN" # optional Bearer token
conduit reload # hot-reload config
conduit status # uptime, version, in-flight count
conduit status --upstream # upstream health table
conduit upstreams add --route /api --target http://new-backend:4000
# Admin API directly
curl http://localhost:2019/status
curl -X POST http://localhost:2019/reload
curl -X DELETE "http://localhost:2019/cache/purge?url=https://example.com/api/data"
curl -X POST http://localhost:2019/ip-deny -d '{"cidr":"1.2.3.0/24"}'
→ All endpoints with request/response examples: docs/admin.md
Docker
# Standard (~14 MB musl, FROM scratch)
docker pull ghcr.io/lopatnov/conduit:latest
# Full — JWT, Rhai, WASM, OTLP, ACME, Redis, TCP proxy, Kubernetes, etc. (~29 MB)
docker pull ghcr.io/lopatnov/conduit:latest-full
docker run -p 8080:8080 \
-v $(pwd)/conduit.yaml:/etc/conduit/conduit.yaml:ro \
ghcr.io/lopatnov/conduit:latest -c /etc/conduit/conduit.yaml
Both images run as nobody (UID 65534), no shell, no OS userland.
→ docker-compose, systemd, Kubernetes, production checklist: docs/deployment.md
Editor Integration (JSON Schema)
Conduit ships a JSON Schema for autocompletion, hover docs, and inline validation in both JSON and YAML configs.
VS Code — JSON: add one line to your config:
{
"$schema": "https://raw.githubusercontent.com/lopatnov/conduit/main/schema/conduit.schema.json",
"port": 3000
}
VS Code — JSON: workspace-wide (all conduit*.json files):
// .vscode/settings.json
{
"json.schemas": [{
"fileMatch": ["conduit.json", "conduit.*.json"],
"url": "https://raw.githubusercontent.com/lopatnov/conduit/main/schema/conduit.schema.json"
}]
}
VS Code — YAML: add to .vscode/settings.json (requires the
YAML extension):
// .vscode/settings.json
{
"yaml.schemas": {
"https://raw.githubusercontent.com/lopatnov/conduit/main/schema/conduit.schema.json":
["conduit.yaml", "conduit.yml", "conduit.*.yaml"]
}
}
IntelliJ / WebStorm: Settings → Languages & Frameworks → Schemas and DTDs → JSON Schema Mappings
→ add URL https://raw.githubusercontent.com/lopatnov/conduit/main/schema/conduit.schema.json,
file pattern conduit*.json, conduit*.yaml.
Contributing
Contributions are welcome. Read CONTRIBUTING.md before opening a PR.
- Bug reports → GitHub Issues
- Security vulnerabilities → GitHub Security Advisories (not public issues)
- Questions & ideas → GitHub Discussions
- Found it useful? — a ⭐ helps others discover the project
License
Apache 2.0 © 2024–2026 Oleksandr Lopatnov