DeepSeek Harness 内网穿透(Cloudflare Tunnel + Access 公网访问)

场景:本地/云电脑跑着 DeepSeek Harness Web UI(http://127.0.0.1:3080),电脑没有公网 IP、无法端口映射,想从手机/外部安全访问。
方案:Cloudflare Tunnel(免费)+ Cloudflare Access 登录墙(免费)+ 自有域名,全程零服务器、零入站端口、源站 IP 不暴露。
实测环境:Windows 云电脑(Ecloud/Elink VDI,无公网 IP),2026-08-15 部署成功。

方案对比(为什么选 Cloudflare)

方案 免费程度 安全 固定域名 结论
Cloudflare Tunnel + Access ✅ 全免费 ✅ 源站零暴露 + 登录墙 ✅ 自有域名 采用
frp(自建服务器) ❌ 需要一台有公网 IP 的服务器 一般 ✅ 要买服务器,成本高
ngrok ⚠️ 免费版域名随机 一般 ❌ 固定域名要付费 不选
专门的 DSH Remote Gateway 项目 ✅ 免费 ❌ 有安全漏洞 ❌ Quick Tunnel 随机域名 弃用(见下)

为什么弃用 DeepSeekHarnessRemoteGateway(第三方网关)

调研了专为 DSH 设计的 GitHub 项目 lbwnb666-ai/DeepSeekHarnessRemoteGateway(2026-08-14 创建,v0.1.0),逐文件审查后发现有严重安全问题,不采用:

  1. 🔴 /_gateway/health 接口无认证直接明文返回访问密码 —— 等于把钥匙挂在门口
  2. 🔴 6 位数字密码(约 100 万组合)且登录无速率限制 —— 公网可暴力破解
  3. 🔴 基于 Quick Tunnel,随机域名每次重启变化,无法绑定自有域名

结论:仅适合临时手机分享/演示,不适合公网长期方案。Cloudflare 官方方案更安全可靠。


总流程(6 大步骤)

步骤 内容 耗时
1 Cloudflare 添加站点(域名接入) 10 min
2 域名注册商改 NS 到 Cloudflare 5 min + 传播等待
3 创建 Tunnel(拿 token) 5 min
4 云电脑安装 cloudflared 并启动 5 min
5 配置公共主机名路由(关键坑点!) 5 min
6 Cloudflare Access 登录墙 10 min

步骤 1:Cloudflare 添加站点

  1. 注册/登录 Cloudflare(邮箱注册)
  2. 首页 → 添加站点 / Add a site → 输入根域名(如 gungnir.top,不是子域名!)
  3. 选 Free(免费) 套餐 → 继续
  4. Cloudflare 扫描出你域名现有的 DNS 记录 → 保留它们不要删(避免迁移期间业务中断)
  5. 拿到两个 NS 地址(形如 xxx.ns.cloudflare.com / yyy.ns.cloudflare.com)→ 截图记下来

⚠️ 添加站点只接受根域名。子域名(如 dsh.gungnir.top)的解析由后面配置隧道时自动创建,无需手动加。

步骤 2:域名注册商改 NS(卡点高发区)

以腾讯云(DNSPod)为例:

  1. 腾讯云域名控制台 → 找到域名 → 修改 DNS 服务器
  2. 选择 使用非腾讯云 DNS → 填 Cloudflare 给的两个 NS
  3. 提交成功 → 注册商提示”最长 48 小时生效,一般几小时”

⚠️ 大坑:NS 提交后长时间不生效怎么办

实测等了 1.5 小时仍不生效(公共 DNS 还是旧的 DNSPod NS)。排查顺序:

  1. 先查 DNSSEC 是否开启(最常见原因)
    • 腾讯云 → DNSSEC 设置:如果列表里有记录 = 开启
    • 开启状态必须关闭,否则注册局会拒绝 NS 变更(签名密钥不匹配)
    • 实测:DNSSEC 未开启(列表为空)→ 排除
  2. 查提交状态:联系腾讯云在线客服,问”NS 变更是否已提交到 .top 注册局、预计何时生效”——这是唯一能区分”等待中”vs”提交失败”的权威途径
  3. 等注册局处理(.top 是 Radix 注册局,SLA 24h、提示最长 48h)

NS 生效验证(三层测试法)

# ① 注册局权威(无缓存,最真实)
nslookup -type=NS gungnir.top a.nic.top
nslookup -type=NS gungnir.top b.nic.top

# ② 公共递归 DNS(模拟普通用户视角,三家一致排除单点缓存)
nslookup -type=NS gungnir.top 1.1.1.1
nslookup -type=NS gungnir.top 8.8.8.8
nslookup -type=NS gungnir.top 223.5.5.5

# ③ 实际解析子域(最终目标)
python -c "import socket; print(socket.getaddrinfo('dsh.gungnir.top', 443, socket.AF_INET))"
  • 看到 xxx.ns.cloudflare.com = 已切换 ✅
  • 看到 xxx.dnspod.net = 还没生效 ⏳
  • 生效判定:CF 后台站点状态 Pending → Active;或手机(用流量,别用云电脑)打开 https://dsh.gungnir.top

💡 免费工具查全球传播:dnschecker.org(选 NS 类型)、whois.domaintools.com

步骤 3:创建 Tunnel

  1. CF 后台 → Zero Trust → Networks → Tunnels → 创建隧道
  2. 选 Cloudflared → 命名(如 deepseek harness)→ 创建
  3. 得到安装命令和 token → 下一步会用到

⚠️ 隧道 UUID 要以后台 URL 为准,不要凭记忆抄——实测曾把 d6b001d1d48f 抄成 d66b001d48f,导致后续 CNAME 配置错误。隧道详情页 URL:dash.cloudflare.com/<账号>/networks/connectors/cloudflare-tunnels/<隧道UUID>/...

步骤 4:云电脑安装 cloudflared(Windows)

安装方式选择

方式 说明
绿色版 exe(推荐,实测成功) 下载 cloudflared.exe 放到固定目录(如 C:\Users\Admin\Desktop\AI_project\cloudflared\)
MSI 安装包 云电脑 VDI 策略会拦截(实测闪退/报错),改用绿色版

下载地址:https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/downloads/

安装为 Windows 服务(开机自启)

cd C:\Users\Admin\Desktop\AI_project\cloudflared
# ① 安装服务(token 换成你自己的,注意别在公开场合贴 token)
cloudflared.exe service install <token>
# ② 启动服务
net start Cloudflared
# ③ 验证
sc query Cloudflared # STATE: 4 RUNNING

验证隧道连接

  • CF 后台隧道详情页 → 连接器(Connectors)显示 Connected,数据中心为 hkg(香港)等
  • 连接器在线:1/1 个副本日志连接器在线

⚠️ 配置公共主机名时若弹出 WARP 设备配置文件提示,点取消即可——那是给”私有网络路由/装 WARP 客户端”场景用的,与公共主机名(浏览器直接访问)无关。

步骤 5:配置公共主机名路由(⚠️ 最容易踩的坑!)

⚠️ 核心坑点:新版 UI 里「主机名路由」≠ 公共主机名!

Cloudflare 新版后台(2026 年后),隧道路由分了 4 种类型:

类型 用途 是否你要的
已发布的应用程序(Published Application) 通过公共主机名把本地应用发布到互联网,DNS 自动配置 ✅ 就是这个
私有主机名(Private Hostname) 需要装 Cloudflare One/WARP 客户端才能访问内网 ❌ 不是
私有 CIDR 远程访问私有 IP 网段 ❌ 不是
Workers VPC Workers 连私有服务 ❌ 不是

正确入口:隧道详情页 → 路由 标签 → 添加路由 → 选 「已发布的应用程序」(不是「主机名路由」/「私有主机名」!)

填表(以 DSH 为例)

字段 填什么
子域(Subdomain) dsh
域(Domain) gungnir.top
路径(Path) 留空
类型(Type) HTTP
URL localhost:3080(或 127.0.0.1:3080,都行)

保存后 Cloudflare 自动创建 DNS 记录(CNAME)+ 签发 HTTPS 证书。

⚠️ 配错类型的故障特征(对照排查)

如果配成了「私有主机名」(或服务列为空),访问会 503 Service Unavailable,隧道实时日志会报:

No ingress rules were defined in provided config (if any) nor from the cli,
cloudflared will return 503 for all incoming HTTP requests

含义:cloudflared 没有收到任何”入口规则”(私有主机名不走公网 DNS,不当作 ingress)。修复:删掉错误路由,重新按「已发布的应用程序」添加。

⚠️ 另一个坑:站点 Pending 期自动创建 CNAME 会失败

添加公共主机名时如果站点还处于 Pending(NS 未生效),Cloudflare 不会自动创建 dsh 的 CNAME 记录 → DNS 记录列表里根本没有 dsh。需要手动补:

DNS → 记录 → 添加记录:

字段 值
类型 CNAME
名称 dsh
目标 <隧道UUID>.cfargotunnel.com(如 48642d26-...-d6b001d1d48f.cfargotunnel.com)
代理状态 ✅ 开启(橙色云朵),必须开!
TTL 自动

cfargotunnel.com 是 Cloudflare 官方保留的隧道 CNAME 目标域名,格式固定为 <隧道UUID>.cfargotunnel.com。更稳的做法:在目标输入框里直接下拉选你的隧道,让 CF 自动填,零出错。

⚠️ 还有:http://dsh.gungnir.top:3080/ 为什么不通?

隧道只按 Host 头接收 80/443 端口,公网 3080 端口不暴露。带端口访问必然失败。正确入口永远是 https://dsh.gungnir.top(生效后先见 Access 登录墙或应用页面)。

步骤 6:Cloudflare Access 登录墙(⚠️ 有逻辑坑)

目的:https://dsh.gungnir.top 目前任何人拿到链接都能访问,必须加登录墙。

前置:确认 One-time PIN 已启用

Access Controls → 身份提供商(Identity Providers):确认 One-time PIN 是启用状态(勾选)。这是邮箱验证码的基础——访问者输邮箱收 6 位验证码即可登录,不需要注册/登录 Cloudflare 账号。

正确配置顺序(三层结构)

第 1 层:创建规则组(Rule Group)——白名单

位置:Access Controls → 规则组 → 创建(如「允许访问的邮箱」):

  • 用 Include(逻辑为”或”,满足其一即可)→ 电子邮件地址 → 填你的邮箱 860637048@qq.com
  • 组含义:只有组里的人才有资格登录

第 2 层:创建策略

位置:Access Controls → 策略 → 新建:

字段 值
策略名称 如 dsh_access_c_policy
操作(Action) 允许(Allow)
会话持续时间 1 month(30 天)(免频繁验证)
Include(包含) 登录方法 → 勾选 One-time PIN(以及你想开放的其他登录方式)
Require(要求) Access 规则组 → 选「允许访问的邮箱」⭐

⭐ 关键逻辑坑(官方教程作者也踩过):

邮箱白名单必须放在 Require,不能放在 Include!
如果直接把邮箱加进 Include,逻辑会变成”登录方式可以是 One-time PIN,或者这些邮箱”——结果是任何 Google/邮箱账户都能登录。
只有 Require 绑定规则组,才能确保”不管用什么登录方式,最终邮箱必须在我白名单里”。

参考教程(LINUX DO,需登录才能看):https://linux.do/t/topic/558073

第 3 层:绑定到应用

位置:Access → 应用程序 → 你的 dsh 应用(自托管)→ 策略选择刚才创建的策略 → 保存。

验证

手机用流量(别用云电脑,避免本地 DNS 干扰)打开 https://dsh.gungnir.top:

  1. 跳转到 Cloudflare Access 登录页
  2. 输入邮箱 → 邮箱收到 6 位验证码
  3. 输入验证码 → 进入 DeepSeek Harness
  4. 之后 30 天内免登录

完整链路图

手机浏览器
↓ https://dsh.gungnir.top
Cloudflare 边缘节点 (104.x / 172.x,全球就近)
├─ Access 登录墙(验证码通过后才放行)
↓ CNAME 解析到 <隧道UUID>.cfargotunnel.com
Cloudflare Tunnel(hkg 香港节点出站连接)
↓ 加密隧道
云电脑 cloudflared(Windows 服务)
↓ http://localhost:3080
DeepSeek Harness Web UI

应急方案:Quick Tunnel(临时测试用)

不想等 NS 生效/临时演示时,可在云电脑执行:

cd C:\Users\Admin\Desktop\AI_project\cloudflared
cloudflared.exe tunnel --url http://localhost:3080

会生成一个随机 https://<xxx>.trycloudflare.com 链接,立即可用。注意:

  • ❌ 无 Access 鉴权(拿到链接即可访问)
  • ❌ 关窗即失效
  • ✅ 仅限本人临时测试,用完即关

全部坑点速查表

# 坑 现象 解决
1 隧道 UUID 抄错 CNAME 目标错误、无法访问 以后台 URL 为准,或目标框下拉选隧道
2 路由配成「私有主机名」 全部 503 + 日志 No ingress rules 删掉,改配「已发布的应用程序」
3 站点 Pending 期自动 CNAME 失败 DNS 列表无 dsh 记录 手动补 CNAME(目标 <隧道UUID>.cfargotunnel.com,橙云)
4 NS 提交后不生效 公共 DNS 仍是旧 NS 查 DNSSEC(须关闭)→ 问注册商客服提交状态 → 等(最长 48h)
5 MSI 安装被 VDI 拦截 安装闪退/报错 用绿色版 cloudflared.exe
6 WARP 设备配置文件弹窗 配路由时弹提示 与公共主机名无关,点取消
7 Access 邮箱白名单放错位置 任何账户都能登录 邮箱放 Require(规则组),Include 只放登录方法
8 带端口访问 :3080 连接失败 隧道只暴露 80/443,用 https://dsh.gungnir.top
9 VDI 本地 DNS 干扰 nslookup 报 Binary file matches 显式指定 DNS 服务器(1.1.1.1 等)或直查注册局
10 cf_DNS 默认位置删不掉 提示先设另一个默认 是 Gateway DNS 过滤功能,与隧道无关,忽略即可
11 国内访问偏慢 晚高峰卡 CF 优选 IP 加速(另文)
12 隧道 token 泄露 担心被滥用 CF 后台删隧道重建作废即可
13 DSH 启动没加 --trusted-host 页面能开但 /api 全 403、卡 Loading plugins DSH 启动加 --trusted-host dsh.gungnir.top(详见下节)
14 远程点「打开文件夹」报 403 transport failure for /api/host.pickDirectory: HTTP 403 官方设计,特权方法只允许本机,远程无解(详见下节)
15 想远程选文件/传文件 打开文件夹被拒 装插件替代:dsh-at-file / DSH-better-sidebar / dsh-file-uploads

⚠️ DSH 自身的远程访问限制(2026-08-16 实测,重点)

穿透打通 ≠ DSH 全部功能远程可用。 DSH 有一个 browser-trust fence(浏览器信任围栏),专门防 DNS-rebinding 和跨站攻击,对所有 /api 请求做 Host 头校验:

请求到达 DSH 时,Host 头必须是:
✅ 127.0.0.1 / localhost(loopback)
✅ --trusted-host 声明的域名
❌ 其他任何值 → 403 Forbidden

1️⃣ 必须加 --trusted-host(否则页面卡 Loading plugins)

DSH 启动命令必须声明公网域名,否则所有 /api 请求(包括聊天、会话列表)都被 403 拒绝,表现为页面能打开但卡在 “Loading plugins”:

# ❌ 错误:公网访问时 /api 全 403
npx @deepseek-ai/dsh web

# ✅ 正确:声明信任的公网域名(可重复加多个)
npx @deepseek-ai/dsh web --trusted-host dsh.gungnir.top

本地 127.0.0.1 访问不受影响(loopback 天然信任)。

2️⃣ 打开文件夹/设置等特权操作:远程永远 403(官方设计,无解)

host.pickDirectory(打开文件夹)、host.openPath、settings.*(设置)、credentials.*(凭据)等 15 个 PRIVILEGED_METHODS 被 DSH 源码硬编码强制 loopback——即使配了 --trusted-host 也放行不了:

// @deepseek-ai/dsh-client-connection/lib/index.js
// 注释原文:"privileged methods additionally pass it with an empty trust
// list, which pins them to loopback"(特权方法强制本机)
if (method !== undefined && PRIVILEGED_METHODS.has(method) && !isTrustedApiRequest(request, []))
return new Response("forbidden", { status: 403 });

这是安全设计不是 bug:打开文件夹对话框作用于宿主机,设置/凭据会改配置和密钥库。DSH 官方在”真正的认证层出现之前”不开放这些能力到远程。远程就是 403,不是配错,改设置/选文件夹得回本机操作。

3️⃣ 远程选文件/传文件:装插件替代

插件 作用 用法
dsh-at-file 输入框 @ 引用工作区文件 装好后在输入框打 @文件名 即可引用
DSH-better-sidebar 工作区文件浏览、下载、内嵌预览 PDF/图片/MD/Office 侧边栏直接浏览工作区文件
dsh-file-uploads 浏览器上传任意文件到工作区,支持下载删除 远程也能传文件

安装方式:在 DSH 里让 AI 帮你装(插件管理器),或 dsh plugin --profile web <pnpm args>。

4️⃣ 🔴 严禁改 0.0.0.0 裸奔(有 RCE 风险)

网上有人改 cordis.patch.yml 的 host 为 0.0.0.0 + 改源码禁用检查来”解锁”全部功能——绝对不要做。GitHub 安全讨论 #853 已证实:DSH 的 /api 有 60+ 无认证 RPC 方法(含 session.prompt 可驱动 agent 执行任意 shell 命令、/permission danger-full-access 一键提权),唯一保护就是 Host 头围栏。改 0.0.0.0 绑定 = 公网任何人可远程执行任意命令(未认证 RCE)。

正确做法(也是官方在 #853 里的缓解建议):保持 DSH 只监听本机,公网访问用 CF Tunnel + Access 登录墙做认证层(本教程的整套方案),接受特权操作远程不可用。


参考资料

待办 / 后续优化

  • 开启 Always Use HTTPS / HSTS(SSL/TLS 设置)
  • WAF 托管规则(SQLi/XSS 基础防护)
  • CF 优选 IP 加速国内访问
  • 同一隧道继续加 wiki/api 等子域(指向不同本地端口)
  • 如日后需要可在 CF 重新开启 DNSSEC(NS 已生效后可开)