Self-hosted reverse tunnel server to expose your localhost to the internet
Website • Русский • Discussions
fxTunnel is a fast, self-hosted reverse tunneling solution written in Go. It lets you expose local HTTP, TCP, and UDP services to the internet through a server you fully control — no third-party dependencies, no usage limits, no vendor lock-in.
Deploy the server on any VPS, point a wildcard DNS record at it, and your team instantly gets secure public URLs for local development servers, webhook testing, IoT devices, SSH access, and more.
| Feature | fxTunnel | ngrok | Cloudflare Tunnel | frp |
|---|---|---|---|---|
| Self-hosted | Yes | No | Partial | Yes |
| Open source | Yes | No | Client only | Yes |
| HTTP tunnels | Yes | Yes | Yes | Yes |
| TCP tunnels | Yes | Yes | Yes | Yes |
| UDP tunnels | Yes | Paid | No | Yes |
| Custom subdomains | Unlimited | 1 free | Via DNS | Manual |
| Wildcard domains | Yes | Paid | No | No |
| Web admin panel | Built-in | Cloud dashboard | Cloud dashboard | Dashboard plugin |
| GUI desktop client | Yes | No | No | No |
| User management & 2FA | Built-in | Cloud-based | Cloudflare Access | No |
| Connection limits | None | 1 tunnel free | No limit | None |
| Bandwidth limits | None | 1 GB/mo free | No limit | None |
| Price | Free | From $8/mo | Free (requires CF) | Free |
| Multiplexing | yamux | QUIC | QUIC | Custom |
- HTTP Tunnels — Expose local web services at
yourapp.tunnel.example.comwith automatic subdomain routing - TCP Tunnels — Forward any TCP port: SSH, databases, game servers, RDP
- UDP Tunnels — Forward UDP traffic for DNS, VoIP, gaming protocols
- Wildcard Domains — Full
*.yourdomain.comsupport with nginx + Let's Encrypt - Web Admin Panel — Manage users, tokens, domains, and active tunnels from a built-in Vue 3 dashboard
- User Management — Registration with invite codes, TOTP two-factor authentication, scoped API tokens
- Desktop GUI Client — Cross-platform Wails-based app (Linux, macOS, Windows) with system tray support
- CLI Client — Lightweight command-line client with YAML config and auto-reconnect
- Stream Multiplexing — Efficient yamux-based multiplexed connections over a single TCP link
- Docker Ready — Official container image on GitHub Container Registry
- Security — Interstitial warning pages for untrusted tunnel traffic, TLS termination via nginx, token-scoped permissions
One-liner install (Linux/macOS):
curl -fsSL https://fxtun.dev/install.sh | shOr download from Releases.
Windows users: Windows may show a SmartScreen warning ("Windows protected your PC") when running the
.exefor the first time. This is expected — the binaries are not code-signed yet. All release binaries are automatically scanned with VirusTotal during CI — check the scan results linked in each release.To bypass SmartScreen: click "More info" → "Run anyway".
Expose a local HTTP server:
fxtunnel http 3000 --server tunnel.example.com:4443 --token sk_your_token
# → https://random-subdomain.tunnel.example.comUse a custom subdomain:
fxtunnel http 3000 --domain myapp --server tunnel.example.com:4443 --token sk_your_token
# → https://myapp.tunnel.example.comForward a TCP port (SSH, database, etc.):
fxtunnel tcp 22 --server tunnel.example.com:4443 --token sk_your_tokenForward UDP traffic:
fxtunnel udp 53 --server tunnel.example.com:4443 --token sk_your_tokenUse a config file for persistent tunnels:
fxtunnel --config client.yamlInstall the server via Docker:
docker run -d \
--name fxtunnel \
-p 4443:4443 \
-p 8080:8080 \
-p 3000:3000 \
-p 10000-20000:10000-20000 \
-v ./data:/app/data \
-v ./configs/server.yaml:/app/configs/server.yaml \
ghcr.io/mephistofox/fxtun.dev:latestOr build from source:
git clone https://github.com/mephistofox/fxtun.dev.git
cd fxtun.dev
make build
./bin/fxtunnel-server --config configs/server.yamlPoint a wildcard DNS record to your server:
*.tunnel.example.com → A → YOUR_SERVER_IP
INTERNET
│
┌───────────────────┼───────────────────┐
│ │ │
▼ ▼ ▼
*.domain.com TCP ports UDP ports
(via nginx) (dynamic) (dynamic)
│ │ │
└───────────────────┼───────────────────┘
│
▼
┌───────────────────┐
│ fxtunnel-server │
│ │
│ • HTTP Router │
│ • TCP Manager │
│ • UDP Manager │
│ • Web Admin UI │
│ • REST API │
└─────────┬──────────┘
│
yamux-multiplexed TCP
│
┌───────────────────────┼───────────────────────┐
│ │ │
▼ ▼ ▼
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ Client 1 │ │ Client 2 │ │ Client N │
│ webapp:3000 │ │ ssh:22 │ │ dns:53/udp │
└──────────────┘ └──────────────┘ └──────────────┘
server:
control_port: 4443 # Client tunnel connections
http_port: 8080 # HTTP tunnel traffic
tcp_port_range:
min: 10000
max: 20000
udp_port_range:
min: 20001
max: 30000
domain:
base: "tunnel.example.com"
wildcard: true
web:
port: 3000 # Admin panel & API
auth:
jwt_secret: "change-me"
totp_key: "change-me"
database:
path: "./data/fxtunnel.db"server:
address: "tunnel.example.com:4443"
token: "sk_your_token"
tunnels:
- name: "webapp"
type: "http"
local_port: 3000
subdomain: "myapp"
- name: "ssh"
type: "tcp"
local_port: 22
reconnect:
enabled: true
interval: 5sAll config values can be set via environment variables with FXTUNNEL_ prefix:
export FXTUNNEL_AUTH_JWT_SECRET="your-secret"
export FXTUNNEL_SERVER_CONTROL_PORT=4443
export FXTUNNEL_DATABASE_PATH="./data/fxtunnel.db"For production use with HTTPS, configure nginx as a TLS-terminating reverse proxy:
server {
listen 443 ssl http2;
server_name *.tunnel.example.com;
ssl_certificate /etc/letsencrypt/live/tunnel.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/tunnel.example.com/privkey.pem;
location / {
proxy_pass http://127.0.0.1:8080;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_read_timeout 86400;
}
}Get a wildcard certificate:
certbot certonly --dns-cloudflare \
--dns-cloudflare-credentials /etc/letsencrypt/cloudflare.ini \
-d tunnel.example.com \
-d *.tunnel.example.commake build # Build CLI client + server
make server # Build server only
make client # Build CLI client only
make gui # Build desktop GUI client (requires Wails)
make web # Build Vue 3 admin panel
make test # Run tests
make build-all # Full build: web + server + all platform clientsRequirements: Go 1.24+, Node.js 20+ (for web UI and GUI client)
fxTunnel uses a custom length-prefixed JSON protocol over TCP, with yamux stream multiplexing:
┌──────────────┬──────────────────────────────┐
│ Length (4B) │ JSON Payload │
│ big-endian │ │
└──────────────┴──────────────────────────────┘
Contributions are welcome! Please open an issue first to discuss what you would like to change.
MIT with Attribution Requirement — see LICENSE.
Any use, deployment, or distribution must include visible attribution:
- GitHub: github.com/mephistofox/fxtun.dev
- Website: fxtun.dev