OmniRoute 零开放端口公网部署:Cloudflare Tunnel 与 Zero Trust(Split-Port 模式)完整实战指南
本指南记录了 OmniRoute 网络基础设施的"黄金标准"部署方案:利用 Split-Port(端口分离) 模式将 API 与管理面板拆到两个独立端口,再借助 Cloudflare Tunnel(cloudflared) 以纯出站连接暴露服务,实现 Zero Inbound(零入站端口) 的公网可达性,并分别用 Cloudflare Access(Zero Trust) 与 WAF 速率限制 对管理面板和 API 进行差异化加固。读完本文,你将掌握一套可复制的、不开任何防火墙端口的 OmniRoute 安全上线流程,并理解每个环节背后的源码级依据。
1. 前置基础:Split-Port 模式与强制 API 鉴权
1.1 你的虚拟机上做了什么
文档描述的部署案例在虚拟机(VM)上通过 PM2 以 Split-Port 模式运行 OmniRoute,将两个职责彻底隔离到不同端口:
- 端口
20128: 仅运行 API/v1(供各编程代理、CLI 工具消费)。 - 端口
20129: 仅运行可视化管理 Dashboard(管理面板)。
与此同时,内部服务强制开启 REQUIRE_API_KEY=true。这意味着任何代理程序都必须携带在管理面板 API Keys 标签页中生成的有效 Bearer Token 才能访问 API 端点,否则请求会被拒绝。
这种拆分带来的核心收益是:可以在网络层为两个服务创建两条完全独立的安全规则——管理面板走"人"的通道(浏览器 + 身份验证),API 走"程序"的通道(Token + 速率限制),互不干扰。
1.2 源码中的端口分离依据
从仓库源码可以确认,Split-Port 是 OmniRoute 运行时的一等公民能力。在 src/lib/runtime/ports.ts 中,getRuntimePorts() 会读取环境变量并分别解析出 API 与 Dashboard 端口:
const basePort = parsePort(process.env.OMNIROUTE_PORT || process.env.PORT, DEFAULT_PORT);
const apiPortExplicit = !!process.env.API_PORT;
const dashboardPortExplicit = !!process.env.DASHBOARD_PORT;
return {
port: basePort,
apiPort: parsePort(process.env.API_PORT, basePort),
dashboardPort: parsePort(process.env.DASHBOARD_PORT, basePort),
apiPortExplicit,
dashboardPortExplicit,
};
对应的环境变量契约记录在 .env.example 的 "NETWORK & PORTS" 一节(第 178–183 行):
# Split-port mode: serve Dashboard and API on separate ports for network isolation.
# Used by: src/lib/runtime/ports.ts — overrides PORT for each service.
# API_PORT=20129
# API_HOST=0.0.0.0
# DASHBOARD_PORT=20128
要点说明:
| 变量 | 作用 | 默认值 |
|---|---|---|
PORT |
单端口模式下的统一端口(Dashboard + API 共用) | 20128 |
API_PORT |
分离模式下 API 服务的监听端口 | 未设置时回落到 PORT |
DASHBOARD_PORT |
分离模式下 Dashboard 的监听端口 | 未设置时回落到 PORT |
API_HOST |
分离模式下 API 的绑定地址 | 默认跟随服务器配置(0.0.0.0) |
REQUIRE_API_KEY |
是否要求所有 /v1/* 代理端点携带 API Key |
false |
注意:本文案例中作者将
20128用作 API、20129用作 Dashboard,这是部署者自行约定的赋值;实际哪个端口承载哪个服务,完全由你在.env中给API_PORT/DASHBOARD_PORT的赋值决定,两者都是运行时可配置的。
REQUIRE_API_KEY 的语义在 .env.example 的 "SECURITY & AUTHENTICATION" 一节也有明确注释(第 373–376 行):
# Require an API key for all /v1/* proxy endpoints.
# Used by: API middleware — rejects unauthenticated requests to the proxy API.
# Default: false | Set true for multi-user/public deployments.
REQUIRE_API_KEY=false
即:默认关闭,任何公网/多用户部署都应当设为 true——这正是本指南案例的前提。
2. 第一步:在 Cloudflare 创建隧道
cloudflared 工具已预装在目标机器上(或通过 cloudflared service install 首次安装),接下来在云端完成隧道创建:
- 登录 Cloudflare Zero Trust 面板(
one.dash.cloudflare.com)。 - 在左侧菜单进入 Networks > Tunnels。
- 点击 Add a Tunnel,选择类型 Cloudflared,命名隧道为
OmniRoute-VM。 - 屏幕会生成一条名为 "Install and run a connector" 的安装命令。只需复制其中的 Token(即
--token后面的长字符串),无需在本地手工执行这条完整命令。 - 通过 SSH 登录虚拟机(或在 Proxmox 的终端中)执行:
# 启动 cloudflared 守护进程,并将隧道永久绑定到你的 Cloudflare 账户
cloudflared service install YOUR_HUGE_TOKEN_HERE
执行后,cloudflared 会作为系统服务常驻,主动以 HTTPS 出站连接到 Cloudflare 边缘节点。隧道建立后,云端的边缘节点可以把公网域名流量经该出站连接反向送回本机服务——全程不需要在你的 VM 上开放任何入站端口。
3. 第二步:配置路由(Public Hostnames)
在新创建的隧道详情页中,进入 Public Hostnames 标签页,利用前面做好的端口分离,添加两条路由,分别对应 API 与管理面板:
路由 1:安全 API(受限)
| 配置项 | 值 |
|---|---|
| Subdomain | api |
| Domain | yourdomain.com(替换为你的真实域名) |
| Service Type | HTTP |
| URL | 127.0.0.1:20128(API 内部端口) |
路由 2:Zero Trust 管理面板(封闭)
| 配置项 | 值 |
|---|---|
| Subdomain | omniroute 或 panel |
| Domain | yourdomain.com |
| Service Type | HTTP |
| URL | 127.0.0.1:20129(App/可视化内部端口) |
两条路由均使用
HTTP+ 本机回环地址(127.0.0.1),因为 Cloudflare 边缘到cloudflared连接本身已由 Cloudflare 侧的 TLS 加密,隧道内部到本机服务走回环即可,无需再套一层 HTTPS 证书。
至此,"物理"连接层面已经打通:api.yourdomain.com 能命中本机 20128 的 API 服务,omniroute.yourdomain.com 能命中 20129 的管理面板。接下来才是真正意义上的加固——让面板"隐形"、让 API"限流"。
4. 第三步:用 Zero Trust(Access)封死管理面板
任何本地密码都比不上"将面板从开放互联网中彻底移除"这一招——面板不再暴露给公网,攻击者连登录界面都看不到。
- 在 Zero Trust 面板中进入 Access > Applications > Add an application。
- 选择 Self-hosted 应用类型。
- Application name 填
OmniRoute Panel。 - Application domain 填
omniroute.yourdomain.com(必须与"路由 2"中的子域名完全一致)。 - 点击 Next。
- 在 Rule action 中选择
Allow,Rule 名称填Admin Only。 - 在 Include 条件的 Selector 中选择
Emails,输入你的邮箱,例如admin@example.com(可添加多个受信邮箱)。 - 点击 Add application 保存。
效果说明: 配置完成后,任何人直接打开 omniroute.yourdomain.com,看到的将不再是 OmniRoute 登录页,而是 Cloudflare 的身份验证页,要求输入邮箱地址。只有你(或配置的白名单邮箱)输入邮箱后,Outlook/Gmail 会收到一个 6 位临时验证码,验证通过后 Cloudflare 才放行隧道,把请求转发到本机 20129 端口。这相当于给管理面板加了一层邮箱 OTP 二次验证(邮件 2FA),且身份校验发生在流量进入你的 VM 之前。
5. 第四步:用 WAF 速率限制保护 API
Zero Trust Dashboard 的 Access 策略不适用于 API 路由(api.yourdomain.com)——因为 API 是自动化工具(编程代理)发起的程序化访问,没有浏览器、没有邮箱可验证。因此对 API 采用 Cloudflare 主防火墙(WAF)的速率限制规则:
- 登录 Cloudflare 常规面板(
dash.cloudflare.com),进入你的域名。 - 左侧菜单进入 Security > WAF > Rate limiting rules。
- 点击 Create rule。
- Name 填
Anti-Abuse OmniRoute API。 - 在 If incoming requests match... 中配置匹配条件:
- Field:
Hostname - Operator:
equals - Value:
api.yourdomain.com
- Field:
- With the same characteristics(按相同特征聚合):保持
IP——即按来源 IP 分别计数。 - 设置阈值(Limit):
- When requests exceed:
50 - Period:
1 minute
- When requests exceed:
- 最终 Action 选择
Block(阻断),并决定封禁持续 1 分钟 或 1 小时。 - 点击 Deploy 发布。
效果说明: 任何来源 IP 在 60 秒内向你的 API URL 发送超过 50 次请求,都会在互联网边缘层(Edge Layer)被直接拦截,流量根本不会进入隧道。由于你运行着多个编程代理,其背后的消费侧(OmniRoute 内部)本身已有速率限制与 Token 用量追踪,这里的 WAF 规则是一道前置保险:在流量抵达自建实例之前,先挡住突发压力,避免实例因"热应力"过载宕机。
实操建议:
50 req/min是文档给出的保守基线。如果代理集群的合法并发较高,可先调高到200–300 req/min观察正常峰值,再回落到一个恰好高于合法流量峰值、低于攻击面可接受值的阈值。
6. 收尾核对:零暴露清单
完成上述四步后,按以下清单逐项核对,确认部署达到文档定义的加固完成态:
-
无任何端口暴露:虚拟机的
/etc/ufw防火墙规则中没有开放任何入站端口;对外只有cloudflared建立的出站连接。 -
纯出站通信:OmniRoute 仅通过
cloudflared进行 HTTPS 出站通信,不直接接收来自公网的 TCP 连接——公网流量全部经由 Cloudflare 边缘 → 隧道 → 回环端口的链路进入。 -
上游请求混淆:发往 OpenAI 等上游提供商的请求已全局配置为走 SOCKS5 代理,真实出口 IP 被隐藏。该能力在 .env.example 的 "OUTBOUND PROXY" 一节有完整契约:
# Enable SOCKS5 proxy support in both server and client components. # Used by: open-sse/executors — wraps fetch() calls through the proxy agent. ENABLE_SOCKS5_PROXY=true NEXT_PUBLIC_ENABLE_SOCKS5_PROXY=true # ALL_PROXY=socks5://127.0.0.1:7890 # HTTP_PROXY=http://127.0.0.1:7890 # HTTPS_PROXY=http://127.0.0.1:7890 # NO_PROXY=localhost,127.0.0.1 -
面板 2FA:管理面板通过 Cloudflare Access 获得邮箱验证码二次验证。
-
API 边缘限流 + Token 鉴权:API 在 Cloudflare 边缘层受速率限制,且内部仅接受合法 Bearer Token(
REQUIRE_API_KEY=true)。
7. 安全模型剖析与扩展建议
7.1 三层纵深防御结构
从源码与配置可以推断,这套方案形成了清晰的三层纵深防御:
- 边缘层(Cloudflare):WAF 速率限制拦截暴力流量 + Access 身份验证拦截未授权访问者,攻击面在到达 VM 之前就被压缩。
- 传输层(cloudflared):无入站端口,网络层扫描(nmap 等)几乎看不到任何服务;同时规避了直接暴露 IP 带来的 DDoS 与端口探测风险。
- 应用层(OmniRoute 自身):
REQUIRE_API_KEY=true强制所有/v1/*端点鉴权,即使边缘规则被绕过,无 Token 的请求依然会被 src/lib/runtime/ports.ts 对应的 API 中间件拒绝。
7.2 与 OmniRoute 其他安全特性的联动
- 会话 Cookie 安全:公网 HTTPS 部署下应同步设置
AUTH_COOKIE_SECURE=true(见 .env.example "SECURITY & AUTHENTICATION" 一节),让 Dashboard 会话 Cookie 携带Secure标志,仅在 HTTPS 通道传输。 - SSRF 出站防护:OmniRoute 自带出站 URL 守卫(
src/shared/network/outboundUrlGuard.ts),默认阻止指向私网/云元数据的 Provider 地址;若你的部署同时接入了本地模型(Ollama、vLLM 等),才需要显式开启OMNIROUTE_ALLOW_PRIVATE_PROVIDER_URLS。 - 速率限制后端可扩展:边缘限流之外,OmniRoute 内置内存限流器,也可通过
REDIS_URL切换到 Redis 后端(见 .env.example 的 Redis 段落),适合多实例部署时共享限流状态。
7.3 排障速查
| 症状 | 排查方向 |
|---|---|
omniroute.yourdomain.com 一直跳 Cloudflare 验证页 |
确认 Access Application 的 domain 与隧道 Public Hostname 完全一致(含子域名大小写);确认白名单邮箱拼写 |
API 出现大量 429 / 连接被重置 |
检查 WAF 速率限制阈值是否低于代理集群合法峰值;按上文建议上调后再观察 |
隧道显示 Inactive |
回到 VM 执行 cloudflared service uninstall 后重新 cloudflared service install <TOKEN>,确认 Token 未过期 |
| Dashboard 能进但 API 报 401 | 检查 .env 中 REQUIRE_API_KEY 是否为 true,以及代理端是否配置了在 API Keys 页生成的 Bearer Token |
8. 小结
本方案的核心哲学可以浓缩为一句话:让服务"看不见",比让服务"很难攻破"更安全。通过 OmniRoute 的 Split-Port 能力(由 src/lib/runtime/ports.ts 提供运行时支持、.env.example 记录配置契约),配合 Cloudflare Tunnel 的出站隧道架构与 Zero Trust 身份/限流策略,你可以在不开任何防火墙端口的前提下,将 OmniRoute 的 API 与管理面板安全地暴露给全球用户与编程代理——API 走 Token + 边缘限流,面板走邮箱 OTP + 身份白名单,各得其所、互为犄角。
关联参考:.env.example(全部运行环境变量契约)、src/lib/runtime/ports.ts(Split-Port 运行时解析)、docs/i18n/zh-CN/docs/cloudflare-zero-trust-guide.md(本文档的简体中文版)、docs/guides/USER_GUIDE.md(OmniRoute 用户指南)。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0631
MiniCPM5-2BMiniCPM5-2B 是一款面向端侧、本地部署和资源受限场景的 2B 稠密 Transformer,能够达到同尺寸开源模型 SOTA 水平。Markdown00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
HivisionIDPhotos⚡️HivisionIDPhotos: a lightweight and efficient AI ID photos tools. 一个轻量级的AI证件照制作算法。Python09
DragonOSDragonOS is an operating system developed from scratch using Rust, with Linux compatibility. It is designed for **Serverless** scenarios. 使用Rust从0自研内核,具有Linux兼容性的操作系统,面向云计算Serverless场景而设计。Rust00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00