Tunr Documentation

Tunr exposes your local development server to the internet in < 3 seconds with automatic HTTPS, WebSocket support, and zero configuration. It's a developer-first alternative to ngrok and Cloudflare Tunnel.

💡

Note: tunr is a single static Go binary. It doesn't rely on Node.js or Python to run, and the CLI is fully open-source.

Quickstart

Install via Homebrew or curl, then start sharing immediately.

brew install ahmetvural79/tap/tunr
tunr share --port 3000

CLI Reference

❄️ Freeze / Snapshot Mode

If your app crashes (e.g., Node throws an exception, Database disconnects) while demoing to a client, the freeze mode will intercept the 500 error and serve the last working HTML/CSS/JS response from memory.

tunr share --port 3000 --freeze

🛡️ Read-Only Demo Mode

Prevents destructive actions. Whenever a client submits a form (POST) or clicks a delete button (DELETE), the tunr proxy safely intercepts the request, blocks it from hitting your actual local backend, and returns a simulated success response.

tunr share --port 3000 --demo

💬 Feedback Widget Injection

Every HTML page that passes through the tunnel gets a transparent feedback widget injected via proxy middleware (no code changes required on your end). Both visual UI feedback and background JavaScript exceptions are captured.

tunr share --port 3000 --inject-widget

📱 QR Code Tunnel Sharing

Generate a scannable QR code for your tunnel URL directly in the terminal. Perfect for mobile testing and quickly sharing URLs with clients or for scanning into mobile browsers.

tunr share -p 3000 --qr

🔑 Bearer Token Authentication

Protect your tunnel with a simple API key. Requests must include Authorization: Bearer <token> in the header or ?token=<value> in the query string to be served.

tunr share -p 3000 --auth-token "my-super-secret-key"

🛡️ IP Whitelisting

Restrict tunnel access to specific CIDR ranges. Only whitelisted IP addresses can reach your local server — ideal for staging environments, team access, and production testing.

# Single network
tunr share -p 3000 --allow-ip "203.0.113.0/24"

# Multiple networks
tunr share -p 3000 --allow-ip "10.0.0.0/8,172.16.0.0/12"

🔧 Live Header Modification

Add, replace, or remove HTTP headers on the fly before they reach your local server. Useful for debugging, internal routing, or stripping fingerprinting headers.

# Add headers
tunr share -p 3000 --header-add "X-Env: staging"

# Replace a header
tunr share -p 3000 --header-replace "Host: internal.local"

# Remove headers
tunr share -p 3000 --header-remove "X-Powered-By"

🔒 Password Protection

Add Basic Authentication to your public URL instantly without writing any code. Keep your development environments secure from unauthorized access while sharing with clients or third parties.

tunr share -p 8080 --password "secret"

⏳ Auto-Expiring Tunnels

Forget to stop a tunnel exposing your local machine? Use a Time-To-Live (TTL). Once the duration expires, the tunnel daemon safely terminates the connection and shuts down the proxy.

tunr share -p 3000 --ttl 1h30m

🔀 Path Routing

Map different incoming URL paths to different upstream ports on your machine. This is perfect for testing microservices or serving your frontend and API from a single public proxy domain.

tunr share --route /=3000 --route /api=8080

🤖 Model Context Protocol

Tunr supports MCP out of the box. Add it to Claude Desktop or Cursor so your AI can manage tunnels locally.

// .cursor/mcp.json
{
  "mcpServers": {
    "tunr": {
      "command": "tunr",
      "args": ["mcp"]
    }
  }
}

🔌 TCP Tunnels

Expose raw TCP services — databases, SSH servers, Redis, game servers — through secure tunnels without any HTTP parsing overhead. Perfect for PostgreSQL, MySQL, MongoDB, Redis, or any TCP-based protocol.

# Basic TCP tunnel
tunr tcp --port 5432

# TCP tunnel with QR code
tunr tcp --port 22 --qr

# TCP tunnel with IP restriction
tunr tcp --port 6379 --allow-ip 10.0.0.0/8

🌐 Multi-Region Routing

Select a preferred relay region for lower latency to specific geographic areas. Currently available regions:

CodeLocationRegion
amsAmsterdamEurope (EU)
seaSeattleUS West (Americas)
sinSingaporeAsia-Pacific
# HTTP tunnel to European clients
tunr share --port 3000 --region ams

# TCP tunnel for Asia-Pacific users
tunr tcp --port 5432 --region sin

🐍 Python SDK

Official Python SDK: pip install tunr

from tunr import TunrClient, TunnelOptions

client = TunrClient()

# Simple tunnel
tunnel = client.share(port=3000)
print(tunnel.public_url)

# With options
opts = TunnelOptions(
    subdomain="myapp",
    password="demo123",
    allow_ips=["10.0.0.0/8"],
)
tunnel = client.share(port=8080, opts=opts)

# Inspect requests
requests = client.get_requests(tunnel.id)

# Replay a request
client.replay_request(requests[0].id)

# Clean up
tunnel.close()

⚡ Node.js SDK

Official Node.js SDK: npm install @tunr/cli

import { TunrClient } from '@tunr/cli'

const client = new TunrClient()

// Simple tunnel
const tunnel = await client.share(3000)
console.log(tunnel.publicUrl)

// With options
const tunnel = await client.share(8080, {
  subdomain: 'myapp',
  password: 'demo123',
  allowIps: ['10.0.0.0/8'],
})

// Event-based lifecycle
tunnel.on('ready', () => console.log('Tunnel live'))
tunnel.on('error', (err) => console.error(err))
tunnel.on('exit', () => console.log('Tunnel closed'))

// Inspect & replay
const requests = await client.getRequests(tunnel.id)
await client.replayRequest(requests[0].id)

// Clean up
await tunnel.close()