Skip to content

Conduit

Oleksandr edited this page Jun 12, 2026 · 1 revision

Conduit

CI crates.io crates.io downloads npm version npm downloads License

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

# 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 --features when 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: "{{ jwt.sub }}"        # 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.


License

Apache 2.0 © 2024–2026 Oleksandr Lopatnov

Clone this wiki locally