这套方案只用三样免费资源:两个 Cloudflare Worker + 一个 GitHub 仓库。目标不是「从零搭一个代理」,而是把 VPN Gate 上的公共 SSTP 节点 自动筛成一份能连通、可分类、会自己更新的订阅清单(nodes.txt),再交给 edgetunnel 生成最终订阅。全文从零开始,做完大约 10 分钟。
目录
- 先搞清楚:三个组件各管什么
- 前置准备
- 第 1 步:部署 edgetunnel(核心使用端)
- 第 2 步:部署检测 Worker(CheckSocks5)
- 第 3 步:Fork gate 仓库
- 第 4 步:设置 Secret
DOMAIN - 第 5 步:启用 GitHub Pages
- 第 6 步:运行工作流,生成 nodes.txt
- 第 7 步:把 nodes.txt 填进 edgetunnel
- 第 8 步(可选):定时自动更新
- 部署完成验证清单
- 这次更新了什么
- 常见问题 FAQ
- 安全提醒与免费额度
- 附录:配置项速查与目录结构
先搞清楚:三个组件各管什么
绝大多数踩坑都来自「把不同组件的配置填到了彼此身上」。先看这张分工表,后面每一步都会对应回来:
| 组件 | 部署在哪 | 负责什么 | 你会拿到什么 |
|---|---|---|---|
| edgetunnel | Cloudflare Worker | 对外提供代理与订阅后台,最终订阅由它生成 | ADMIN 密码、UUID、节点域名、/admin 后台 |
| CheckSocks5 检测 Worker | Cloudflare Worker | 接收一个 SSTP 地址,返回「通不通、延迟、出口国家、是否机房 IP」 | 形如 abc.用户名.workers.dev 的检测地址 |
| gate(本仓库) | GitHub Actions + Pages | 抓 VPN Gate 节点 → 调用检测 Worker 逐个验证 → 发布节点清单与面板 | nodes.txt、data.json、在线面板 |
- ADMIN:edgetunnel 后台登录密码,只在第 1 步设置。
- UUID / 节点域名:edgetunnel 自己的东西,只在 edgetunnel 后台看,永远不需要写进 gate。
- DOMAIN:第 2 步那个检测 Worker 的 host(不含 https:// 与路径),是 gate 唯一的必填配置。
前置准备
- 一个 GitHub 账号(免费即可,工作流跑在公开仓库上不消耗私有分钟数)。
- 一个 Cloudflare 账号(免费版足够:两个 Worker 的检测请求量远低于每日 10 万次上限)。
- 可选但推荐:一个已托管在 Cloudflare 的自定义域名。
*.workers.dev在部分地区无法直接访问,用自定义域名绑定的 Worker 更稳。 - 时间 20 分钟左右;全程不需要服务器、不需要花钱。
第 1 步部署 edgetunnel(核心使用端)
edgetunnel 是你最终会「用到」的那个 Worker,先把它部署好,后面拿到 nodes.txt 才有地方填。
- 登录 Cloudflare 控制台,点击左侧 Workers 和 Pages。
- 点击 创建 → 选择 创建 Worker,起名
edgetunnel,点击 部署。 - 打开 https://github.com/cmliu/edgetunnel/blob/main/_worker.js,复制全部代码(建议点右上角 Raw 后 Ctrl+A 全选、Ctrl+C 复制,避免把行号一起复制进去)。
- 回到 Cloudflare Worker 编辑器,先把示例代码全部清空,粘贴代码,点击 保存并部署。
- 在 设置 → 变量 中,添加变量 ADMIN,值填你的管理员密码(建议顺手点「加密」,避免明文出现在控制台历史里)。
- 在 绑定 中,添加 KV 命名空间绑定,变量名称必须填
KV(大小写一致)。若还没有命名空间,就在 Workers 和 Pages → KV 命名空间 里新建一个,例如edgetunnel-kv。 - (推荐)在 触发器 中绑定自定义域名,例如
tunnel.example.com。绑好后优先用这个域名访问,不要只用*.workers.dev。 - 浏览器访问
https://你的域名/admin,用第 5 条的 ADMIN 密码登录后台。 - 在后台首页记下你的 UUID 和 节点域名(后面要用)。
这一步容易踩的坑:
| 现象 | 原因与处理 |
|---|---|
| 访问 Worker 报 1101 / 后台打不开 | 多半是 KV 没绑,或绑定的变量名不是 KV;改完记得重新部署 |
| /admin 提示未配置密码 | 变量名写成小写 admin 了;必须是大写 ADMIN,保存后重新部署 |
| 粘贴代码后仍是默认欢迎页 | 只点了「保存」没点「部署」;或粘贴时带了行号导致语法错误,改用 Raw 页面复制 |
| 自定义域名打不开 | 域名未托管到 Cloudflare,或记录没走代理(橙色云);先在触发器里确认为 active |
第 2 步部署检测 Worker(CheckSocks5)
gate 本身无法从 GitHub 直接连到那些 SSTP 节点,需要一个「站在 Cloudflare 上」的帮手替它逐个试连。这个帮手就是 CheckSocks5,它同时也是第 4 步 Secret DOMAIN 的唯一来源。
- 打开 https://github.com/lsh8848/cm-Workers-CheckSocks5,点 Fork(Fork 只是为了留一份自己的代码,不 Fork 直接打开仓库里的
_worker.js复制也可以)。 - 进 Cloudflare 控制台 → Workers 和 Pages → 创建 → 创建 Worker,起名例如
checksocks5。 - 把仓库里
_worker.js的全部内容粘贴进编辑器,点「部署」。 - 记下这个 Worker 的域名,形如
https://xxx.你的用户名.workers.dev。 - 验证:浏览器打开
https://你的Worker域名/check?sstp=vpn:vpn@任意节点:端口,能返回 JSON 即成功。例如:
https://check.你的用户名.workers.dev/check?sstp=vpn:vpn@public-vpn-114.opengw.net:443
正常返回长这样(字段值为示例):
{
"success": true,
"responseTime": 132,
"colo": "NRT",
"error": null,
"exit": {
"ip": "203.0.113.10",
"country": "Japan",
"country_code": "JP",
"city": "Tokyo",
"continent": "AS",
"asn": { "asn": 12345, "name": "Example ISP", "org": "Example Org" },
"is_datacenter": false
}
}
| 字段 | 含义 | gate 拿它做什么 |
|---|---|---|
success | 该节点这次是否连通 | 只保留 true 的节点进入清单 |
responseTime | 检测耗时(毫秒) | 面板显示与排序参考 |
colo | 命中的 Cloudflare 机房代码 | 写入 data.json 供筛选 |
exit.country_code | 出口国家/地区 | 分组、每国数量上限、备注里的中文国名 |
exit.is_datacenter | 出口 IP 是否为云厂商/机房 IP | 判定「住宅 / 机房」标签(本次更新的重点) |
error | 失败原因文本 | 统计失败类型、判断 Worker 自身是否异常 |
- 返回
"success": false也算部署成功——它说明 Worker 正常应答,只是那个节点恰好不通(公共节点本来就大量失效,很正常)。 - 请把这个地址的 host 抄下来(去掉
https://和后面的路径),第 4 步填 Secret 时用的就是它。
第 3 步Fork gate 仓库
- 打开 https://github.com/hezhanleiok/gate,点右上角 Fork,选自己的账号。
- 仓库名保持默认的
gate最省事;改了名字,最终订阅地址会跟着变(后面自动推导,不用手配)。 - 请保持仓库为 Public:GitHub Pages 在免费账号上只对公开仓库开放;工作流跑在公开仓库上也不消耗私有分钟数。
fork 之后这份代码完全属于你:抓取逻辑、检测并发、发布产物都在你自己的 Actions 额度里跑。
第 4 步设置 Secret DOMAIN(唯一必填项)
这是整个仓库唯一需要你填的配置。路径:
仓库 → Settings → Secrets and variables → Actions → New repository secret
| Name | Value | 说明 |
|---|---|---|
DOMAIN | check.你的用户名.workers.dev | 只填 host,正确写法 |
| — | https://check.你的用户名.workers.dev | 带了协议——脚本会自动补,但建议按规范只填 host |
| — | check.xxx.workers.dev/check?sstp=vpn:vpn@ | 把整条地址塞进 Secret,属于旧写法,不必要 |
工作流会自动把它拼成检测地址:
https://[DOMAIN]/check?sstp=vpn:vpn@
/check、补 ?sstp=vpn:vpn@ 都能纠正。
第 5 步启用 GitHub Pages
节点清单要「发布」成一个可访问的网址,靠的是 Pages。设置路径:
仓库 → Settings → Pages → Build and deployment → Source 选 GitHub Actions
POST /repos/.../pages,build_type=workflow)帮你打开;已经开启过会返回 409,脚本按成功处理。只有权限不够(例如返回 403)时才需要你手动按上面路径设置一次。
Pages 就绪后你会得到三个地址(以用户名 alice、仓库 gate 为例):
- 在线面板:
https://alice.github.io/gate/ - 订阅清单:
https://alice.github.io/gate/nodes.txt - 结构化数据:
https://alice.github.io/gate/data.json
这三个地址不需要你写进任何配置文件——脚本会用 GITHUB_REPOSITORY 自动推导订阅地址,面板则自己按当前网址定位 data.json。
第 6 步运行工作流,生成 nodes.txt
路径:仓库 → Actions → 左侧「VPN Gate Node Check」→ Run workflow → 选分支(main 或 test)→ Run workflow。
运行前有三个可选参数,保持默认就能出结果:
| 参数 | 默认 | 什么时候要改 |
|---|---|---|
| concurrency | 32 | 检测很慢或想更激进时调大/调小 |
| timeout | 25 | 单个节点等待秒数,公网高延迟节点可调到 35 |
| max_nodes | 0(全部) | 想更快出结果时填 40 之类;脚本会先按延迟/评分排序再截断 |
一次正常运行的日志顺序大致是这样:
========== VPN GATE ========== 主源(官方 API) 获取到 96 个原始节点 原始节点 96, SSTP 87, 去重后 87 ========== CLOUDFLARE WORKER ========== 提交检测: 87 成功 74, 失败 13(Worker 异常 0), 用时 48.6s ========== EDGE POOL ========== 入口地址池: 静态/配置 20 个, API 0 个, 合并 20 个 ========== RESULT ========== 可用节点 74, 国家/地区 9, nodes.txt 66 行 ========== WEBSITE ========== 完成(GitHub Pages 部署由 workflow 执行)
第 7 步把 nodes.txt 填进 edgetunnel
- 打开
https://你的域名/admin,用 ADMIN 密码登录。 - 找到「自定义优选 IP / 优选 IP 订阅」这一项(不同版本命名略有差异),填入
https://用户名.github.io/仓库名/nodes.txt。 - 保存,然后在客户端(v2rayN、Clash、Shadowrocket 等)更新订阅即可。
nodes.txt 每行三部分,用 # 和 $ 分隔:
edge1.example.com:443#日本-住宅-01$sstp://vpn:vpn@public-vpn-114.opengw.net:443 edge2.example.com:443#日本-住宅-02$sstp://vpn:vpn@public-vpn-242.opengw.net:443 edge1.example.com:443#韩国-机房-01$sstp://vpn:vpn@public-vpn-153.opengw.net:22494
#前面是优选入口(host:port),这是喂给 edgetunnel 的部分,同一国家内会轮转使用不同入口。#后面是备注:国家中文名 + 住宅/机房 + 该类别内序号,住宅优先排前面。$后面是原始 SSTP 链接,方便你手动导入系统 VPN 客户端(Windows:设置 → 网络和 Internet → VPN → 添加 VPN,类型选 SSTP,服务器填public-vpn-114.opengw.net,用户名密码都是vpn)。
打开面板 https://用户名.github.io/仓库名/ 还能按国家/住宅机房筛选、单条复制、一键复制全部或下载 nodes.txt,页面每 5 分钟自动刷新一次数据。
第 8 步(可选)定时自动更新
作为模板仓库,工作流默认只开手动触发,不替你决定调度频率。要自动更新时,编辑 .github/workflows/check.yml,把文件里注释好的这段取消注释,并按自己的需求改时间:
on:
schedule:
- cron: '*/30 * * * *' # 每 30 分钟一次,改成你自己的节奏
workflow_dispatch:
- 最小粒度约 5 分钟,且实际触发常比计划晚几分钟到十几分钟,不要卡点依赖它。
- 仓库连续 60 天没有任何提交,定时任务会被 GitHub 自动停用。
- 公开仓库的 Actions 时长免费;私有仓库每月 2000 分钟,每 30 分钟跑一次(约 2880 分钟/月)会超,请放大间隔。
部署完成验证清单
- ☐ 第 2 步那个
/check?sstp=...能返回 JSON(不管 success 是 true 还是 false) - ☐ 仓库 Secrets 里存在
DOMAIN,且值只有 host - ☐ Actions 里这次运行是绿色 ✓,日志末尾出现「完成(GitHub Pages 部署由 workflow 执行)」
- ☐
https://用户名.github.io/仓库名/nodes.txt能打开且有内容 - ☐ 面板首页能看到节点列表、国家分组与「住宅/机房」标签
- ☐ edgetunnel 后台已填入该 nodes.txt 地址
- ☐ 客户端更新订阅后能选中节点并连通
这次更新了什么
版本:bf3dc92 + b24936f,14 个文件变更(+2001 / −693),新增 32 个自动化测试。整体方向是把仓库从「一份需要改代码才能跑的脚本」变成「fork 后只设一个 Secret 就能跑的模板」,同时补齐可靠性和工程质量。分六组说明。
一、模板化:把「必须改源码」的配置项全部请出去
| 项目 | 之前 | 现在 |
|---|---|---|
| 检测地址 | 源码里写占位符,要自己改 CHECK_WORKER 完整 URL | GitHub Secret DOMAIN 只填 host,工作流拼装;缺失/仍是占位符时启动即报错并给指引 |
| 订阅地址 | 要手改 NODES_URL 里的用户名和仓库名 | 由 GITHUB_REPOSITORY 自动推导,README 里这一步直接删掉 |
| 定时任务 | 自带一个写死的 cron | 默认不启用,示例以注释形式保留,由用户自己决定节奏 |
| Pages 启用 | 调用方式不合法(PUT 带 source.path=/public),常静默失败 | 改为 POST build_type=workflow;已存在(409)视为成功;403 时明确提示去 Settings 手动切换 |
二、可靠性:不再把坏结果发布出去
- 发布护栏:0 个成功节点、或全部是 Worker 自身异常时,终止运行并保留上一次发布的产物,订阅不会被清空。
- 成功率阈值可选:新增
MIN_SUCCESS_RATIO,默认 0(不限制)。之所以不做硬阈值,是因为 VPN Gate 的公共节点本身成功率就不高,写死 30% 会让任务频繁「假红」。 - 原子写入:三个产物都先写临时文件再原子替换,运行中途被取消不会留下半截 JSON。
- 空入口池兜底:
EDGE_HOSTS被清空时自动回退内置入口池,不再触发除零错误。
三、检测准确性与速度
- 住宅/机房分类改为以检测接口的
is_datacenter为准。之前那套 ASN 关键字表基本是死代码(该字段一直是布尔值);更严重的是旧版还会「主机名以 public-vpn 开头就判机房」,而 VPN Gate 的节点全部是这个名字,等于所有节点都被贴成机房标签。现在关键字只在字段缺失时作为兜底,并恢复了未知这一类。 - 超时对齐:单节点从 90 秒降到 25 秒(检测 Worker 内部上限 12 秒,等更久没意义),并新增整体截止时间,避免个别卡死请求拖垮整个任务。
- 连接复用与重试:连接池大小跟随并发数扩容,三个 HTTP 出口统一加了退避重试,减少偶发网络抖动造成的误判。
- 抽样前先排序:限制检测数量时,先按 VPN Gate 的延迟/评分排序再截断,不会把最快的节点切掉。
四、产物格式
- nodes.txt:每国数量上限(住宅 20 / 机房 10,可调)、链接去重、备注清洗掉会破坏解析的字符、住宅优先排序、序号按类别独立计数、同一国家内轮转不同优选入口。
- IPv6 端点:统一规范成
[地址]:端口,无法解析的端点直接丢弃而不是写出坏行。 - data.json:去掉重复字段、改为紧凑输出,新增
schema_version、耗时、超时计数、Worker 异常数等统计。 - 不再公开完整检测地址:产物里原本会带你的整条 Worker URL(含查询串),现在只记录 host。
五、面板与文档
- 面板所有渲染改为转义输出(此前用字符串拼 innerHTML,节点备注里带尖括号就能把页面结构撑坏);数据没更新时不再重复重绘;新增按国家/类型筛选、单条复制、复制全部、下载 nodes.txt。
- README 全文重写:架构图、fork 三步、Secret 说明、定时示例、完整配置表、产物格式、本地运行、FAQ、已知限制与免责声明。
六、工程质量
- 新增
tests/:32 个用例,除单元逻辑外还包含一个离线端到端测试(本地起假数据源和假检测接口,跑完整流程并逐字符校验 nodes.txt 内容、验证失败时不会写文件)。 - 新增 CI(代码检查 + 测试),任意分支推送都会跑;补齐依赖锁定、开发依赖、LICENSE、行尾规范化配置。
DOMAIN Secret → 可以删掉旧的 CHECK_WORKER、NODES_URL 等自定义项(仍兼容,但已非必需)。除此之外不需要改动其他文件。
常见问题 FAQ
- 必须准备自定义域名吗?
不必须,*.workers.dev也能跑完全部流程;但该域名在部分地区不可直连,检测 Worker 和 edgetunnel 都建议绑自定义域名。 - Secret 填完运行,报「未配置检测 Worker 地址」。
Secret 名字必须是全大写DOMAIN,且添加在仓库级 Secrets 里;改完要重新触发一次运行。 - 日志里全是 Worker 异常 / 全部失败。
先用浏览器手动访问检测地址确认能返回 JSON;再检查有没有给这个 Worker 加 Access 认证或 WAF 拦截;最后确认 host 拼写正确。 - Pages 部署步骤 403。
去 Settings → Pages 手动把 Source 改成 GitHub Actions 一次即可;自动启用那步只是省你手点,失败不代表流程坏了。 - 成功节点数时多时少,正常吗?
正常。VPN Gate 是志愿者公共节点,上下线频繁,同一份清单不同时间跑差异很大;这也是发布护栏只在「全失败」时拦停的原因。 - 为什么有的节点标「机房」?
检测接口判定出口 IP 属于云厂商/数据中心,这类 IP 在一些网站会触发风控;想优先用住宅 IP,看面板里的「住宅」筛选即可,nodes.txt 也已把住宅排在前面。 - 能加更多节点源吗?
官方接口单次返回约 90~100 行,其中约 87 个支持 TCP(本项目按 SSTP 端口处理)。想扩大规模需要多个数据源合并,脚本目前的主源 + 镜像回退已经覆盖了常见故障。 - 上游有更新,我的 fork 怎么同步?
在 fork 页面点 Sync fork → Update branch;或者添加上游 remote 后 pull。
安全提醒与免费额度
- ADMIN 请用足够长的随机串,它直接决定谁能改你的订阅配置;检测 Worker 无需密码,但请别给它套访问认证。
- nodes.txt 与 data.json 是公开的(挂在 Pages 上)。里面只有优选入口和国家/备注信息,不含 UUID 与密码,但仍不建议把它当作私密订阅分发。
- 真正的私密性由 edgetunnel 的 UUID 保证,请务必不要把带 UUID 的订阅链接贴到公开场合。
- VPN Gate 节点是公共志愿者节点,出口可能被他人共享、可能被目标网站拦截;请勿用于任何违法违规用途,遵守所在地区的法律法规。
| 服务 | 免费额度(参考) | 本方案用量 |
|---|---|---|
| Cloudflare Workers | 约 10 万次请求/天 | 每次运行约 90 次检测,每小时跑也远不到上限 |
| Cloudflare Workers KV | 读 10 万/天、写 1000/天、1GB 存储 | 仅 edgetunnel 存配置,量极小 |
| GitHub Pages | 软限约 100GB/月带宽、站点 1GB | 产物几十 KB,可忽略 |
| GitHub Actions | 公开仓库免费;私有仓库 2000 分钟/月 | 每次约 1~2 分钟 |
附录:配置项速查与目录结构
除 DOMAIN 外,以下环境变量都是可选的(在 workflow 的 env 或本地运行时设置):
| 变量 | 默认 | 作用 |
|---|---|---|
| CHECK_WORKER | 空 | 本地运行用完整检测地址;Actions 里由 DOMAIN 拼装 |
| CHECK_CONCURRENCY | 32 | 并发检测数量 |
| CHECK_TIMEOUT | 25 | 单节点超时(秒) |
| CHECK_DEADLINE | 1200 | 整轮检测截止(秒) |
| MAX_CHECK_NODES | 0 | 最多检测多少个节点,0 为全部 |
| MIN_SUCCESS_RATIO | 0 | 成功率低于此值则判定本次运行失败,0 为不限制 |
| MAX_RESIDENTIAL_PER_COUNTRY | 20 | 每国住宅节点发布上限 |
| MAX_DATACENTER_PER_COUNTRY | 10 | 每国机房节点发布上限 |
| EDGE_HOSTS | 内置池 | 优选入口列表,建议换成你自己的域名优选 IP |
| VPNGATE_API / VPNGATE_MIRROR | 内置 | 主数据源与镜像回退源 |
| NODES_URL | 自动 | 订阅地址,通常不需要设置 |
gate/
vpngate.py 主脚本(抓取 检测 生成产物)
requirements.txt 运行依赖
web/index.html 面板模板
public/ 工作流生成的产物(data.json / index.html / nodes.txt)
tests/ 32 个自动化测试
.github/workflows/
check.yml 抓取与发布(手动触发,可选加 cron)
ci.yml 代码检查与测试
README.md 部署与配置说明
免责声明:本文涉及的第三方项目(edgetunnel、cm-Workers-CheckSocks5、VPN Gate)归各自作者所有;公共节点的稳定性、可用性与合规性由节点提供者负责,本项目只做抓取、检测与展示,不提供任何节点。请仅用于合法用途。
相关地址:gate 仓库 | edgetunnel | CheckSocks5 | VPN Gate

文章评论 (0)