MIT Open Source — v1.1.0

Webhook debugging.
Persistent history.
Your infrastructure.

Self-hosted reverse tunnel server with a persistent request inspector and replay engine. Your webhook traffic never leaves your network. The history is yours.

Quick Start
# 1. Clone and configure the server
git clone https://github.com/sqoia-dev/tunnl
cd tunnl
cp .env.example .env   # edit: set DOMAIN and JWT_SECRET
docker compose up -d

# 2. Install the CLI and connect
curl -sSL https://tunnl.sh/install.sh | sh
tunnl login --server https://your.domain.com
tunnl --port 3000   # → https://abc123.your.domain.com

Everything in the debugging loop

Built for the specific problem: you changed your handler, you need the same webhook payload again.

💾
Persistent request history
Full headers and bodies in PostgreSQL. Survives process restarts, reconnects, and browser closes. Configurable retention — default 30 days.
One-click replay
Re-send any captured request with its original headers, including signature headers from Stripe, GitHub, Slack, and Shopify. Diff the original vs replayed response.
🔎
TUI inspector
tunnl inspect opens a split-pane terminal UI. Live request stream, request selection, replay, and curl export. Built with Bubble Tea.
🤖
MCP server for AI agents
tunnl mcp exposes 8 tools over stdio. Claude Desktop, Cursor, and Copilot Agent Mode can query live tunnel traffic and replay requests without you leaving the editor.
🏠
Self-hosted
Your data stays on your network. Wildcard subdomain routing via Caddy. PostgreSQL for storage. Docker Compose for the server and database. No vendor lock-in.
📜
MIT licensed
Server and CLI are both open source under the MIT license. Read it, fork it, modify it. No usage-based restrictions. No telemetry.

How the tunnel works

WebSocket-based reverse proxy with HTTP/2 passthrough and per-chunk back-pressure.

1
CLI connects to your server
The tunnl CLI opens a persistent WebSocket to your self-hosted server. It registers a subdomain and waits for inbound requests.
2
Webhook arrives at the subdomain
Stripe, GitHub, or any provider POSTs to abc123.webhooks.yourdomain.com. Caddy routes it to the Go server. The full request is serialized and stored in PostgreSQL.
3
Request forwarded to localhost
The server sends the request over the WebSocket to your CLI. The CLI forwards it to localhost:3000, captures the response, and sends it back. Supports HTTP/2 and streaming.
4
Inspect and replay anytime
The request lives in PostgreSQL. Kill the terminal, restart the server, reconnect from a different machine — the history is still there. Replay it with original headers from the dashboard or TUI.