main
md 207 lines 7.33 KB
Rendered Raw
1 # Portal - Self-Hostable Relay Tunnel for Localhost
2
3 [English](./README.md) | [简体中文](./README.zh-CN.md)
4
5 <p align="center"><img width="800" alt="Portal Demo" src="./portal.gif" /></p>
6
7 <p align="center"><b>Expose local services through self-hosted or public relays.</b><br/>No port forwarding. No inbound firewall rules. No manual DNS setup. No accounts.</p>
8
9 ## Why Portal?
10
11 Portal is a local tunnel runtime and relay network for publishing services to the agentic web.
12 It publishes local apps, APIs, tools, and agents through self-hosted or public relays,
13 keeps routing and x402 payment policy in the tunnel process, and avoids requiring a hosted vendor account.
14
15 - **Self-Hostable, Fully Open Source** - Run your own relay with a single
16 command. The relay is MIT-licensed with no enterprise tier, no feature gating,
17 and no call-home. Your relay, your rules.
18
19 - **Anonymous Relay Network** - Connect to public relays without a hosted
20 account or central operator. Combine self-hosted relays with public relays in
21 a pool to split trust across independent operators you choose.
22
23 - **End-to-End Tenant TLS And ECH** - Because relays are trustless, Portal
24 terminates tenant TLS at the user's endpoint instead of the relay. Portal also
25 provides ECH to avoid exposing the real hostname in plaintext SNI.
26
27 - **Built-in MITM Detection** - Portal actively self-probes its own connection
28 after real traffic begins. It compares TLS keying material exported on both
29 sides and treats a mismatch as suspected relay-side TLS termination.
30
31 - **Multi-Hop Relay Routing** - Chain multiple relays together so no single
32 relay knows both the origin and the destination. Use `--multi-hop-depth 3` to
33 select a three-hop route automatically.
34
35 - **No Accounts, No API Keys** - Authentication uses SIWE-compatible signing
36 with a locally generated secp256k1 key pair. No email, no registration, no
37 vendor lock-in.
38
39 - **Built-in x402 Payments** - Routed HTTP paths can require Sui gasless
40 USDC x402 payment before proxying. Browser apps can import `/x402/client.js`,
41 and native clients can call `/x402/prepare` directly and send `X-PAYMENT`.
42
43 ## Comparison
44
45 | | Portal | ngrok | Cloudflare Tunnel | frp |
46 |---|---|---|---|---|
47 | Public localhost URL | **Yes** | Yes | Yes | Yes |
48 | Self-hostable | **Yes** | Enterprise only | No | Yes |
49 | Open source | **MIT** | No | Client only | Apache 2.0 |
50 | Custom domain | **Yes** | Paid plans | Yes | Yes |
51 | End-to-end tenant TLS | **Yes** | No | No | No |
52 | SNI hiding (ECH) | **Yes** | No | No | No |
53 | MITM self-probe | **Built-in** | No | No | No |
54 | Multi-relay failover | **Yes** | Managed | Built-in | No |
55 | Multi-hop routing | **Yes** | No | No | No |
56 | Account required | **No** | Yes | Yes | No |
57 | Native x402 payments | **Yes** | No | No | No |
58
59 ## Quick Start
60
61 ### Expose a local service
62
63 **macOS / Linux:**
64
65 ```bash
66 curl -fsSL https://github.com/gosuda/portal-tunnel/releases/latest/download/install.sh | bash
67 portal expose 3000
68 ```
69
70 **Windows (PowerShell):**
71
72 ```powershell
73 $ProgressPreference = 'SilentlyContinue'
74 irm https://github.com/gosuda/portal-tunnel/releases/latest/download/install.ps1 | iex
75 portal expose 3000
76 ```
77
78 Portal prints a public HTTPS URL for your local app instantly. More examples:
79
80 ```bash
81 # Custom name and relay
82 portal expose 3000 --name myapp --relays https://portal.example.com --discovery=false
83
84 # Mount frontend and API behind one URL
85 portal expose --name myapp \
86 --http-route /api=http://127.0.0.1:3001 \
87 --http-route /=http://127.0.0.1:5173
88
89 # Require Sui USDC x402 payment before proxying a route
90 portal expose --name paid-app \
91 --http-route "/paid=http://127.0.0.1:3001 GET:0.01" \
92 --http-route /=http://127.0.0.1:5173 \
93 --x402-pay-to 0x...
94
95 # Raw TCP port (Minecraft, databases, SSH)
96 portal expose localhost:25565 --name minecraft --tcp
97
98 # Three-hop route for maximum anonymity
99 portal expose 3000 --multi-hop-depth 3
100 ```
101
102 See [CLI Reference](cmd/portal-tunnel/README.md) for the full route syntax and
103 [API Reference](docs/src/routes/api-reference/+page.md#payments) for the x402
104 helper endpoints.
105
106 ### Keep tunnels running with Portal Agent
107
108 Use `portal agent run` when tunnels should keep running outside your terminal.
109 It runs as a local OS service, keeps every tunnel in one TOML config alive, and
110 provides a dashboard for relay and multi-hop management.
111
112 ```bash
113 portal agent run --config config.toml
114 portal agent dashboard --config config.toml
115 portal agent restart
116 portal agent stop
117
118 # Foreground mode skips OS service installation.
119 portal agent run --config config.toml --foreground
120 ```
121
122 See [Portal Agent](docs/src/routes/portal-agent/+page.md) for the config format.
123
124 ### Run your own relay
125
126 ```bash
127 git clone https://github.com/gosuda/portal-tunnel
128 cd portal-tunnel && cp .env.example .env
129 docker compose up
130 ```
131
132 For public deployment with DNS automation (ACME), TCP/UDP port ranges, and relay
133 policy, see [Deployment](docs/src/routes/deployment/+page.md).
134
135 ## How End-to-End Encryption Works
136
137 ```text
138 Browser
139 -> Relay SNI router (reads only routing token, forwards raw bytes)
140 -> Reverse session
141 -> Portal tunnel (performs TLS handshake locally, derives session keys)
142 -> Local service
143 ```
144
145 1. The relay accepts the incoming connection and reads only the TLS ClientHello
146 for SNI-based routing.
147 2. It forwards the raw encrypted stream over the reverse session without
148 terminating TLS.
149 3. The Portal tunnel on your side completes the TLS handshake locally. Session
150 keys are derived on your machine.
151 4. For relay-hosted domains, the tunnel obtains certificate signatures via
152 `/v1/sign`, using the relay only as a keyless signing oracle. The relay signs
153 handshake digests but never receives session keys.
154 5. After the handshake, the relay continues forwarding ciphertext without access
155 to plaintext.
156
157 When ECH is enabled, the relay also cannot see the actual tenant hostname. It
158 routes by an opaque token derived from the tunnel identity, while the real SNI
159 stays inside the ECH-protected ClientHello.
160
161 ## How Multi-Hop Routing Works
162
163 ```text
164 Browser
165 -> Entry relay (sees only the opaque route hostname)
166 -> Middle relay (sees only the next-hop token)
167 -> Exit relay (sees only the reverse session token)
168 -> Portal tunnel
169 -> Local service
170 ```
171
172 Each relay in the chain knows only its immediate neighbors. No single relay
173 holds the full path. Tenant TLS still terminates only on your side, so no relay
174 in the chain receives tenant TLS plaintext.
175
176 ## Public Relay Registry
177
178 Portal's official public relay registry is:
179
180 ```text
181 https://raw.githubusercontent.com/gosuda/portal-tunnel/main/registry.json
182 ```
183
184 Tunnel clients include this registry by default. If you operate a public Portal
185 relay, open a pull request to add your relay URL to `registry.json`.
186
187 ## Documentation
188
189 - [CLI Reference](cmd/portal-tunnel/README.md)
190 - [Concepts](docs/src/routes/concepts/+page.md)
191 - [Portal Agent](docs/src/routes/portal-agent/+page.md)
192 - [Wallet and ENS](docs/src/routes/wallet-and-ens/+page.md)
193 - [Security Model](docs/src/routes/security-model/+page.md)
194 - [Architecture](docs/src/routes/architecture/+page.md)
195 - [Deployment](docs/src/routes/deployment/+page.md)
196 - [Configuration Reference](docs/src/routes/configuration/+page.md)
197
198 ## Contributing
199
200 1. Fork the repository.
201 2. Create a feature branch (`git checkout -b feature/amazing-feature`).
202 3. Make the change with focused tests or docs.
203 4. Open a pull request.
204
205 ## License
206
207 MIT License - see [LICENSE](LICENSE).