main
md 177 lines 7.54 KB
Rendered Raw
1 # Portal - 面向 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>通过自托管或公共中继公开本地服务。</b><br/>无需端口转发。无需入站防火墙规则。无需手动 DNS 配置。无需账户。</p>
8
9 ## 为什么选择 Portal?
10
11 Portal 是一个本地隧道运行时和中继网络。它通过自托管或公共中继发布本地服务,把路由策略保留在隧道进程中,并避免依赖托管式厂商账户。
12
13 - **自托管,完全开源** - 用一条命令运行你自己的中继。中继采用 MIT 许可证,没有企业版层级,没有功能门槛,也不会回传遥测。你的中继,你的规则。
14
15 - **匿名中继网络** - 无需托管账户或中心化运营方即可连接公共中继。你可以把自托管中继和公共中继组合到一个池中,把信任拆分给你选择的多个独立运营方。
16
17 - **端到端租户 TLS 和 ECH** - 因为中继是不可信的,Portal 会在用户端点而不是中继处终止租户 TLS。Portal 还提供 ECH,避免真实主机名以明文 SNI 暴露。
18
19 - **内置 MITM 检测** - Portal 会在真实流量开始后主动自探测自己的连接。它会比较两端导出的 TLS 密钥材料,并把不匹配视为疑似中继侧 TLS 终止。
20
21 - **多跳中继路由** - 将多个中继串联起来,使单个中继无法同时知道来源和目的地。使用 `--multi-hop-depth 3` 可以自动选择三跳路由。
22
23 - **无账户,无 API Key** - 身份认证使用本地生成的 secp256k1 密钥对进行 SIWE 兼容签名。无需邮箱,无需注册,也没有厂商锁定。
24
25 - **原生 x402 支付** - Routed HTTP 路径可以在代理前要求 Sui gasless USDC x402 支付。浏览器应用可以导入 `/x402/client.js`,原生客户端可以直接调用 `/x402/prepare` 并发送 `X-PAYMENT`
26
27 ## 对比
28
29 | | Portal | ngrok | Cloudflare Tunnel | frp |
30 |---|---|---|---|---|
31 | 公共 localhost URL | **是** | 是 | 是 | 是 |
32 | 可自托管 | **是** | 仅企业版 | 否 | 是 |
33 | 开源 | **MIT** | 否 | 仅客户端 | Apache 2.0 |
34 | 自定义域名 | **是** | 付费套餐 | 是 | 是 |
35 | 端到端租户 TLS | **是** | 否 | 否 | 否 |
36 | SNI 隐藏 (ECH) | **是** | 否 | 否 | 否 |
37 | MITM 自探测 | **内置** | 否 | 否 | 否 |
38 | 多中继故障切换 | **是** | 托管 | 内置 | 否 |
39 | 多跳路由 | **是** | 否 | 否 | 否 |
40 | 需要账户 | **否** | 是 | 是 | 否 |
41 | 原生 x402 支付 | **是** | 否 | 否 | 否 |
42
43 ## 快速开始
44
45 ### 公开本地服务
46
47 **macOS / Linux:**
48
49 ```bash
50 curl -fsSL https://github.com/gosuda/portal-tunnel/releases/latest/download/install.sh | bash
51 portal expose 3000
52 ```
53
54 **Windows (PowerShell):**
55
56 ```powershell
57 $ProgressPreference = 'SilentlyContinue'
58 irm https://github.com/gosuda/portal-tunnel/releases/latest/download/install.ps1 | iex
59 portal expose 3000
60 ```
61
62 Portal 会立即为你的本地应用打印一个公共 HTTPS URL。更多示例:
63
64 ```bash
65 # 自定义名称和中继
66 portal expose 3000 --name myapp --relays https://portal.example.com --discovery=false
67
68 # 把前端和 API 挂到同一个 URL 后面
69 portal expose --name myapp \
70 --http-route /api=http://127.0.0.1:3001 \
71 --http-route /=http://127.0.0.1:5173
72
73 # 在代理某个路由前要求 Sui USDC x402 支付
74 portal expose --name paid-app \
75 --http-route "/paid=http://127.0.0.1:3001 GET:0.01" \
76 --http-route /=http://127.0.0.1:5173 \
77 --x402-pay-to 0x...
78
79 # 原始 TCP 端口(Minecraft、数据库、SSH)
80 portal expose localhost:25565 --name minecraft --tcp
81
82 # 三跳路由,获得更高匿名性
83 portal expose 3000 --multi-hop-depth 3
84 ```
85
86 对于付费路由,支付策略运行在隧道进程内,而不是中继上。默认使用 Sui mainnet;加上 `--x402-testnet` 可切换到 Sui testnet,这个选择与中继自身的支付设置无关。隧道会在同一个公共 origin 上提供 `/x402/client.js``/x402/prepare`。浏览器前端可以导入 `/x402/client.js` 并调用 `x402Fetch()`;原生客户端可以直接调用 `/x402/prepare`,用自己的 Sui 运行时签名返回的交易,并发送签名后的 `X-PAYMENT`
87
88 完整路由语法请参阅 [CLI Reference](cmd/portal-tunnel/README.md),x402 helper endpoint 请参阅 [API Reference](docs/src/routes/api-reference/+page.md#payments)
89
90 ### 使用 Portal Agent 持续运行隧道
91
92 当隧道需要在终端之外持续运行时,使用 `portal agent run`。它会作为本地 OS 服务运行,在一个 TOML 配置中保持所有隧道在线,并提供用于中继和多跳管理的 dashboard。
93
94 ```bash
95 portal agent run --config config.toml
96 portal agent dashboard --config config.toml
97 portal agent restart
98 portal agent stop
99
100 # 前台模式会跳过 OS 服务安装。
101 portal agent run --config config.toml --foreground
102 ```
103
104 配置格式请参阅 [Portal Agent](docs/src/routes/portal-agent/+page.md)
105
106 ### 运行你自己的中继
107
108 ```bash
109 git clone https://github.com/gosuda/portal-tunnel
110 cd portal-tunnel && cp .env.example .env
111 docker compose up
112 ```
113
114 关于带 DNS 自动化(ACME)、TCP/UDP 端口范围和中继策略的公网部署,请参阅 [Deployment](docs/src/routes/deployment/+page.md)
115
116 ## 端到端加密如何工作
117
118 ```text
119 Browser
120 -> Relay SNI router (只读取路由 token,转发原始字节)
121 -> Reverse session
122 -> Portal tunnel (在本地执行 TLS 握手,派生 session key)
123 -> Local service
124 ```
125
126 1. 中继接受传入连接,并只读取 TLS ClientHello 中用于 SNI 路由的信息。
127 2. 中继通过反向 session 转发原始加密流,而不终止 TLS。
128 3. 你这边的 Portal 隧道在本地完成 TLS 握手。Session key 在你的机器上派生。
129 4. 对于中继托管域名,隧道会通过 `/v1/sign` 获取证书签名,把中继仅用作 keyless signing oracle。中继签署握手摘要,但永远不会接收 session key。
130 5. 握手完成后,中继继续转发密文,无法访问明文。
131
132 启用 ECH 时,中继也看不到真实租户主机名。它会通过从隧道身份派生出的不透明 token 进行路由,而真实 SNI 保留在 ECH 保护的 ClientHello 中。
133
134 ## 多跳路由如何工作
135
136 ```text
137 Browser
138 -> Entry relay (只看到不透明 route hostname)
139 -> Middle relay (只看到 next-hop token)
140 -> Exit relay (只看到 reverse session token)
141 -> Portal tunnel
142 -> Local service
143 ```
144
145 链中的每个中继只知道自己的直接相邻节点。没有任何单个中继掌握完整路径。租户 TLS 仍然只在你这边终止,因此链中的任何中继都不会收到租户 TLS 明文。
146
147 ## 公共中继 Registry
148
149 Portal 官方公共中继 registry 是:
150
151 ```text
152 https://raw.githubusercontent.com/gosuda/portal-tunnel/main/registry.json
153 ```
154
155 隧道客户端默认包含这个 registry。如果你运营公共 Portal 中继,可以提交 pull request,把你的中继 URL 添加到 `registry.json`
156
157 ## 文档
158
159 - [CLI Reference](cmd/portal-tunnel/README.md)
160 - [Concepts](docs/src/routes/concepts/+page.md)
161 - [Portal Agent](docs/src/routes/portal-agent/+page.md)
162 - [Wallet and ENS](docs/src/routes/wallet-and-ens/+page.md)
163 - [Security Model](docs/src/routes/security-model/+page.md)
164 - [Architecture](docs/src/routes/architecture/+page.md)
165 - [Deployment](docs/src/routes/deployment/+page.md)
166 - [Configuration Reference](docs/src/routes/configuration/+page.md)
167
168 ## 贡献
169
170 1. Fork 这个仓库。
171 2. 创建功能分支(`git checkout -b feature/amazing-feature`)。
172 3. 用聚焦的测试或文档完成修改。
173 4. 打开 pull request。
174
175 ## 许可证
176
177 MIT License - see [LICENSE](LICENSE).