Open-source tunnel solution that securely exposes services on your local network to the internet. A self-hosted alternative similar to Cloudflare Tunnel.
| Package | Description | Install |
|---|---|---|
| pi-tunnel-client | PiTunnel Client | npm install -g pi-tunnel-client |
| pi-tunnel-server | PiTunnel Server | Should be installing via bash script |
- Web Tunnel: HTTP/HTTPS traffic proxying
- TCP Tunnel: SSH, RDP, MySQL, PostgreSQL, FTP and other protocols
- Custom Domain: Use your own domain instead of auto-generated subdomain
- WebSocket Support: Full bidirectional WebSocket proxy (including React/Vite/Next.js HMR)
- Dynamic Port: Automatic port opening based on target port
- Cross-Platform Client: Windows, macOS and Linux support
- Auto Reconnect: Automatic reconnection when connection drops
- System Service: Auto-start on system boot
- RESTful API: API for tunnel management
- Statistics: Request count, bandwidth usage
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ Browser │────▶│ PiTunnel │────▶│ PiTunnel │
│ │ │ Server │ │ Client │
│ tunnel.domain │◀────│ (Public) │◀────│ (Local) │
└─────────────────┘ └─────────────────┘ └────────┬────────┘
│
▼
┌─────────────────┐
│ Local Service │
│ (localhost) │
└─────────────────┘
curl -fsSL https://raw.githubusercontent.com/Pi-Tunnel/Server/refs/heads/main/setup.sh -o /tmp/setup.sh && sudo bash /tmp/setup.shThis will automatically:
- Install Node.js and dependencies
- Configure PiTunnel Server interactively
- Set up systemd service (auto-start on boot)
- Configure firewall rules
- Generate authentication token
- Create
piserverCLI command
Add a wildcard DNS record for auto-generated subdomains:
*.tunnel.yourdomain.com A YOUR_SERVER_IP
For custom domains, point your domain directly to the server:
myapp.example.com A YOUR_SERVER_IP
# Install client globally
npm install -g pi-tunnel-client
# Login to server
piclient login
# Start tunnel
piclient start
# Target: 127.0.0.1:3000http://your-tunnel-name.tunnel.yourdomain.com
# Run development server locally
npm run dev # port 3000
# Start tunnel
piclient start
# Type: Web
# Target: 127.0.0.1:3000
# Now accessible at http://my-app.tunnel.domain.com
# HMR (Hot Reload) works automatically!piclient start
# Type: TCP
# Protocol: SSH
# Target: 127.0.0.1:22
# Connect remotely:
ssh user@my-tunnel.tcp.tunnel.domain.compiclient start
# Type: TCP
# Protocol: MySQL
# Target: 127.0.0.1:3306
# Connect remotely:
mysql -h my-tunnel.tcp.tunnel.domain.com -u user -p# Run Express/Flask/Django API
python app.py # port 8080
# Start tunnel
piclient start
# Target: 127.0.0.1:8080
# Test webhook:
curl http://my-api.tunnel.domain.com/webhookpiclient start
# Type: TCP
# Protocol: RDP
# Target: 127.0.0.1:3389
# Connect from Windows:
mstsc /v:my-tunnel.tcp.tunnel.domain.comUse your own domain instead of auto-generated subdomain:
piclient start
# Type: Web
# Target: 127.0.0.1:3000
# Domain Type: Custom domain
# Custom domain: myapp.example.com
# Now accessible at http://myapp.example.comOr via CLI:
piclient connect -n myapp -s ws://server:8081 -t localhost:3000 --custom-domain myapp.example.com| Command | Description |
|---|---|
piclient login |
Login to server |
piclient logout |
Logout from server |
piclient start |
Start new tunnel (interactive) |
piclient start -b |
Start in background |
piclient stop |
Stop tunnel (interactive) |
piclient stop --all |
Stop all tunnels |
piclient status |
Status and statistics |
piclient list |
List saved connections |
piclient install |
Auto-start on system boot |
piclient uninstall |
Remove auto-start |
After server installation, use piserver to manage:
| Command | Description |
|---|---|
piserver start |
Start server |
piserver stop |
Stop server |
piserver restart |
Restart server |
piserver status |
Show server status |
piserver logs |
View live logs |
piserver config |
Show configuration |
piserver token |
Show auth token |
| Port | Usage |
|---|---|
| 80 | HTTP Tunnel traffic |
| 8081 | WebSocket (Client connections) |
| 8082 | API (Tunnel management) |
| Dynamic | Automatically opened based on client target port |
Server provides RESTful API (protected with token):
| Endpoint | Method | Description |
|---|---|---|
/health |
GET | Server status (public) |
/tunnels |
GET | List active tunnels |
/tunnels/:name |
GET | Tunnel details |
/tunnels/:name |
DELETE | Stop tunnel |
/tunnels/:name/restart |
POST | Restart tunnel |
/stats |
GET | General statistics |
# Example: List tunnels
curl -H "X-Auth-Token: your-token" http://server:8082/tunnelsFor detailed API documentation, see server/README.md.
- Server: github.com/Pi-Tunnel/Server
- Client: github.com/Pi-Tunnel/Client
- All connections are authenticated with token
- API endpoints are protected
- HTTPS recommended for production
- Keep your token secure
# Basic ports
sudo ufw allow 80/tcp # HTTP
sudo ufw allow 8081/tcp # WebSocket
sudo ufw allow 8082/tcp # API
# Dynamic ports (for HMR support)
sudo ufw allow 3000:9000/tcp- Node.js: 18.0.0 or higher
- Server: VPS/server with public IP
- DNS: Wildcard DNS support
| Platform | Client | Server | System Service |
|---|---|---|---|
| Windows | ✅ | ✅ | Task Scheduler |
| macOS | ✅ | ✅ | LaunchDaemon |
| Linux | ✅ | ✅ | systemd |
MIT
Pull requests are welcome! Please open an issue first to discuss the proposed changes.