Sandbox
@gosuda/portal-tunnel

Localhost tunnel and relay tool for agent workflows

Portal publishes local services through self-hosted or public relays, so you can share a localhost app without port forwarding, inbound firewall changes, or a hosted tunnel account. The tunnel process handles routing, end-to-end tenant TLS, ECH, and optional x402 payment gates.

267 stars28 forksGoUpdated 6d ago
Who it's for

Builders who want their local services, tools, or agents reachable through Portal while they work in Claude Code, Codex, or Cursor.

What it delivers

You can expose a local app or API on a public URL and keep control over routing, trust, and payment rules.

What it does

Self-hosted relay support

You can run your own relay with `docker compose up` and avoid depending on a vendor operator.

Local tunnel exposure

`portal expose 3000` publishes a localhost service and prints a public HTTPS URL.

Multi-route publishing

You can map multiple local services under one public name with `--http-route`.

x402 payment gates

The tunnel can require payment before proxying a route, using `--x402-pay-to` and route payment rules.

Agent plugin and skill bundle

The repo includes installable assets for Codex, Claude Code, and Cursor, plus a shared `portal-expose` skill.

Persistent tunnel management

`portal agent run`, `dashboard`, `restart`, and `stop` manage long-running tunnels from a TOML config.

How to get it

  1. 1Install the skill with either CLI
    # GitHub CLI
    gh skill install gosuda/portal-tunnel portal-deploy/portal-expose
    
    # skills CLI
    npx skills add gosuda/portal-tunnel --skill portal-expose
  2. 2macOS / Linux
    curl -fsSL https://github.com/gosuda/portal-tunnel/releases/latest/download/install.sh | bash
    portal expose 3000
  3. 3Windows (PowerShell)
    $ProgressPreference = 'SilentlyContinue'
    irm https://github.com/gosuda/portal-tunnel/releases/latest/download/install.ps1 | iex
    portal expose 3000
  4. 4Use Portal Agent directly when tunnels should keep running outside your terminal. It…
    portal agent run --config config.toml
    portal agent dashboard --config config.toml
    portal agent restart --config config.toml
    portal agent stop --config config.toml
    
    # Foreground mode skips OS service installation.
    portal agent run --config config.toml --foreground
  5. 5Run
    git clone https://github.com/gosuda/portal-tunnel
    cd portal-tunnel && cp .env.example .env
    docker compose up

README

Portal

Portal - Self-Hostable Relay Tunnel for Localhost

CI GitHub Release License awesome-tunneling

English | 简体中文

Portal Demo

Expose local services through self-hosted or public relays.
No port forwarding. No inbound firewall rules. No manual DNS setup. No accounts.

Why Portal?

Portal is a local tunnel runtime and relay network for publishing services to the agentic web. It publishes local apps, APIs, tools, and agents through self-hosted or public relays, keeps routing and x402 payment policy in the tunnel process, and avoids requiring a hosted vendor account.

  • Self-Hostable, Fully Open Source - Run your own relay with a single command. The relay is MIT-licensed with no enterprise tier, no feature gating, and no call-home. Your relay, your rules.

  • Anonymous Relay Network - Connect to public relays without a hosted account or central operator. Combine self-hosted relays with public relays in a pool to split trust across independent operators you choose.

  • End-to-End Tenant TLS And ECH - Because relays are trustless, Portal terminates tenant TLS at the user's endpoint instead of the relay. Portal also provides ECH to avoid exposing the real hostname in plaintext SNI.

  • Built-in MITM Detection - Portal actively self-probes its own connection after real traffic begins. It compares TLS keying material exported on both sides and treats a mismatch as suspected relay-side TLS termination.

  • No Accounts, No API Keys - Authentication uses SIWE-compatible signing with a locally generated secp256k1 key pair. No email, no registration, no vendor lock-in.

  • Built-in x402 Payments - Routed HTTP paths can require Sui gasless USDC or Casper wCSPR x402 payment before proxying. Browser apps can import /x402/client.js, and native clients can call /x402/prepare directly and send X-PAYMENT.

Comparison

PortalngrokCloudflare Tunnelfrp
Public localhost URLYesYesYesYes
Self-hostableYesEnterprise onlyNoYes
Open sourceMITNoClient onlyApache 2.0
Custom domainYesPaid plansYesYes
End-to-end tenant TLSYesNoNoNo
SNI hiding (ECH)YesNoNoNo
MITM self-probeBuilt-inNoNoNo
Multi-relay failoverYesManagedBuilt-inNo
Account requiredNoYesYesNo
Native x402 paymentsYesNoNoNo

Quick Start

Use the local AI agent plugin

The repository includes a portal-deploy plugin for Codex, Claude Code, and Cursor. The shared portal-expose skill inspects a local app, opens a Portal tunnel, configures explicitly requested x402 paid routes, verifies the public URL and payment challenge, and hands off the lifecycle.

Install the skill with either CLI:

# GitHub CLI
gh skill install gosuda/portal-tunnel portal-deploy/portal-expose

# skills CLI
npx skills add gosuda/portal-tunnel --skill portal-expose

Then ask your agent:

  • Temporary preview: “Expose this app with Portal and verify the public URL.”
  • x402 paid route: “Expose this app with Portal, protect GET /paid with x402, and verify the payment challenge.”
  • Persistent tunnel: “Keep this app available with a persistent Portal agent tunnel and verify the public URL.”

Host-specific Codex, Claude Code, and Cursor marketplace setup is in plugins/portal-deploy/README.md.

Expose a local service

macOS / Linux:

curl -fsSL https://github.com/gosuda/portal-tunnel/releases/latest/download/install.sh | bash
portal expose 3000

Windows (PowerShell):

$ProgressPreference = 'SilentlyContinue'
irm https://github.com/gosuda/portal-tunnel/releases/latest/download/install.ps1 | iex
portal expose 3000

Portal prints a public HTTPS URL for your local app instantly. More examples:

# Custom name and relay
portal expose 3000 --name myapp --relays https://portal.example.com --discovery=false

# Prefer IVNP overlay transport when available
portal expose 3000 --overlay

# Mount frontend and API behind one URL
portal expose --name myapp \
  --http-route /api=http://127.0.0.1:3001 \
  --http-route /=http://127.0.0.1:5173

# Require Sui USDC x402 payment before proxying a route
portal expose --name paid-app \
  --http-route "/paid=http://127.0.0.1:3001 GET:0.01" \
  --http-route /=http://127.0.0.1:5173 \
  --x402-pay-to 0x...

# Raw TCP port (Minecraft, databases, SSH)
portal expose localhost:25565 --name minecraft --tcp

See CLI Reference for the full route syntax and API Reference for the x402 helper endpoints.

Manage persistent tunnels manually

Use Portal Agent directly when tunnels should keep running outside your terminal. It runs as a local OS service, keeps every tunnel in one TOML config alive, and provides a dashboard for public relay management.

portal agent run --config config.toml
portal agent dashboard --config config.toml
portal agent restart --config config.toml
portal agent stop --config config.toml

# Foreground mode skips OS service installation.
portal agent run --config config.toml --foreground

See Portal Agent for the config format.

Run your own relay

git clone https://github.com/gosuda/portal-tunnel
cd portal-tunnel && cp .env.example .env
docker compose up

For public deployment with DNS automation (ACME), TCP/UDP port ranges, and relay policy, see Deployment.

How End-to-End Encryption Works

Browser
  -> Relay SNI router  (reads only routing token, forwards raw bytes)
  -> Reverse session
  -> Portal tunnel     (performs TLS handshake locally, derives session keys)
  -> Local service
  1. The relay accepts the incoming connection and reads only the TLS ClientHello for SNI-based routing.
  2. It forwards the raw encrypted stream over the reverse session without terminating TLS.
  3. The Portal tunnel on your side completes the TLS handshake locally. Session keys are derived on your machine.
  4. For relay-hosted domains, the tunnel obtains certificate signatures via /v1/sign, using the relay only as a keyless signing oracle. The relay signs handshake digests but never receives session keys.
  5. After the handshake, the relay continues forwarding ciphertext without access to plaintext.

When ECH is enabled, the relay also cannot see the actual tenant hostname. It routes by an opaque token derived from the tunnel identity, while the real SNI stays inside the ECH-protected ClientHello.

Public Relay Registry

Portal's official public relay registry is:

https://raw.githubusercontent.com/gosuda/portal-tunnel/main/registry.json

Tunnel clients include this registry by default. If you operate a public Portal relay, open a pull request to add your relay URL to registry.json.

Documentation

Contributing

See CONTRIBUTING.md.

License

MIT License - see LICENSE.

Files in the repo

Repository payload35 top-level entries
  • .agents
  • .claude-plugin
  • .cursor-plugin
  • .github
  • cmd
  • docs
  • extensions
  • frontend
  • plugins
  • portal
  • sdk
  • types
  • utils
  • .dockerignore
  • .env.example
  • .gitignore
  • .golangci.yml
  • .pre-commit-config.yaml
  • AGENTS.md
  • CLAUDE.md
  • config.toml
  • CONTRIBUTING.md
  • docker-compose.yml
  • Dockerfile
  • go.mod
  • go.sum
  • LICENSE
  • llms.txt
  • logo.png
  • Makefile
  • manifest.go
  • portal.gif
  • README.md
  • README.zh-CN.md
  • registry.json

Discussion (0)

Ask about usage, or say what you built with it

Sign in to join the discussion.

No comments yet. Be the first to say what this is good for.

More tools

JuliusBrussee/
caveman

🪨 why use many token when few token do trick — Claude Code skill that cuts 65% of tokens by talking like caveman

105k
1 add
MemPalace/
mempalace

The best-benchmarked open-source AI memory system. And it's free.

59k
stablyai/
orca

Orca is the ADE for working with a fleet of parallel agents. Run any coding agent with your own subscription. Available on desktop, mobile and remote runtime.

66k

A cross-platform desktop All-in-One assistant for Claude Code, Codex, OpenCode, OpenClaw, Grok Build & Hermes Agent. Only official website: ccswitch.io

132k

Never stop coding. Free MIT AI gateway: one endpoint, 352 providers (150+ free), 1200+ models Kimi, Claude, GPT, Gemini, GLM, DeepSeek, MiniMax. Works with Claude Code, Codex, Cursor, OpenCode, Cline & Copilot. Quota-aware auto-fallback, RTK+Caveman compression saves 15-95% tokens, MCP/A2A, Desktop/PWA. Built by 550+ contributors

64k
headroomlabs-ai/
headroom

Compress tool outputs, logs, files, and RAG chunks before they reach the LLM. 20% fewer tokens for coding agents, 60-95% fewer tokens for JSON, same answers. Library, proxy, MCP server.

71k