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.1
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.1.tar.gz | 41.3 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| tunnex-26.10.9.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 84.3 kB
Release files / tunnex-26.10.9.1.tar.gz
| Download URL | tunnex-26.10.9.1.tar.gz |
|---|---|
| Size | 41.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
cdf84ac5b6b7a4703f7f248861464ecd67761f95e7ffbea7967162bcf2ba6c25
|
|
BLAKE2b-256 checksum How to use checksums |
672de143288c489df550af9ee1847d57d54423cf98fed2860121fa9b4a8f20d2
|
| 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.1-py3-none-any.whl
| Download URL | tunnex-26.10.9.1-py3-none-any.whl |
|---|---|
| Size | 42.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
c340c3ed69ecd5001a2c23bbb0fb7c8e2f102164f074fda1aa392b0d603a0b17
|
|
BLAKE2b-256 checksum How to use checksums |
89eec0323109229c98656000ba373f5c6c31e5ceafaf2266b385437b57bab73e
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.11.17
|