You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: README.md
+14-1Lines changed: 14 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -18,11 +18,24 @@ Unlike other tunneling services, Portal is self-hosted and permissionless. You c
18
18
19
19
-**NAT-friendly connectivity**: Works behind NAT or firewalls without opening inbound ports
20
20
-**Automatic subdomain routing**: Gives each app its own subdomain (`your-app.<base-domain>`)
21
-
-**End-to-end encryption**: Supports TLS passthrough with relay keyless certificates
21
+
-**End-to-end tenant TLS**: Relay routes by SNI, while tenant TLS terminates on your side with relay-backed keyless signing
22
22
-**Permissionless Hosting**: Anyone can run their own Portal — no approval needed
23
23
-**One-Command Setup**: Expose any local app with a single command
24
24
-**UDP Relay (Experimental)**: Supports raw UDP relay use cases, but the transport model and operational behavior may still change
25
25
26
+
## How Portal Provides End-to-End Encryption
27
+
28
+
Portal is designed so that tenant TLS terminates on your side rather than at the relay. In the normal data path, the relay forwards encrypted traffic without access to tenant TLS plaintext.
29
+
30
+
1. The relay accepts the public connection and reads only the TLS ClientHello required for SNI-based routing.
31
+
2. It forwards the tenant connection as raw encrypted bytes over the reverse session without terminating tenant TLS.
32
+
3. The Portal client on your side acts as the TLS server and completes the tenant handshake locally.
33
+
4. For relay-hosted domains, the Portal client obtains certificate signatures via `/v1/sign`, using the relay only as a keyless signing oracle.
34
+
5. Session keys are derived entirely on your side. The relay provides certificate signatures only and does not receive tenant traffic secrets.
35
+
6. After the handshake, the relay continues forwarding ciphertext without needing tenant TLS plaintext to keep routing traffic.
36
+
37
+
Portal also checks that the relay is preserving TLS passthrough. The Portal client connects to its own public endpoint and compares TLS exporter values observed on both client-controlled ends. If they differ, Portal logs suspected TLS termination by default. You can switch to strict enforcement with `portal expose --ban-mitm`.
38
+
26
39
## Components
27
40
28
41
-**Relay**: A server that routes public requests to the right connected app.
utils.StringFlagEnv(fs, &cfg.relayURLs, "relays", "https://gosunuts.xyz", "additional relay API URLs (comma-separated; scheme omitted defaults to https; merged with public registry relays when discovery is enabled)", "RELAYS")
50
51
utils.BoolFlagEnv(fs, &cfg.discovery, "discovery", true, "include public registry relays and enable discovery", "DISCOVERY")
52
+
utils.BoolFlagEnv(fs, &cfg.banMITM, "ban-mitm", false, "ban relay when the MITM self-probe detects TLS termination", "BAN_MITM")
51
53
utils.StringFlag(fs, &cfg.addr, "addr", "127.0.0.1:8092", "local demo HTTP listen address (host:port or URL; disable if empty)")
52
54
utils.StringFlag(fs, &cfg.name, "name", "demo-app", "public hostname prefix (single DNS label)")
utils.StringFlagEnv(fs, &cfg.relayURLs, "relays", "https://localhost:4017", "additional relay API URLs (comma-separated; scheme omitted defaults to https; merged with public registry relays when discovery is enabled)", "RELAYS")
81
83
utils.BoolFlagEnv(fs, &cfg.discovery, "discovery", true, "include public registry relays and enable discovery", "DISCOVERY")
84
+
utils.BoolFlagEnv(fs, &cfg.banMITM, "ban-mitm", false, "ban relay when the MITM self-probe detects TLS termination", "BAN_MITM")
82
85
utils.StringFlag(fs, &cfg.name, "name", "demo-udp", "public hostname prefix (single DNS label)")
-`--name` is optional. When omitted, the CLI generates a name for that run.
38
38
-`--relays` sets the relay API URLs for that run.
39
39
-`--discovery=false` disables the public registry seed list and the discovery expansion loop for that run.
40
+
-`--ban-mitm` enables strict rejection when the TLS self-probe detects termination in the path.
40
41
41
42
Flags:
42
43
43
44
```text
44
45
--relays Portal relay API URLs (comma-separated, https only)
45
46
--discovery Include public registry relays and discover additional relay bootstraps
47
+
--ban-mitm Ban relay when the MITM self-probe detects TLS termination
46
48
--name Public hostname prefix (single DNS label); auto-generated when omitted
47
49
--description Service description metadata
48
50
--tags Service tags metadata (comma-separated)
@@ -80,4 +82,5 @@ Legacy execution compatibility has been removed:
80
82
- With discovery enabled, the configured relay list starts with `public registry + --relays values` and can expand through relay discovery. With `--discovery=false`, only the explicit relay URLs are used. Published public URLs appear only for relays that have registered successfully.
81
83
- SDK callers that do not set `ListenerConfig.RetryCount` use infinite retry semantics for each relay.
82
84
- Tenant TLS is provisioned automatically through the relay keyless signer. The SDK fetches the relay certificate chain and uses `/v1/sign` for remote signing.
85
+
- TLS self-probe mismatches log warnings by default. Use `--ban-mitm` to reject relays that terminate tenant TLS.
83
86
- When the local service is unreachable, the tunnel returns an HTTP 503 page.
0 commit comments