Tunnex
The tunnel built for developers and their AI agents. Expose localhost over HTTPS, WebSocket, TCP and UDP in one command — then let your agent drive it over MCP, share local LLMs and MCP servers behind keys, and understand your traffic with an AI-assisted inspector.
pip install tunnex
tunnex http 3000 # → https://<random>.tunnex.org
Website · Console · Product · APIs · Protocol · Architecture · Benchmarks
What you can do
| Command | |
|---|---|
| Public HTTPS URL for a local app (WebSockets, SSE and large uploads stream end to end) | tunnex http 3000 |
| Sign in: your own subdomains, TCP/UDP, email SSO | tunnex login |
| Pick a subdomain (auto-reserved to your account) | tunnex http 3000 --subdomain myapp |
| Private demo | --basic-auth demo:secret · --allow-email @company.com · --allow-ip 203.0.113.0/24 |
| Protect an API with keys | tunnex http 8000 --key auto |
| Let Claude Code / Cursor drive Tunnex | claude mcp add tunnex -- tunnex mcp serve |
| Share a local model (Ollama, LM Studio, vLLM, llama.cpp) | tunnex llm |
| Publish a stdio MCP server as a remote MCP URL | tunnex mcp expose -- npx -y @modelcontextprotocol/server-filesystem ~/docs |
| Raw TCP / UDP (SSH, Postgres, game servers) | tunnex tcp 5432 · tunnex udp 27015 |
| Your addresses | tunnex domains · tunnex domains reserve myapp |
| What's running locally | tunnex status |
Every tunnel records its traffic in the local inspector at http://127.0.0.1:4040:
replay and edit requests, export them as curl/Python/JS/pytest, Explain with AI, search in plain English,
infer an OpenAPI spec from real traffic, and serve mocks — including an offline mock that answers from
recorded traffic when your backend is down.
For AI agents (MCP)
tunnex mcp serve is an MCP server with tools start_tunnel, stop_tunnel, list_tunnels,
list_requests, get_request, wait_for_request, replay_request, send_request, set_mock,
clear_mock, set_offline_mock, explain_request, get_openapi. The canonical loop — "fix the Stripe
webhook handler": start a tunnel → give the URL to Stripe → wait_for_request → read the 500 → fix the
code → replay_request → 200. Traffic of tunnels started in other terminals is visible too.
Sharing local AI safely
Why not just tunnel Ollama's port? Model servers have no authentication, expose admin endpoints
(/api/pull, /api/delete — a stranger can fill your disk or delete models), give you no per-user
accounting, and naive tunnels buffer streaming responses. tunnex llm adds edge-enforced API keys, an
inference-only path allowlist, per-key rate limits, true token streaming and per-key/model token usage:
from openai import OpenAI
client = OpenAI(base_url="https://myllm.tunnex.org/v1", api_key="sk-tnx-...")
tunnex mcp expose bridges stdio MCP servers to Streamable HTTP (one subprocess per MCP session), behind
a secret URL (works with claude.ai / ChatGPT connectors) or a bearer key.
AI provider for the inspector
Claude (claude-opus-5-5) when ANTHROPIC_API_KEY is set, or a local model through Ollama so traffic never
leaves your machine: tunnex ai --provider ollama --model qwen2.5:7b. Secrets (authorization, cookies, API
keys, password/token fields) are redacted before any prompt.
Plans
| Anonymous | Free account | |
|---|---|---|
| Subdomain | random, sticky per machine | your choice, reserved (3) |
| Browser interstitial | yes | no |
| Edge policies | basic auth, keys, IP/path allowlists | + email SSO |
| TCP / UDP | — | yes, stable ports |
| Rate limit | 120 req/min | 1200 req/min |
| Concurrent tunnels | 3 per IP | 10 |
Architecture in one picture
browser / webhook / agent
│ HTTPS, WSS, TCP, UDP
▼
┌──────────────── edge: <sub>.tunnex.org ────────────────┐ ┌─ control: connect.tunnex.org ─┐
│ policies (IP, path, keys, basic, SSO) · rate limits │ │ console · accounts · tokens │
│ interstitial · identity headers · streaming proxy │ │ device login · SSO · usage │
└──────────────┬──────────────────────────────────────────┘ └──────────────┬────────────────┘
│ protocol v2: binary frames, multiplexed streams, flow control │ PostgreSQL
▼ ▼
┌──────────── tunnex client (your machine) ─────────────┐
│ HTTP/WS/TCP/UDP → localhost · capture → ~/.tunnex │──▶ inspector :4040 · MCP server · AI
└───────────────────────────────────────────────────────┘
Details: ARCHITECTURE.md.
Self-hosting
Requirements: a host with a public IP, a domain with a wildcard DNS record (*.example.com) and a wildcard
TLS certificate, Docker with Compose.
CF_API_TOKEN=<cloudflare token with Zone:DNS:Edit> ./deploy/bootstrap-server.sh root@<host>
The bootstrap installs Nginx (TLS termination, streaming proxy), certbot (wildcard certificate via DNS-01),
ufw, and /opt/tunnex/ with docker-compose.yml — Tunnex server, PostgreSQL,
Prometheus and Grafana — plus a .env with generated secrets. Migrations run on container start. Server
settings: server_/config.yaml.example; every value can be overridden with
TUNNEX_* environment variables. Optional: SMTP (email verification) and a GitHub OAuth app
(https://connect.<domain>/auth/github/callback) — either one enables email SSO.
Point the client at your server with TUNNEX_SERVER=wss://connect.example.com (or --server).
Metrics are served on 127.0.0.1:9101/metrics; the Grafana dashboard is provisioned automatically
(ssh -L 3000:127.0.0.1:3000 <host>).
Development
uv venv .venv --python 3.10 && uv pip install -e . -r server_/requirements.txt pytest pytest-asyncio
.venv/bin/python -m pytest -q # end-to-end suite (SQLite)
TUNNEX_TEST_DATABASE_URL=postgresql+asyncpg://... .venv/bin/python -m pytest -q # against PostgreSQL
TUNNEX_CONFIG=server_/config.yaml.example .venv/bin/python -m server_ # run a server
The suite starts real servers, clients and upstream apps in-process and covers streaming, flow control, policies, accounts, SSO, TCP/UDP, MCP, LLM publishing and the AI features (with fake providers).
| Path | What |
|---|---|
shared/ |
protocol v2 frames (protocol.py) and the stream multiplexer (mux.py) |
server_/ |
edge proxy, control plane API, accounts, policies, PostgreSQL models + Alembic migrations, metrics, web console |
client/ |
CLI, tunnel client, inspector API + UI, MCP server and bridge, LLM publishing, AI features |
deploy/ |
bootstrap script, Nginx, Compose stack, monitoring |
landing/ |
tunnex.org |
bench/ |
benchmark harness |
CI (GitLab): tests on every change → server image → deploy with Compose; client → PyPI; landing → rsync.
Contact
dev@tunnex.org · MIT License
Metadata
Release files for tunnex 26.10.10.21
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| tunnex-26.10.10.21.tar.gz | 131.9 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| tunnex-26.10.10.21-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 265.5 kB
Release files / tunnex-26.10.10.21.tar.gz
| Download URL | tunnex-26.10.10.21.tar.gz |
|---|---|
| Size | 131.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
90d8c1b493d77033c3bf8e175f8b84e19b6c994b569e45b494d554a493507b89
|
|
BLAKE2b-256 checksum How to use checksums |
b907a2ee4a14ce2e037c62deecbdfac3640288a2fab2051f0529dd51422aa1f3
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.11.17
|
Release files / tunnex-26.10.10.21-py3-none-any.whl
| Download URL | tunnex-26.10.10.21-py3-none-any.whl |
|---|---|
| Size | 133.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
a7b9372941b175932a7279114c6492481dea5df603b3dd279b1b536e6c45e1d8
|
|
BLAKE2b-256 checksum How to use checksums |
9e3e4b2f6daf3ea34b9971070f7ed19f5788ac947c5ecc4f535e0aa7dae0003c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.11.17
|