Skip to content

API Reference

Tunnel Whisperer exposes two APIs: a REST/WebSocket API served by the dashboard for browser and HTTP clients, and a gRPC API for CLI-to-daemon communication.


REST API (Dashboard)

The dashboard HTTP server registers the endpoints listed below. All REST endpoints accept and return JSON unless noted otherwise.

Read-only

Method Path Description
GET /api/status Current daemon status (mode, version, relay, server/client state)
GET /api/config Current configuration (sanitized)
GET /api/relay Relay provisioning status (provisioned, domain, IP, provider)
GET /api/providers List of supported cloud providers for relay provisioning
GET /api/stats Bandwidth statistics snapshots and history (returns enabled: false when analytics is off)
GET /metrics Prometheus-format bandwidth metrics

Mode

Method Path Description
POST /api/mode Set the operating mode (server or client)

Request body:

{ "mode": "server" }

Settings

Method Path Description
POST /api/proxy Set or clear the outbound proxy URL
POST /api/log-level Set the log level (debug, info, warn, error)
POST /api/settings/server Update server settings (ports, relay SSH user, temp Xray port)
POST /api/settings/xray Update Xray transport settings (relay host, port, path)
POST /api/settings/client Update client settings (SSH user, server SSH port)
POST /api/settings/analytics Enable/disable analytics and set history size

Proxy request body:

{ "proxy": "socks5://host:1080" }

Log level request body:

{ "log_level": "debug" }

Server settings request body:

{
  "ssh_port": 2222,
  "api_port": 50051,
  "dashboard_port": 8080,
  "relay_ssh_port": 22,
  "relay_ssh_user": "ubuntu",
  "remote_port": 2222,
  "temp_xray_port": 59000
}

Only non-zero / non-empty fields are applied; omitted fields keep their current value.

Xray settings request body:

{
  "relay_host": "relay.example.com",
  "relay_port": 443,
  "path": "/tw"
}

Client settings request body:

{
  "ssh_user": "tunnel",
  "server_ssh_port": 2222
}

Analytics settings request body:

{
  "enabled": true,
  "history_size": 720
}

Analytics changes take effect immediately — no restart required. The stats collector is created or destroyed on the fly.

Restart required

Settings changes are persisted to config.yaml immediately. A restart (server) or reconnect (client) is needed for most changes to take effect. Exception: analytics settings take effect immediately.

Server control

Method Path Description
POST /api/server/start Start all server components (SSH, Xray, reverse tunnel)
POST /api/server/stop Stop the server
POST /api/server/restart Stop and restart the server

Client control

Method Path Description
POST /api/client/start Start the client (Xray + SSH tunnel)
POST /api/client/stop Stop the client
POST /api/client/reconnect Disconnect and reconnect the client
POST /api/client/upload Upload a user config bundle (.zip) to configure the client

Upload: POST /api/client/upload expects a multipart/form-data body with the zip file.

Relay management

Method Path Description
POST /api/relay/test-creds Validate cloud provider credentials
POST /api/relay/provision Provision a new relay server via Terraform
POST /api/relay/destroy Destroy the provisioned relay server
POST /api/relay/test Run connectivity tests against the relay
POST /api/relay/generate-script Generate a manual setup script for the relay
POST /api/relay/save-manual Save relay details from a manual (non-Terraform) setup
WS /api/relay/ssh WebSocket-based interactive SSH shell to the relay server

Provision request body:

{
  "domain": "relay.example.com",
  "provider": "digitalocean",
  "token": "dop_v1_..."
}

WebSocket: /api/relay/ssh

This endpoint upgrades to a WebSocket connection and provides a full interactive terminal session to the relay server. The dashboard uses xterm.js to render the terminal in the browser.

User management

Method Path Description
GET /api/users List all configured users
POST /api/users Create a new user
DELETE /api/users/{name} Delete a user by name
PUT /api/users/{name}/mappings Update a user's port mappings
GET /api/users/{name}/download Download a user's config bundle as a .zip file
POST /api/users/apply Apply user changes (regenerate authorized_keys)
POST /api/users/unregister Unregister users from the server
GET /api/users/online List currently connected users

Create user request body:

{
  "name": "alice",
  "mappings": [
    { "client_port": 3389, "server_port": 3389 },
    { "client_port": 8443, "server_port": 443 }
  ]
}

Update user mappings request body:

{
  "mappings": [
    { "client_port": 3389, "server_port": 3389 },
    { "client_port": 8443, "server_port": 443 }
  ]
}

After updating, the user's authorized_keys entry is rewritten with new permitopen restrictions and a config outdated flag is set. The flag is cleared when the user's config bundle is downloaded.

Download response: application/zip binary with Content-Disposition header.

Application templates

Method Path Description
GET /api/apps List all application templates
POST /api/apps Create a new application template
PUT /api/apps/{name} Update an application template
DELETE /api/apps/{name} Delete an application template

Create/update application request body:

{
  "name": "web-app",
  "mappings": [
    { "client_port": 3000, "server_port": 3000 },
    { "client_port": 5432, "server_port": 5432 }
  ]
}

Application templates are reusable port mapping bundles. They are stored in config.yaml under server.applications and are not synced to the relay.

Server-Sent Events (SSE)

Method Path Description
GET /api/events/{session_id} SSE stream of daemon events (status changes, progress)
GET /api/logs SSE stream of real-time log output

The {session_id} parameter identifies a browser session so multiple dashboard tabs can each receive events independently.

Event format:

event: status
data: {"mode":"server","server":{"state":"running",...}}

event: progress
data: {"step":2,"total":5,"label":"Starting Xray","status":"running"}

gRPC API

The gRPC API listens on port 50051 (configurable via server.api_port) and is used for CLI-to-daemon communication. When a daemon is running (via tw serve or tw dashboard), CLI commands like tw status, tw list users, and tw delete user connect to this API instead of reading state directly from disk.

Note

The gRPC API is an internal interface. It is not intended for external consumption and its protobuf schema may change between versions. Use the REST API for integrations.

Available RPC methods

Method Description
GetStatus Returns current mode, relay status, server/client state, user count
ListUsers Returns all configured users with their tunnel mappings
DeleteUser Deletes a user by name
GetUserConfig Returns a user's config bundle as a zip byte stream
TestRelay Runs relay connectivity tests and returns step-by-step results
DestroyRelay Destroys the provisioned relay (accepts cloud credentials)

The gRPC server starts automatically when running tw serve or tw dashboard.