A yunzes-node server based on multi core, modified from V2bX.
一个基于多种内核的 yunzes-node 节点服务端,修改自 V2bX,支持 V2ray、Trojan、Shadowsocks、Tuic、Hysteria 协议。
Scripts/yunzes-node.sh 是完整运维入口,安装后可直接以 yunzes-node 命令调用。它默认走 Docker + host network + 单容器双核心 模式,并把 PreCheck(23 项)、备份、回滚、卸载、fake panel 4 协议自测都串在一起。
# 1. 拉源码 + 进入目录
git clone https://github.com/husibo16/yunzes-node.git
cd yunzes-node
# 2. 安装命令入口(写到 /usr/bin/yunzes-node)
sudo bash Scripts/yunzes-node.sh setup-entry
# 3. 进入交互菜单
sudo yunzes-node也支持非交互子命令,每个菜单项都有对应的 CLI:
sudo yunzes-node install # 装并启动
sudo yunzes-node install --no-restart # 装但不启 restart=always(用于先 verify)
sudo yunzes-node verify # 三级验证:基础 / 网络 / 业务
sudo yunzes-node logs # 最近 100 行
sudo yunzes-node follow-log # 跟随日志
sudo yunzes-node ports # ss 看 yunzes-node PID 的监听端口
sudo yunzes-node check-panel # curl 探活每个节点的 panel API
sudo yunzes-node fake-test # 起 fake panel + 4 协议自测
sudo yunzes-node show-config # 自动隐藏 ApiKey 显示
sudo yunzes-node edit-config # 自动备份再编辑,JSON 校验失败不重启
sudo yunzes-node backup # 一次完整备份(config + certs + 镜像 ID)
sudo yunzes-node rollback # 列出备份并选一个回滚
sudo yunzes-node update # build/pull 新镜像 + 自动 PostCheck,失败自动回滚
sudo yunzes-node uninstall # 删容器/镜像,保留配置和证书
sudo yunzes-node uninstall-full # 全清;要求二次输入 "DELETE YUNZES NODE"完整命令清单:yunzes-node help。
智能模式 (panel-driven, 推荐)
yunzes-node install / gen-config 现在默认走智能模式:
请选择安装模式:
1) 智能模式 — 由面板提供节点列表 (推荐)
2) 手动模式 — 逐个输入 NodeID + NodeType
智能模式只需输入 ApiHost + SecretKey + ServerID(一个),脚本探测 ${ApiHost}/v2/server/${ServerID}?secret_key=...,由面板返回该 ServerID 上配置的所有协议(vless / shadowsocks / hysteria2 / ...)。生成的 config 是 StartNodes 风格(顶层 Api 块 + 空 Nodes 数组),运行时由面板下发每协议的端口、cipher、security 等参数,本地无需手动维护 NodeID/NodeType/CertConfig 列表。
如果面板不支持 /v2/server/{ID}(HTTP 404),脚本自动回退到手动模式。
国际化 (中文 / English)
默认中文。 第一次跑 yunzes-node 菜单时会交互提示选语言(root 写到 /opt/yunzes-node/state/locale),之后保持。脚本不看系统 LANG(绝大多数 VPS 默认 LANG=en_US.UTF-8,但那不代表用户偏好英文)。三种切语言方式:
# 1) 一次性切(环境变量优先级最高)
YUNZES_LANG=en sudo yunzes-node menu
YUNZES_LANG=zh sudo yunzes-node verify # 即便已经 lang en 持久了,本次仍 zh
# 2) 持久切(写到 /opt/yunzes-node/state/locale,所有后续运行都生效)
sudo yunzes-node lang en # 切英文
sudo yunzes-node lang zh # 切回中文
sudo yunzes-node lang reset # 删除偏好文件,恢复默认(zh)
# 3) 仅查看
yunzes-node lang # 不需要 root优先级:YUNZES_LANG env > /opt/yunzes-node/state/locale 文件 > 默认 zh。
每条 print_* 输出都通过内联的 _t "中文" "English" 翻译;维护时双语版本紧贴在一起便于审核。
彩色输出与 NO_COLOR
脚本默认输出彩色(步骤青、信息蓝、成功绿、警告黄、错误红、危险红、命令紫)。日志采集 / CI / 重定向到文件场景下脚本自动检测 ! -t 1 关闭颜色;想强制关闭也可以:
NO_COLOR=1 yunzes-node verify
NO_COLOR=1 yunzes-node fake-test 2>&1 | tee fake-test.log配置体检 validate-config
yunzes-node validate-config(或菜单 1 安装流程内自动调用)做语义校验:
- 每个节点
NodeID必须存在且不重复 - 每个节点
NodeType必须是支持列表里的协议 CertConfig.CertMode在http/dns/file/self时 CertDomain 必须非空(否则 C3 EnsureCertificate 会拒绝并触发容器 restart 循环)- 未知
CertMode报 warn,建议用none/file/self/http/dns
gen_config_interactive 在交互生成时也会强制 CertDomain / ApiKey / ACME Email 非空,从源头杜绝"按 Enter 跳过 → 容器死循环"。
panel API 预检 preflight_panel_check
yunzes-node check-panel(或安装流程内自动调用)在容器启动前 curl 每个节点的 ${ApiHost}/v1/server/config?protocol=...&server_id=...&secret_key=...:
- HTTP 200 → 节点能从 panel 拿到配置(OK)
- 401 / 403 → ApiKey 错或权限不足(warn)
- 404 → panel 路径或 NodeID 不对(fail,会询问是否继续)
- 5xx → panel 内部错误(warn)
- 000 → 不可达(fail)
verify_basic 检测 restart 循环
如果容器在最近 60 秒发生 ≥3 次 start 事件且 RestartCount ≥ 3,verify L1 直接报 FAIL "容器在重启循环",避免用户看到瞬时 "Up" 而误以为正常。
自动安装依赖
yunzes-node install 进入 ensure_dependencies 阶段会自动检测缺失的 docker.io / curl / jq / git / tar / iproute2 / python3,在 Debian / Ubuntu 上提示一次 y/N 后批量 apt install,并尝试 service docker start / systemctl start docker。用户拒绝 y 则中断流程。其他发行版只警告,让你手动装。
镜像来源 4 选 1
1) 从 GitHub 拉源码并本地构建 ← 默认推荐, REPO_URL=husibo16/yunzes-node
2) 使用当前目录源码构建 ← 仅当从源码 checkout 内运行脚本
3) 拉取远程 Docker 镜像
4) 手动输入镜像名
源码克隆到 /opt/yunzes-node/src/;再次安装时可选 git pull / 复用 / 重新 clone / 退出。
443/tcp → vless + reality
8388/tcp+udp → shadowsocks (脚本会自动同时登记 tcp+udp)
8443/udp → hysteria2
9443/tcp → trojan
端口规则(脚本和 Go 端 portRegistry 都强制执行):
- 同
transport(tcp / udp) + 同 port → 冲突; 0.0.0.0:p/T与具体 IPv4:p/T → 冲突(wildcard 覆盖具体);::与0.0.0.0同 p+T → 冲突(dual-stack 不一致);443/tcp与443/udp→ 不冲突,可共存(reality + hysteria2 同 443 的常见做法);- shadowsocks 默认 tcp+udp 双登记,因此不能同端口再放 hysteria2。
yunzes-node fake-test 用于离线验证整套 C0~C5 行为,不需要真实 panel:
- 启动一个 Python
127.0.0.1:9999fake panel,返回 4 协议的 NodeInfo - 写入临时 4 协议测试配置(vless+tls / shadowsocks / hysteria2 / vless+reality)
- 用
--restart no起容器(避免崩了无限重启刷屏) - 检查日志无
panic/nil pointer dereference/runtime error - 检查日志含
Core Selector/Adding node inbound/logical_tag/core=/runtime_key/protocol=/server_id/port=字段 - 用
ss -lntup校验 8101/tcp、8102/tcp、8102/udp、8103/udp、8104/tcp 五个监听都由 yunzes-node 占用 - 重启容器后日志含
cert_action=reuse(证明 C3 持久化生效)
跑完询问是否恢复原 config / 停 fake panel / 删测试容器 / 删测试证书。默认不会动你已有的 ApiKey 和真实证书,只在收尾时按你 y/N 选择处理。
yunzes-node update 走如下流程:
- PreCheck(同安装)
- 备份当前 config.json / certs /
docker inspect/ 镜像 ID 到/opt/yunzes-node/backups/<timestamp>/ - 重新 build(源码可用时)或 pull 镜像
- 删旧容器、起新容器
- PostCheck —— L1 失败立即触发自动回滚:
- 用旧镜像 ID 起回去
- 还原 config + certs
- 重跑一次 PostCheck
升级失败不会出现"容器没了 / 配置丢了 / 证书丢了"的状态,最坏情况是版本仍在升级前。
手动回滚到任一历史备份:yunzes-node rollback。
yunzes-node uninstall— 删容器、可选删镜像、可选删/usr/bin/yunzes-node,保留/etc/yunzes-node+ 备份。yunzes-node uninstall-full— 危险操作,要求输入DELETE YUNZES NODE二次确认,删除所有容器 + 镜像 + 配置 + 证书 + 备份 + 全局命令。
| 现象 | 原因 | 处理 |
|---|---|---|
permission denied while trying to connect to the docker API |
当前用户不在 docker 组 | sudo usermod -aG docker $USER,重开终端;或直接用 root 跑脚本 |
cert_action=error invalid reality config: missing reality_private_key |
panel 下发 reality 配置缺 private key | 检查 panel 后台 reality 节点配置是否完整 |
容器无限 Restarting (0) |
dummy / 离线 panel 被配成 ApiHost 但 --restart always |
用 yunzes-node fake-test 替代手动 dummy;或临时 redeploy --no-restart |
docker logs 出现 panic |
已通过 C5 修复理论上消除;如再发生,立即 yunzes-node backup 留证据,提 issue 附 docker logs |
|
| 升级后业务不通 | PostCheck 应已触发自动回滚;若没回滚,手动 yunzes-node rollback 选最近一个 |
|
| 端口 443 既要 reality 又要 hysteria2 | 一个 tcp 一个 udp 可共存;脚本会接受 |
如果你不想用菜单脚本,仓库里有 docker-compose.yml 和 Scripts/docker-run.sh 两个轻量入口可直接用,行为与菜单脚本一致。
# 通过-tags选项指定要编译的内核, 可选 xray,sing
GOEXPERIMENT=jsonv2 go build -v -o ./node -tags "xray sing with_quic with_grpc with_utls with_wireguard with_acme" -trimpath -ldflags "-s -w -buildid="本阶段采用单容器双核心模式:xray-core 与 sing-box 都以 Go 库形式链接进同一个 yunzes-node 二进制;不拆成 xray / sing 独立容器。
| 路径 | 用途 | 是否必须持久化 |
|---|---|---|
/etc/yunzes-node/config.json |
节点配置入口 | 是 |
/etc/yunzes-node/certs/ |
ACME / 自签证书 | 是(容器重建不能丢,否则会重复申请) |
容器内入口固定为:
yunzes-node server --config /etc/yunzes-node/config.json
docker build -t yunzes-node:test .构建阶段已在 Dockerfile 内固定 GOEXPERIMENT=jsonv2,并带齐 build tags:
sing xray with_quic with_grpc with_utls with_wireguard with_acme with_gvisor。
docker run -d \
--name yunzes-node \
--network host \
--restart always \
-v /etc/yunzes-node:/etc/yunzes-node \
yunzes-node:test或使用 docker-compose:
docker compose up -ddocker-compose.yml 已默认 network_mode: host + restart: always + 挂 /etc/yunzes-node。
Scripts/docker-run.sh 是一键脚本,等价于上面的 docker run,并会自动创建 host 目录、检查 config.json 是否存在、删除旧容器。
Scripts/docker-run.sh # host network
Scripts/docker-run.sh --bridge # 端口映射 fallback
Scripts/docker-run.sh --bridge --port 443:443/tcp --port 443:443/udp --port 80:80/tcpbridge 模式只适合固定端口的本地测试,不推荐生产。需要注意:
- ACME HTTP-01 需要把
80/tcp映射出来(-p 80:80/tcp) - Hysteria2 / TUIC 等 UDP 协议必须显式
-p xxxx:xxxx/udp,否则容器收不到 UDP - bridge 默认会做 SNAT,客户端真实 IP 会被遮掉,除非你额外配 proxy-protocol
- 多端口 / 大量端口情况下手动
-p易漏,host network 更适合
docker run -d \
--name yunzes-node \
--restart always \
-p 80:80/tcp \
-p 443:443/tcp \
-p 443:443/udp \
-v /etc/yunzes-node:/etc/yunzes-node \
yunzes-node:test/etc/yunzes-node 必须挂 host 目录,至少包含:
config.json— 节点配置;可热更新(容器内--watch会自动 reload)certs/— 由EnsureCertificate写入 ACME 颁发的证书 + 私钥;首次启动后会出现*.crt/*.key
容器重建只要 host 目录还在,证书会被复用:EnsureCertificate 在 reload / start 时 stat + parse X.509,未临近过期就 reuse,不会触发 ACME。RenewBeforeDays(默认 30)控制提前多少天续签,可在 CertConfig 里配。
| 主机 | host network | 备注 |
|---|---|---|
| Linux | ✅ 真实可用 | 生产推荐 |
| Linux + WSL2 | ✅ 真实可用 | 在 Linux 子系统内执行 |
| Windows Docker Desktop | 容器跑在 WSL2 VM 里,宿主端口拿不到;只能做 build / 启动 / 配置加载 / 日志 等降级验证 | |
| macOS Docker Desktop | 同上 |
真实的 host network 验证(80/tcp、UDP、host 端口绑定)必须在 Linux / WSL / VPS 上执行。
容器日志走 stdout/stderr,结构化字段:
docker logs -f yunzes-node启动事件每条日志会带:
logical_tag—[apiHost]-protocol:server_id,server-facing 标识core—xray或singruntime_key—core|logicalTag,进程内 inbound tag / limiter map keyprotocol— vless / vmess / trojan / shadowsocks / hysteria2 / tuic / anytlsserver_id— 节点 IDlisten_addr— 已归一("" →0.0.0.0)network—[tcp]/[udp]/[tcp udp](shadowsocks 双登记)port— listen 端口
证书事件额外带:
cert_action—issue/renew/reuse/reissue/errordomain/cert_file/key_fileremaining— 距离NotAfter的时长renew_before_days— 实际生效的续签阈值
# 1. 镜像构建
docker build -t yunzes-node:test .
# 2. Windows Docker Desktop 降级(无 host 网络)
docker run --rm \
-v /etc/yunzes-node:/etc/yunzes-node \
yunzes-node:test
# 3. Linux / WSL / VPS 最终验证
docker run --rm --network host \
-v /etc/yunzes-node:/etc/yunzes-node \
yunzes-node:test需要在 Linux 主机确认:
docker build成功- 容器启动且
docker logs看得到节点上线日志 ss -lntup | grep yunzes-node能看到 80/tcp、443/tcp、443/udp 等监听- 容器重启后
cert_action=reuse(不是renew或issue),证明证书目录被持久化 - Hysteria2 / TUIC 节点客户端能连上(验证 UDP 监听真的工作)
docker stop yunzes-node不 panic,docker logs收尾干净(C2 反向 Close + nil-skip)