Tunnex
Expose local services to the internet through public domains. Supports HTTP/HTTPS, WebSocket, TCP and UDP.
localhost:3000 → https://my-app.tunnex.org
Features
- HTTP/HTTPS — proxy web applications with automatic TLS
- WebSocket — full WS support (HMR, Socket.IO, chats)
- TCP — tunnels for databases, SSH and any TCP service
- UDP — tunnels for VoIP, game servers, IoT
- Web dashboard — live view of requests and TCP/UDP streams, settings management
- Custom subdomains —
your-name.tunnex.org - Rate limiting — on both the client and the server
- Custom response — stub mode with a configurable response
- Replay — resend HTTP requests from the dashboard
Quick start
Install
pip install tunnex
Run
tunnex --port 3000
Once started:
- Public URL:
https://<subdomain>.tunnex.org - Dashboard:
http://127.0.0.1:8080
Default server: wss://connect.tunnex.org (override with --server).
CLI options
| Option | Description | Default |
|---|---|---|
--port, -p |
Local application port | — (required) |
--dashboard-port, -d |
Dashboard port | 8080 |
--server, -s |
Tunnel server URL | wss://connect.tunnex.org |
--config |
Path to the client config | — |
Subcommands
tunnex start --port 3000 # start (default)
tunnex list # list registered subdomains
Architecture
┌──────────────┐ ┌───────────────┐ WebSocket (TLS) ┌───────────────┐
│ Your app │◄──────────────────►│ Tunnex client │◄─────────────────────►│ Tunnex server │
│ :3000 │ localhost proxy │ (Python) │ encrypted tunnel │ │
└──────────────┘ └───────────────┘ └───────┬───────┘
│ HTTPS/TCP/UDP
▼
┌───────────────┐
│ Users │
│ (internet) │
└───────────────┘
Tech stack
| Component | Technologies |
|---|---|
| Server | Python 3.10+, FastAPI, Uvicorn, SQLAlchemy, aiosqlite |
| Client | Python 3.10+, websockets, httpx, Click, Rich |
| Protocol | WebSocket + JSON, Base64 for binary data |
| Deployment | Docker, Nginx, GitLab CI/CD |
| Database | SQLite (client), SQLite/PostgreSQL (server) |
Dashboard
Local dashboard at http://127.0.0.1:8080:
- Requests — live list of HTTP requests, filtering by method/status, URL search, headers and bodies
- Replay — resend a request, optionally with modified parameters
- TCP — active TCP streams, hex view, send data, close connections
- UDP — UDP events, packet view (hex/text), send packets
- Settings — subdomain, local port, rate limit, custom response
- Status — connection state, public URL, uptime, errors
Updates arrive in real time over WebSocket.
Server deployment
Domain layout
| Host | Purpose |
|---|---|
tunnex.org |
Landing page (www redirects here) |
connect.tunnex.org |
Control endpoint the client connects to (/tunnel/connect, /api/*) |
*.tunnex.org |
Public tunnels |
DNS is hosted on Cloudflare. All records are DNS-only (not proxied): tunnels use raw TCP/UDP
ports and second-level wildcards that the Cloudflare proxy cannot serve. Reserved subdomains
(www, connect, api, mail, …) cannot be claimed by tunnels.
Bootstrap a fresh host
deploy/bootstrap-server.sh prepares an Ubuntu 24.04 host: installs Docker,
Nginx, certbot and ufw, issues a wildcard Let's Encrypt certificate for tunnex.org + *.tunnex.org
via the dns-cloudflare plugin, installs deploy/nginx/tunnex.conf and
deploy/server-config.yaml, and opens ports 22, 80, 443 and 45000–46000 (TCP/UDP).
CF_API_TOKEN=<token with Zone:DNS:Edit> ./deploy/bootstrap-server.sh root@<host>
Certificates renew automatically via certbot.timer; Nginx is reloaded after renewal.
Docker
The server container is started by CI, equivalent to:
docker run -d \
--name tunnex-server \
--restart unless-stopped \
--network host \
-v /opt/tunnex/config.yaml:/app/config.yaml:ro \
-v /opt/tunnex/certs:/app/certs:ro \
-v /opt/tunnex/data:/app/data \
-e SERVER_CONFIG=/app/config.yaml \
registry.gitlab.com/homycoder/tunnex/server:latest
Server requirements
- Public IP address
- Domain with a wildcard DNS record (
*.example.com) - Reverse proxy (Nginx) for TLS termination
- Open ports: 80, 443, TCP/UDP range 45000–46000
CI/CD (GitLab)
Pipelines
On changes to server_/ or shared/:
- Build the Docker image and push it to the GitLab Container Registry
- Deploy to the server (pull + restart the container)
On changes to client/, shared/, setup.py:
- Bump the version (
YY.MM.DD.patch) - Build wheel + sdist
- Publish to PyPI
On changes to landing/: rsync to /opt/tunnex/landing on the server.
CI/CD variables
Server deployment (GitLab → Settings → CI/CD → Variables):
SSH_PRIVATE_KEY— SSH private key for deploymentSSH_USER— server userSERVER_HOST— server address
PyPI publishing:
PYPI_USERNAME—__token__PYPI_PASSWORD— PyPI API token
Development
make install-dev # dev tools (ruff, black, mypy)
make lint # lint (ruff)
make fmt # format (black)
make mypy # type check
make test # tests
make build-client # build the client package
Project layout
├── client/ # tunnel client
│ ├── client.py # CLI (Click)
│ ├── tunnel_client.py # tunnel logic
│ ├── dashboard.py # FastAPI dashboard
│ ├── models.py # SQLAlchemy models
│ └── static/ # dashboard frontend
├── server_/ # tunnel server
│ ├── main.py # FastAPI + WS + HTTP proxy
│ ├── tunnel_manager.py # tunnel registry
│ ├── tcp_udp_manager.py # TCP/UDP manager
│ ├── models.py # SQLAlchemy models
│ └── Dockerfile
├── shared/ # shared code
│ └── protocol.py # protocol message types
├── landing/ # tunnex.org landing page
├── deploy/ # server bootstrap, Nginx and server config
├── learn/ # step-by-step walkthroughs of the protocol
└── setup.py # tunnex package
Contact
License
MIT
Metadata
Release files for tunnex 26.10.9.19
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.9.19.tar.gz | 41.4 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| tunnex-26.10.9.19-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 84.4 kB
Release files / tunnex-26.10.9.19.tar.gz
| Download URL | tunnex-26.10.9.19.tar.gz |
|---|---|
| Size | 41.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
f28bdb4e8f4cebc5c2ecea3ecebf2f18a2390a842bb9e7e5529c01b1a1b7a309
|
|
BLAKE2b-256 checksum How to use checksums |
6881a9487e7b24ab82add6599d40339731bed67e0111a1d6b6f427a496515829
|
| 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.9.19-py3-none-any.whl
| Download URL | tunnex-26.10.9.19-py3-none-any.whl |
|---|---|
| Size | 43.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
8eb00eb7b1face7a391993ce8f668a418e5ffed33f5fc878b93da3064d450b81
|
|
BLAKE2b-256 checksum How to use checksums |
85cfaf08e6b37e76fa4bd08cb679b1666d3739659a1135830c8594fc6d0a848c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.11.17
|