PiTunnel server is a tunnel server that exposes services on your local network to the internet.
- Web Tunnel: HTTP/HTTPS traffic proxying
- TCP Tunnel: SSH, RDP, MySQL, PostgreSQL and other protocols
- Custom Domain: Support for custom domains (clients can use their own domains)
- WebSocket Support: Full bidirectional WebSocket proxy (including HMR support)
- Dynamic Port: Automatic port opening based on client's target port
- API: RESTful API for tunnel management
- Statistics: Request count, bandwidth usage
One-line installer for Linux servers (Ubuntu, Debian, CentOS, etc.):
curl -fsSL https://raw.githubusercontent.com/Pi-Tunnel/Server/refs/heads/main/setup.sh -o /tmp/setup.sh && sudo bash /tmp/setup.shThis will:
- Install Node.js and dependencies
- Download and configure PiTunnel Server
- Set up systemd service (auto-start on boot)
- Configure firewall rules
- Generate authentication token
- Create
piserverCLI command
After installation, use the piserver command to manage the server:
| Command | Description |
|---|---|
piserver start |
Start PiTunnel Server |
piserver stop |
Stop PiTunnel Server |
piserver restart |
Restart PiTunnel Server |
piserver status |
Show server status |
piserver logs |
View live logs |
piserver update |
Update to latest version |
piserver config |
Show configuration |
piserver token |
Show auth token |
piserver help |
Show help message |
# Check server status
piserver status
# View live logs
piserver logs
# Restart server
piserver restart
# Show auth token
piserver token PiTunnel Server Status
────────────────────────────────────────
Status: â—Ź Running
PID: 12345
Autostart: Enabled
Configuration
────────────────────────────────────────
Domain: *.tunnel.example.com
HTTP: Port 80
WebSocket: Port 8081
API: Port 8082
Configuration file: /etc/pitunnel/config.json
{
"domain": "tunnel.example.com",
"httpPort": 80,
"wsPort": 8081,
"apiPort": 8082,
"authToken": "your-secret-token-here"
}| Parameter | Default | Description |
|---|---|---|
domain |
tunnel.example.com | Main domain for tunnel access |
httpPort |
80 | Port for HTTP traffic |
wsPort |
8081 | Port for WebSocket connections |
apiPort |
8082 | Port for API endpoints |
authToken |
null | Client authentication token |
The server automatically starts listening on the client's target port. This enables Hot Module Replacement (HMR) for frameworks like React, Vite, and Next.js to work automatically.
Example:
- Client starts a tunnel with target
127.0.0.1:3000 - Server automatically starts listening on port 3000 as well
- Browser can request
ws://tunnel-name.domain.com:3000/ws - Server forwards this request to the client
Supported Ports:
- All user ports (1024+)
- 80 and 443 (HTTP/HTTPS)
Note: You may need to allow dynamic ports in your firewall.
All API endpoints (except health) require authentication.
Include one of the following headers with each request:
X-Auth-Token: your-token-here
or
Authorization: Bearer your-token-here
Server health check. No token required.
Response:
{
"status": "ok",
"uptime": 3600,
"tunnels": 5,
"memory": {...},
"domain": "tunnel.example.com"
}Lists all active tunnels.
Response:
{
"tunnels": [
{
"name": "my-tunnel",
"target": "127.0.0.1:3000",
"tunnelType": "web",
"protocol": "http",
"customDomain": null,
"ports": [],
"connectedAt": "2025-01-01T00:00:00.000Z",
"uptime": 3600000,
"stats": {
"requests": 150,
"bytesIn": 45000,
"bytesOut": 1250000
},
"accessUrl": "http://my-tunnel.tunnel.example.com"
}
],
"count": 1
}Note: If a tunnel has a custom domain configured,
customDomainwill contain the domain (e.g.,"myapp.example.com") andaccessUrlwill be"http://myapp.example.com".
Gets details of a specific tunnel.
Response:
{
"name": "my-tunnel",
"target": "127.0.0.1:3000",
"tunnelType": "web",
"protocol": "http",
"connectedAt": "2025-01-01T00:00:00.000Z",
"uptime": 3600000,
"stats": {
"requests": 150,
"bytesIn": 45000,
"bytesOut": 1250000
},
"accessUrl": "http://my-tunnel.tunnel.example.com"
}Stops a tunnel and closes the client connection.
Response:
{
"success": true,
"message": "Tunnel my-tunnel stopped"
}Sends a restart command to the tunnel.
Response:
{
"success": true,
"message": "Restart command sent to my-tunnel"
}Gets overall server statistics.
Response:
{
"tunnels": 5,
"totalRequests": 1500,
"totalBytesIn": 450000,
"totalBytesOut": 12500000,
"uptime": 86400
}# List tunnels
curl -H "X-Auth-Token: your-token" http://localhost:8082/tunnels
# Get specific tunnel info
curl -H "X-Auth-Token: your-token" http://localhost:8082/tunnels/my-tunnel
# Stop tunnel
curl -X DELETE -H "X-Auth-Token: your-token" http://localhost:8082/tunnels/my-tunnel
# Restart tunnel
curl -X POST -H "X-Auth-Token: your-token" http://localhost:8082/tunnels/my-tunnel/restart
# Get statistics
curl -H "X-Auth-Token: your-token" http://localhost:8082/statsconst API_URL = 'http://localhost:8082';
const TOKEN = 'your-token';
// Get tunnel list
const response = await fetch(`${API_URL}/tunnels`, {
headers: { 'X-Auth-Token': TOKEN }
});
const data = await response.json();
console.log(data.tunnels);
// Stop tunnel
await fetch(`${API_URL}/tunnels/my-tunnel`, {
method: 'DELETE',
headers: { 'X-Auth-Token': TOKEN }
});import requests
API_URL = 'http://localhost:8082'
HEADERS = {'X-Auth-Token': 'your-token'}
# List tunnels
response = requests.get(f'{API_URL}/tunnels', headers=HEADERS)
tunnels = response.json()['tunnels']
# Stop tunnel
requests.delete(f'{API_URL}/tunnels/my-tunnel', headers=HEADERS)Create a wildcard DNS record for auto-generated subdomains:
*.tunnel.example.com A YOUR_SERVER_IP
Clients can use their own custom domains. For this to work:
-
Client points their domain to your server IP:
myapp.example.com A YOUR_SERVER_IP -
Client starts tunnel with custom domain option:
piclient start # Select "Custom domain" when prompted # Enter: myapp.example.com
-
The server automatically routes requests from
myapp.example.comto the correct tunnel.
Note: Custom domains work alongside wildcard subdomains. You don't need any additional server configuration.
Open the following ports:
# 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 # Common development portsOr to allow all ports:
sudo ufw disable
# or
sudo ufw default allow incomingserver {
listen 80;
server_name *.tunnel.example.com;
location / {
proxy_pass http://127.0.0.1:80;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}- Keep your token secure: Don't share your token with anyone
- Use HTTPS: SSL/TLS is recommended for production
- Firewall: Only open necessary ports
- API access: API endpoints are protected with token
MIT