MonkeyTunel

Self-hosted tunnel server

Sign In

Server:
Total Tunnels
0
Online Now
0
API Keys
0

Your Tunnels

No tunnels configured yet.

Create Tunnel

StatusNameProtocolRoutePublic URLUptimeActions
No tunnels yet. Click "+ New Tunnel" to get started.
Live
StatusMethodPathTime
No requests captured. Send traffic through the tunnel to see requests here.
Save this key now - it won't be shown again
NamePrefixCreatedActions
No API keys. Create one to connect the CLI client.

Quick Start Guide

Get a tunnel running in under 2 minutes.

1

Create an API Key

Go to and create a new key. Copy it immediately - it's only shown once.

2

Create a Tunnel

Go to and create a new tunnel. Choose HTTP protocol with subdomain routing for web apps.

3

Download the Client

Download from the /download page, or:

curl -sL https:///api/download/linux/amd64 -o tunnle-client && chmod +x tunnle-client
4

Connect

Run the client pointing at your local service:

./tunnle-client \
  -server wss:// \
  -key YOUR_API_KEY \
  -tunnel YOUR_TUNNEL_ID \
  -local 127.0.0.1:3000

Auto-Reconnect

The client automatically reconnects with exponential backoff (1s to 30s) if the connection drops. No action needed - just leave it running.

CLI Reference

All available command-line flags for tunnle-client.

FlagDefaultDescription
-serverrequiredServer WebSocket URL (wss://...)
-keyrequiredAPI key for authentication
-tunnelrequiredTunnel ID from the dashboard
-local127.0.0.1:8080Local address to forward traffic to
-protohttpProtocol: http, tcp, or udp
-routesubdomainRoute mode: subdomain, path, or port
-subdomain-Subdomain for routing
-path-Path prefix for routing
-port0Remote port for TCP/UDP
-config~/.monkeytunel.ymlPath to config file
-profile-Config profile to use
-initfalsePrint example config and exit
-vfalseVerbose/debug logging

Config File

Instead of passing flags, use a YAML config at ~/.monkeytunel.yml.

Generate a starter config: tunnle-client -init > ~/.monkeytunel.yml

# ~/.monkeytunel.yml
server: wss://
key: your-api-key-here

tunnels:
  - name: myapp
    id: your-tunnel-uuid
    local: 127.0.0.1:3000
    proto: http
    route: subdomain
    subdomain: myapp

  - name: ssh
    id: another-tunnel-uuid
    local: 127.0.0.1:22
    proto: tcp
    route: port
    port: 2222

Then just run: tunnle-client (no flags needed)

Command-line flags always override config file values.

Protocols

HTTP

Best for web apps, APIs, and webhooks. Traffic is routed via subdomain (e.g., myapp.tunnel.monkeycode.co.uk) or path prefix. Supports the request inspector for debugging. The server acts as a reverse proxy.

TCP

For SSH, databases, game servers, or any TCP service. Allocates a remote port on the server that forwards to your local port. Example: expose local SSH on port 2222 remotely.

./tunnle-client -proto tcp -route port -port 2222 -local 127.0.0.1:22 ...

UDP

For DNS, game servers, VoIP, or any UDP service. Works similarly to TCP - allocates a remote UDP port. Datagrams are framed and tunneled over the WebSocket connection.

./tunnle-client -proto udp -route port -port 5353 -local 127.0.0.1:53 ...

Custom Domains

Point your own domain to a tunnel instead of using the default subdomain.

1

Add a CNAME record

Point your domain to this server:

app.yourdomain.com  CNAME  
2

Set custom domain on tunnel

Edit your tunnel and enter the custom domain in the "Custom Domain" field, or set it when creating the tunnel.

3

Connect the client

Traffic to app.yourdomain.com will be routed to your tunnel automatically.

Note: For HTTPS on custom domains, you'll need a wildcard certificate or use the AutoTLS feature with DNS-01 challenge.

Webhook Notifications

Get notified when your tunnel connects or disconnects. Set a webhook URL on any tunnel.

Events

tunnel_connectedFired when the client connects and registers
tunnel_disconnectedFired when the client disconnects (includes byte counts)

Payload Example

{
  "event": "tunnel_disconnected",
  "tunnel_id": "abc-123-...",
  "timestamp": "2026-02-28T12:00:00Z",
  "data": {
    "bytes_in": 1048576,
    "bytes_out": 524288,
    "connection_count": 42,
    "duration_seconds": 3600.5
  }
}

Request Inspector

The inspector captures the last 100 HTTP requests flowing through a tunnel, showing method, path, status code, headers, body preview, and latency.

To use it:

  1. Go to Tunnels and click Inspect on an HTTP tunnel
  2. Send traffic through the tunnel
  3. The inspector auto-refreshes every 2 seconds
  4. Click any request row to expand headers and body

Note: Only available for HTTP tunnels. Body preview is limited to 4KB. The inspector only captures while you have the page open - it stores the last 100 requests in memory per tunnel session.

You can also fetch requests via the API:

GET /api/tunnels/{id}/requests

Docker / Self-Hosting

Run your own MonkeyTunel server with Docker.

Quick Start with Docker Compose

git clone <repo> && cd monkeytunel
# Edit docker-compose.yml with your domain and secrets
docker compose up -d

Standalone Docker

docker build -t monkeytunel .
docker run -d \
  -p 80:80 -p 443:443 -p 8080:8080 \
  -v ./data:/data \
  -v ./certs:/certs \
  -e TUNNLE_DOMAIN=tunnel.example.com \
  -e TUNNLE_JWT_SECRET=your-secret \
  monkeytunel

Server Config (TOML)

listen = ":443"
domain = "tunnel.example.com"
base_domain = "tunnel.example.com"
db_path = "/data/tunnle.db"
jwt_secret = "generate-a-strong-secret"
tls_cert = "/certs/fullchain.pem"
tls_key = "/certs/privkey.pem"
rate_limit_api = 60
rate_limit_auth = 10
bin_dir = "/data/binaries"

Cross-Compile Client Binaries

make build-all  # Builds for linux/darwin/windows x amd64/arm64

API Reference

All endpoints require Authorization: Bearer <token> except auth routes.

Authentication

POST/api/auth/loginGet tokens
POST/api/auth/refreshRefresh access token

Tunnels

GET/api/tunnelsList your tunnels
POST/api/tunnelsCreate tunnel
GET/api/tunnels/:idGet tunnel
PUT/api/tunnels/:idUpdate tunnel
DELETE/api/tunnels/:idDelete tunnel
GET/api/tunnels/:id/statusOnline status & metadata
GET/api/tunnels/:id/statsAnalytics (historical + live)
GET/api/tunnels/:id/requestsInspector: captured requests

API Keys

GET/api/apikeysList keys
POST/api/apikeysCreate key
DELETE/api/apikeys/:idRevoke key

Admin (admin only)

GET/api/admin/usersList all users
PUT/api/admin/users/:idUpdate user (quota, admin)
DELETE/api/admin/users/:idDelete user
GET/api/admin/tunnelsList all tunnels
GET/api/admin/statsSystem stats

Downloads

GET/downloadDownload page
GET/api/download/:os/:archBinary download

Create User

UserEmailRoleBandwidth LimitJoinedActions
NameProtocolRouteOwnerCreated
No tunnels in the system.