main
md 198 lines 6.38 KB
Rendered Raw
1 ---
2 title: Concepts
3 description: Understand Portal's relay model, transport modes, and end-to-end TLS design.
4 ---
5
6 # Concepts
7
8 Portal publishes local services through relay servers. The important design
9 choice is that the relay is a transport and routing component, not the owner of
10 your application traffic.
11
12 ## Relay And Tunnel Responsibilities
13
14 The relay owns:
15
16 - lease registration and renewal
17 - public hostname and port routing
18 - SNI route lookup for the default stream path
19 - relay discovery and relay-to-relay forwarding
20 - admin policy such as approval, bans, and transport limits
21
22 The tunnel process owns:
23
24 - tenant TLS termination for the default HTTPS stream path
25 - local target proxying
26 - routed HTTP reverse proxy behavior
27 - UDP target forwarding
28 - identity keys and lease signing
29 - MITM self-probe validation
30
31 This split is why Portal can use public relays without giving relay operators
32 tenant plaintext.
33
34 ## Default Stream Path
35
36 The default command is:
37
38 ```bash
39 portal expose 3000
40 ```
41
42 The public URL is HTTPS, but the relay does not terminate tenant TLS.
43
44 ```text
45 Browser
46 -> Relay :443
47 -> reverse session
48 -> tunnel process TLS server
49 -> 127.0.0.1:3000
50 ```
51
52 Flow:
53
54 1. A browser connects to the relay and sends a TLS ClientHello.
55 2. The relay reads the SNI hostname and finds the matching lease.
56 3. The relay claims a waiting reverse session from the tunnel process.
57 4. The tunnel process performs the tenant TLS handshake locally.
58 5. The relay may sign handshake digests through `/v1/sign`, but it does not
59 receive tenant TLS session keys.
60 6. After the handshake, the relay forwards encrypted bytes.
61
62 ## Routed HTTP Mode
63
64 Routed HTTP mode mounts one or more local HTTP upstreams behind one public URL:
65
66 ```bash
67 portal expose --name myapp \
68 --http-route /api=http://127.0.0.1:3001 \
69 --http-route /=http://127.0.0.1:5173
70 ```
71
72 This is not relay-side HTTP proxying. The relay still transports the connection.
73 The tunnel process receives the stream, parses HTTP, and runs the reverse proxy.
74
75 Routed HTTP mode can:
76
77 - match routes longest-prefix-first
78 - strip the mounted prefix before proxying
79 - forward `X-Forwarded-*`
80 - rewrite matching upstream `Location` redirects
81 - strip loopback cookie domains
82 - remap cookie paths to route prefixes
83
84 Because HTTP is parsed in the tunnel process, this is the right place for
85 cooperative HTTP policy such as response headers. It is not a relay-enforced
86 policy boundary.
87
88 Paid routes are also owned by routed HTTP mode. Add `--x402-pay-to` and attach
89 the amount to the HTTP route:
90
91 ```bash
92 portal expose --name paid-app \
93 --http-route "/paid=http://127.0.0.1:3001 GET:0.01" \
94 --http-route /=http://127.0.0.1:5173 \
95 --x402-pay-to 0x...
96 ```
97
98 The tunnel serves `/x402/client.js` and `/x402/prepare` on the same public
99 origin. A browser frontend mounted through the tunnel can import
100 `/x402/client.js` and call `x402Fetch()` from its own UI, so the Sui wallet flow
101 stays in the app instead of requiring a separate payment redirect. Native
102 clients use `/x402/prepare` directly and send the signed payload as
103 `X-PAYMENT`. The tunnel still verifies and settles the payment before proxying
104 the protected request. Paid routes use Sui mainnet by default; add
105 `--x402-testnet` for Sui testnet.
106
107 ## Dedicated Raw TCP
108
109 Use raw TCP when clients need a public TCP port instead of a public HTTPS
110 hostname:
111
112 ```bash
113 portal expose localhost:25565 --name minecraft --tcp
114 ```
115
116 The relay allocates a port from its configured range and bridges raw TCP to the
117 tunnel process. This is useful for Minecraft, game servers, and custom TCP
118 protocols. The raw TCP path does not add TLS; use protocol-level encryption when
119 needed.
120
121 ## UDP Relay
122
123 Use UDP mode for datagram protocols:
124
125 ```bash
126 portal expose localhost:8080 --udp --udp-addr localhost:19132
127 ```
128
129 The relay allocates a UDP port and carries datagrams over the tunnel backhaul to
130 the local UDP target. The positional target is still used for stream traffic;
131 `--udp-addr` selects the local UDP service.
132
133 ## Multi-Relay And Multi-Hop
134
135 With discovery enabled, Portal starts from the public registry plus explicit
136 relays, then expands through relay discovery. Explicit relays are always kept
137 connected separately from the auto-selected relay pool.
138
139 Use a fixed ordered route:
140
141 ```bash
142 portal expose 3000 --multi-hop https://entry.example.com,https://exit.example.com
143 ```
144
145 Or ask Portal to choose one route of a given depth:
146
147 ```bash
148 portal expose 3000 --multi-hop-depth 3
149 ```
150
151 Multi-hop currently applies to the default SNI TLS stream transport. It is not
152 combined with UDP or dedicated raw TCP port mode.
153
154 ## MITM Self-Probe
155
156 Portal runs a TLS passthrough self-probe after real stream traffic starts:
157
158 1. The tunnel opens a client connection to its own public URL.
159 2. The tunnel also receives that connection as the tenant TLS server.
160 3. Both controlled ends export TLS keying material.
161 4. Matching exporter values indicate passthrough for that sampled connection.
162 5. A mismatch is treated as suspected relay-side TLS termination.
163
164 By default, `portal expose` logs self-probe detections without banning the relay.
165 Use `--ban-mitm` when suspected TLS termination should ban the relay.
166
167 The probe is a detection signal, not a mathematical proof for every future
168 connection. It raises the cost of relay-side termination while preserving the
169 transport model.
170
171 ## Identity And Lease Authentication
172
173 On first run, Portal creates a local secp256k1 identity at `identity.json` unless
174 you pass another `--identity-path`.
175
176 Lease registration uses challenge signing. After registration, the relay issues
177 a lease-scoped access token used for renew, unregister, reverse connect, and
178 datagram authentication.
179
180 Reusing the same identity path keeps the same tunnel identity across runs.
181
182 Relay admin token login and optional browser wallet login for local agent status
183 are both separate from tunnel registration. See
184 [Wallet and ENS](/wallet-and-ens) for the distinction.
185
186 ## Domain Boundary
187
188 The default stream path prevents the relay from safely injecting `robots.txt`,
189 `noindex`, or arbitrary HTTP headers into user responses. That is a feature of
190 the trust model, but it also means public multi-tenant relays should use a
191 separate wildcard tunnel domain instead of a brand or docs domain.
192
193 ## Next Steps
194
195 - [Getting Started](/getting-started): run your first tunnel
196 - [Portal Agent](/portal-agent): run durable tunnel configs
197 - [CLI Reference](/cli-reference): command and flag details
198 - [Architecture](/architecture): protocol-level design notes