Conduit routes public HTTPS traffic to your localhost and gives you a full debugging environment to watch, replay, and diff every request in real time. Your data never leaves your infrastructure.
The key difference from ngrok: data stays in your cluster, your whole team shares the same live request stream, and you can go back in time to see exactly what changed between any two requests — field by field.
The VS Code extension works standalone — no CLI required to start forwarding traffic.
Time-travel debugging. The relay stores a ring buffer of up to 1,000 requests per slug. conduit diff <id1> <id2> gives you a field-level JSON diff between any two of them. Find the exact moment something broke without re-triggering it.
Request replay. Hit r in the TUI to re-fire any past request against your local server. No copying curl commands, no re-sending from Postman.
Team observation mode. Share your slug and token. Your whole team sees the same live traffic stream in their own TUI or VS Code panel simultaneously.
Full observation plane. A terminal UI built with Ink, a VS Code sidebar panel, and a persistent storage layer — not just a URL forwarder.
Self-hosted relay. Runs as a Kubernetes pod or Docker container on your infrastructure. OIDC and Azure AD (MSAL) auth layers available. No third-party servers in the data path.
macOS / Linux
curl -fsSL https://get.conduitrelay.com/conduit | bashWindows (PowerShell)
irm https://get.conduitrelay.com/conduit/install.ps1 | iexVS Code — Install Conduit Relay from the Marketplace.
- Install the Conduit Relay extension
- Open any workspace — the extension auto-connects and generates a unique slug
- Your public webhook URL appears in a VS Code notification
- Send a request to it and watch it arrive in the Conduit sidebar panel
# Register a slug and start forwarding to localhost:3000
conduit start --port 3000Your public URL appears in the TUI header. Send a request to it — it shows up immediately.
https://relay.conduitrelay.com/ws-a3f9c2b1d4e6/
On your next run, conduit reads your workspace config from ~/.conduit/projects.json and reconnects automatically. No flags needed.
| Key | Action |
|---|---|
↑ ↓ |
Navigate requests |
r |
Replay selected request against localhost |
d |
Mark as diff base — press again on a second request to compare |
Esc |
Clear diff selection |
q |
Quit |
conduit start Start the tunnel and open the TUI dashboard
conduit auth Authenticate with the relay server
conduit diff <id1> <id2> Field-level diff between two requests in the ring buffer
conduit history List recent requests (default: last 50)
conduit replay <id> Replay a stored request
conduit token refresh Refresh your slug token before it expires
Options (start):
--port <port> Local port to forward to (default: 3000)
--http Accept HTTP in addition to HTTPS
--relay <url> Custom relay WebSocket URL
Conduit stores workspace configuration in ~/.conduit/projects.json, keyed by workspace root path. On first run, it generates a unique ws- prefixed slug for the workspace and saves the slug and token automatically. No config files to create or manage.
The only thing you need to configure manually is a custom relay URL, if you self-host:
export CONDUIT_RELAY_URL=wss://relay.yourdomain.comOr set CONDUIT_HOME to use a different directory for the projects config:
export CONDUIT_HOME=/path/to/configSharing a tunnel with your team: share the slug and token from ~/.conduit/projects.json. Teammates connect as watchers with conduit start --relay wss://relay.conduitrelay.com or via the VS Code extension in watch mode.
The relay is a Fastify WebSocket server. It proxies requests to the owner's CLI, persists a request ring buffer, and broadcasts live traffic to all connected watchers.
The repo includes a docker-compose.yml with Caddy for automatic HTTPS and wss://. Caddy gets a Let's Encrypt cert on first boot and auto-renews it — no cert management needed.
1. Install Docker
curl -fsSL https://get.docker.com | sh
sudo usermod -aG docker $USER && newgrp docker2. Clone the repo
sudo git clone https://github.com/jimseiwert/conduit.git /opt/conduit
sudo chown -R $USER:$USER /opt/conduit
cd /opt/conduit3. Create your .env
cp .env.example .envSet at minimum:
CONDUIT_JWT_SECRET=your-strong-random-secret-here
4. Point your domain at the server, then start
Make sure relay.yourdomain.com has an A record pointing at the server's IP, update the Caddyfile with your domain, then:
nano Caddyfile # replace relay.conduitrelay.com with your domain
docker compose up -d5. Keep it running across reboots and crashes
sudo tee /etc/systemd/system/conduit.service > /dev/null <<EOF
[Unit]
Description=Conduit Relay
Requires=docker.service
After=docker.service network-online.target
[Service]
WorkingDirectory=/opt/conduit
ExecStart=docker compose up
ExecStop=docker compose down
Restart=on-failure
RestartSec=10
[Install]
WantedBy=multi-user.target
EOF
sudo systemctl daemon-reload
sudo systemctl enable --now conduit6. Point your CLI at the relay
Add this to each project's .env (the file conduit reads automatically):
CONDUIT_RELAY_URL=wss://relay.yourdomain.com
Now conduit start --slug myapp connects to your relay instead of conduitrelay.com.
Updating to a new release:
cd /opt/conduit && git pull && docker compose pull && sudo systemctl restart conduitRestarts and state:
docker compose down(without-v) preserves the SQLite volume, so slug registrations survive a restart. Keep your.conduitfile on the client and the CLI will reconnect with its existing token automatically. If you need a completely clean slate (e.g. changedCONDUIT_JWT_SECRET), usedocker compose down -v— this wipes stored slugs, so clients will need to re-register withconduit start --slug <name>.
The chart is published to GHCR on every release and installed directly via OCI.
Prerequisites: a running ingress controller (e.g. ingress-nginx) and an A record for relay.yourdomain.com pointing at your cluster's load balancer IP.
1. Install
helm install conduit-relay oci://ghcr.io/jimseiwert/charts/conduit-relay \
--namespace conduit \
--create-namespace \
--set env.CONDUIT_JWT_SECRET=$(openssl rand -hex 32) \
--set env.RELAY_DOMAIN=relay.yourdomain.com \
--set env.RELAY_PROTO=https \
--set ingress.enabled=true \
--set ingress.host=relay.yourdomain.comIf your ingress controller uses a class name other than nginx, add --set ingress.className=<your-class>.
2. Point your CLI at the relay
Add to each project's .env:
CONDUIT_RELAY_URL=wss://relay.yourdomain.com
Updating to a new release:
helm upgrade conduit-relay oci://ghcr.io/jimseiwert/charts/conduit-relay \
--namespace conduit \
--reuse-valuesKeep
replicaCount: 1. The relay holds an in-memory WebSocket registry. Horizontal scaling via Redis pub/sub is planned for v1.1.
State:
helm upgradepreserves the PVC — slug registrations survive upgrades.helm uninstallremoves the PVC and wipes all stored slugs. Clients will need to re-register withconduit start --slug <name>after a full uninstall.
| Adapter | When to use |
|---|---|
memory |
Development and ephemeral environments |
sqlite |
Single-pod production — persistent, zero-dependency (default) |
postgres |
Production with an external database |
Docker Compose — set in .env:
STORAGE_ADAPTER=sqlite
SQLITE_PATH=/data/conduit.db
# or
STORAGE_ADAPTER=postgres
DATABASE_URL=postgres://user:pass@host/db
Helm — pass as --set flags:
--set env.STORAGE_ADAPTER=postgres \
--set env.DATABASE_URL=postgres://user:pass@host/dbSet AUTH_PROVIDER=oidc or AUTH_PROVIDER=msal (Azure AD) on the relay to require user authentication on top of token-bound slugs.
Docker Compose — set in .env. See .env.example for the full variable list.
Helm:
--set env.AUTH_PROVIDER=oidc \
--set env.OIDC_ISSUER=https://accounts.google.com \
--set env.OIDC_CLIENT_ID=<client-id> \
--set env.OIDC_CLIENT_SECRET=<client-secret> \
--set env.OIDC_REDIRECT_URI=https://relay.yourdomain.com/auth/callbackExternal HTTP request
│
▼
Relay pod (Fastify + WebSocket)
├── /:slug/* ← HTTP proxy — all methods
├── WS /:slug ← Owner (CLI or VS Code ext in proxy mode)
└── WS /:slug/watch ← Watchers (teammates, VS Code in watch mode)
│
▼
ConduitClient (CLI or VS Code ext)
├── Forwards request to localhost:PORT
├── Streams response back via binary WebSocket frames
└── Ink TUI / VS Code panel shows live traffic
Packages:
| Package | Role |
|---|---|
packages/types |
Shared Zod schemas for the WebSocket wire protocol |
packages/relay |
Fastify relay server, JWT auth, ring buffer, storage adapters |
packages/cli |
Ink TUI, WebSocket client, diff / history / replay commands |
packages/vscode-ext |
VS Code sidebar panel with live request list and replay |
apps/relay-chart |
Helm chart for Kubernetes |
bun install
bun run build # Build all packages (types → relay → cli)
bun run dev:relay # Start relay in watch mode
bun test # Run the full test suiteThe wire protocol is defined in packages/types/src/. All messages are Zod-validated JSON over WebSocket. If you're adding a new message type, start there.
Conduit is free and open source. Hosting the public relay, database, and CDN costs roughly $30/month.
If Conduit saves you time, consider sponsoring — it keeps the project alive and the hosted relay running for everyone.
- GitHub Sponsors — one-time or monthly
- Ko-fi — buy a coffee
The goal is never to paywall features. Sponsorship just covers the lights.