[Nas折腾] 群晖 Synology NAS 的Docker的注册表无法打开的解决方法

本文最早写于 2023 年,记录的是群晖 Docker 注册表无法加载时,使用 v2rayA 透明代理解决问题的过程。2026 年重新排障后,DSM 旧版 iptables、v2rayA 新版内核路径以及 Docker 守护进程代理方式都发生了变化,因此本文已重写为一套可验证、可回滚的完整方案。
一、问题是什么
群晖 Docker 套件可以正常启动,但“注册表”页面无法加载,或者执行下面的命令超时:
docker pull hello-world
这类问题不一定都是“被墙”,常见原因包括:
- DNS 返回了错误地址;
- Docker Hub 的鉴权域名或对象存储域名无法连接;
- DSM 的 Docker 守护进程没有使用代理;
- v2rayA 节点本身能连通,但透明代理规则没有生效;
- 新版 v2rayA 与 DSM 自带的旧 iptables 模块不兼容;
- Docker 守护进程和普通 Shell 使用的网络路径并不相同。

二、先理解三种代理方式
1. 显式代理
应用主动连接 SOCKS5 或 HTTP 代理端口。例如:
SOCKS5: 127.0.0.1:20170
HTTP: 127.0.0.1:20171
规则: 127.0.0.1:20172
其中 20172 会经过 v2rayA 的分流规则,特别适合 Docker 守护进程和 Hysteria2 服务端显式调用。
2. 系统代理
操作系统把代理地址告诉支持系统代理的应用。只对主动读取系统代理设置的程序有效,Docker 守护进程不一定自动继承。
3. 透明代理
应用不知道代理存在,v2rayA 通过 iptables、TProxy 或 TUN 截获流量。优点是覆盖面广,缺点是依赖内核模块;DSM 是定制 Linux,最容易在这里遇到兼容问题。
本文的推荐架构是:
Docker daemon
|
| HTTP_PROXY=http://127.0.0.1:20172
v
v2rayA RoutingA
|
+-- Docker / 国外域名 --> proxy --> 国外节点
|
+-- 中国域名 / 私网 --> direct
Hysteria2 server
|
+-- 192.168.0.0/16 等私网 --> direct
|
+-- 公网请求 --> SOCKS5 127.0.0.1:20170 --> v2rayA
这样不需要让 DSM 全机进入透明代理,也不会把 NAS 内网访问错误地送到国外节点。
三、部署最新版 v2rayA
以下示例使用群晖旧版 Docker 套件。Container Manager 用户请按自己的实际路径调整。
1. 创建持久化目录
mkdir -p /volume1/docker/v2raya/etc
printf 'nameserver 223.5.5.5\nnameserver 1.1.1.1\n' \
> /volume1/docker/v2raya/etc/resolv.conf
2. 拉取镜像
/usr/local/bin/docker pull mzz2017/v2raya
3. 先确认镜像内的核心路径
不同版本的镜像可能使用不同路径。新版镜像出现“核心版本必须完全一致”时,不要随意挂载外部旧核心。
/usr/local/bin/docker run --rm --entrypoint sh mzz2017/v2raya \
-c 'command -v v2raya_core || command -v xray || command -v v2ray'
本文实机验证的新版镜像返回:
/usr/bin/v2raya_core
4. 停止并删除旧容器
配置保存在 /volume1/docker/v2raya/etc,删除容器不会删除配置。
/usr/local/bin/docker stop v2raya 2>/dev/null || true
/usr/local/bin/docker rm v2raya 2>/dev/null || true
5. 启动 v2rayA
/usr/local/bin/docker run -d \
--restart=always \
--privileged \
--network=host \
--name v2raya \
-e V2RAYA_LOG_FILE=/tmp/v2raya.log \
-e V2RAYA_V2RAY_BIN=/usr/bin/v2raya_core \
-e V2RAYA_NFTABLES_SUPPORT=off \
-e IPTABLES_MODE=legacy \
-v /lib/modules:/lib/modules:ro \
-v /volume1/docker/v2raya/etc/resolv.conf:/etc/resolv.conf \
-v /volume1/docker/v2raya/etc:/etc/v2raya \
mzz2017/v2raya
检查状态:
/usr/local/bin/docker ps --filter name=v2raya
/usr/local/bin/docker logs --tail 100 v2raya
netstat -lntp | grep -E '2017|20170|20171|20172'
Web 管理页面为:
http://<NAS_LAN_IP>:2017/

四、配置 v2rayA 分流
导入并启用一个可用的代理节点,然后在“设置”中选择规则端口的分流模式,例如 RoutingA。

推荐规则:
default: proxy
domain(domain:mail.qq.com)->direct
domain(geosite:docker)->proxy
domain(geosite:google-scholar)->proxy
domain(geosite:category-scholar-!cn, geosite:category-scholar-cn)->direct
domain(geosite:geolocation-!cn, geosite:google)->proxy
domain(geosite:cn)->direct
ip(geoip:hk,geoip:mo)->proxy
ip(geoip:private,geoip:cn)->direct

最关键的一条是:
domain(geosite:docker)->proxy

DNS 可按以下思路配置:
| DNS | 域名范围 | 出口 |
|---|---|---|
localhost | geosite:private | direct |
223.5.5.5 | geosite:cn | direct |
1.0.0.1 | 留空,作为兜底 | proxy |
五、让 Docker 守护进程真正经过 v2rayA
这里只启动 v2rayA 还不够。Docker Hub 的请求由 dockerd 发出,必须明确给 Docker 守护进程配置代理。
1. 创建 systemd drop-in
mkdir -p /etc/systemd/system/pkg-Docker-dockerd.service.d
cat > /etc/systemd/system/pkg-Docker-dockerd.service.d/http-proxy.conf <<'EOF'
[Service]
Environment="HTTP_PROXY=http://127.0.0.1:20172"
Environment="HTTPS_PROXY=http://127.0.0.1:20172"
Environment="NO_PROXY=localhost,127.0.0.1,::1,192.168.0.0/16,10.0.0.0/8,172.16.0.0/12"
EOF
这里使用 20172,因为它会执行上面的 RoutingA 分流规则;使用 20171 时通常是普通 HTTP 代理入口。
2. 重载并重启 Docker 服务
重启 Docker 守护进程可能短暂影响正在运行的容器,请安排维护窗口,并确保关键容器配置了重启策略。
systemctl daemon-reload
systemctl restart pkg-Docker-dockerd
3. 验证环境变量
systemctl show pkg-Docker-dockerd --property=Environment
预期能看到:
HTTP_PROXY=http://127.0.0.1:20172
HTTPS_PROXY=http://127.0.0.1:20172
也可以直接检查运行中 dockerd 的环境:
tr '\0' '\n' < /proc/$(cat /var/run/docker.pid)/environ \
| grep -i proxy
4. 验证 Docker Hub
先测试 Registry API:
curl -I https://registry-1.docker.io/v2/
返回 HTTP 401 Unauthorized 反而表示 DNS、TLS 和 Registry 已经连通,只是没有携带 Docker Hub 鉴权信息。
再做一次真实拉取:
/usr/local/bin/docker pull hello-world
实机验证结果:
Status: Image is up to date for hello-world:latest
docker.io/library/hello-world:latest
此时重新打开群晖 Docker 的“注册表”页面,应能正常查询镜像。

六、为什么新版 v2rayA 的透明代理会失败
1. 核心路径不匹配
典型错误:
failed to get v2raya_core version:
fork/exec /usr/local/bin/v2ray: no such file or directory
原因是容器启动参数仍指向旧路径。先用本文前面的命令检查镜像内实际路径,再设置 V2RAYA_V2RAY_BIN。
2. redirect 与 DSM iptables 不兼容
典型错误:
iptables-legacy -t nat -A DNS_REDIRECT -j REDIRECT --to-port 52353
iptables: Need TCP, UDP, SCTP or DCCP with port specification
这不是普通 DNS 配置错误,而是新版 v2rayA 生成的透明代理规则与 DSM 旧内核、旧 iptables 模块组合不兼容。官方群晖透明代理文档也明确说明,DSM 可能缺少透明代理需要的 iptables 模块。
可选方案:
1. 按官方文档补齐与 DSM 内核完全匹配的 iptables 模块;
2. 使用兼容的旧版 v2rayA;
3. 像本文一样关闭透明代理,改用 20170/20172 显式代理。
不建议直接升级 DSM 的系统 iptables。群晖内核、套件脚本和 Docker 都依赖它,强行替换可能导致防火墙、端口映射或套件服务异常。
3. TinyTun 缺失
典型错误:
tinytun binary not found:
please install tinytun or use --tinytun-bin to specify its path
这说明选择了 TinyTun 实现,但镜像或宿主机没有对应二进制。对于“只让 Docker 和 Hysteria2 使用代理”的目标,没有必要为了 TinyTun 改动整个 DSM 网络栈。
七、让 Hysteria2 把 NAS 当作远程隧道和国外中转站
Hysteria2 使用 QUIC/UDP 建立隧道,但它可以代理隧道内的 TCP 和 UDP 业务。WebDAV、DSM 网页和 iperf3 的 TCP 流量都可以通过 Hysteria2 传输。
下面使用脱敏示例:
listen: :8443
acme:
domains:
- nas.example.com
email: [email protected]
ca: letsencrypt
dir: /usr/local/etc/hysteria2/acme
type: dns
dns:
name: cloudflare
config:
cloudflare_api_token: <CLOUDFLARE_API_TOKEN>
auth:
type: password
password: <HYSTERIA_PASSWORD>
obfs:
type: salamander
salamander:
password: <SALAMANDER_PASSWORD>
congestion:
type: bbr
outbounds:
- name: direct
type: direct
direct:
mode: 4
- name: v2raya
type: socks5
socks5:
addr: 127.0.0.1:20170
acl:
inline:
- direct(127.0.0.0/8)
- direct(10.0.0.0/8)
- direct(172.16.0.0/12)
- direct(192.168.0.0/16)
- v2raya(all)
路由逻辑是:
外部客户端
|
| UDP 8443 / Hysteria2
v
NAS Hysteria2 server
|
+-- NAS 和公司内网地址 --> direct
|
+-- Google 等公网地址 --> SOCKS5 20170 --> v2rayA --> 国外节点
因此:
- 访问 NAS 私网地址时不会绕到国外;
- 客户端把 Google 交给 NAS 的 Hysteria2 节点时,NAS 会继续交给 v2rayA;
- v2rayA 的 RoutingA 再决定直连还是走国外节点;
- Hysteria2 的
server.yaml是服务端出口策略,不等同于客户端路由表。
八、用 iperf3 测试隧道真实吞吐量
网页测速会受到浏览器、JavaScript、HTTP 缓存和单连接影响。要测 NAS 与远程客户端之间的纯网络吞吐量,推荐 iperf3。
1. 在 NAS 启动 iperf3 服务端
/usr/local/bin/docker pull networkstatic/iperf3
/usr/local/bin/docker run -d \
--restart=unless-stopped \
--name iperf3-server \
-p 5201:5201/tcp \
networkstatic/iperf3 \
-s -p 5201
验证监听:
/usr/local/bin/docker ps --filter name=iperf3-server
netstat -lntp | grep 5201
2. 在 Mac 安装客户端
brew install iperf3
3. 通过 Hysteria2 测试
先确保 Shadowrocket、v2rayN 或其他客户端已启用 TUN,并把示例 NAS 地址 192.168.10.20/32 路由到 Hysteria2 节点。
测试客户端上传到 NAS:
iperf3 -c 192.168.10.20 -p 5201 -P 4 -t 20
测试客户端从 NAS 下载:
iperf3 -c 192.168.10.20 -p 5201 -P 4 -t 20 -R
双向同时测试:
iperf3 -c 192.168.10.20 -p 5201 -P 4 -t 20 --bidir
参数说明:
-P 4:4 条并行流,减少单连接窗口对结果的影响;-t 20:持续 20 秒;-R:反向测试,由 NAS 向客户端发送;--bidir:上下行同时测试。
iperf3 本身不支持 SOCKS5。客户端只有“应用代理”而没有 TUN 时,直接执行 iperf3 不会自动进入 Hysteria2。此时应启用 TUN 路由,或使用 Hysteria2 内建测速。
4. Hysteria2 内建测速
Hysteria2 2.3.0 以后支持内建测速。服务端增加:
speedTest: true
重启 Hysteria2 后,客户端执行:
hysteria speedtest -c client.yaml --duration 20s
内建测速只测试“客户端到 Hysteria2 服务端”的隧道性能,不经过 ACL 和 v2rayA 出站,适合把问题分成两段:
1. Hysteria2 隧道本身是否足够快;
2. NAS 再经过 v2rayA 访问公网是否成为瓶颈。
九、排障命令清单
v2rayA 是否在运行
/usr/local/bin/docker ps --filter name=v2raya
netstat -lntp | grep -E '2017|20170|20171|20172'
显式 HTTP 代理是否可用
curl -x http://127.0.0.1:20171 \
-I https://registry-1.docker.io/v2/
规则代理是否可用
curl -x http://127.0.0.1:20172 \
-I https://registry-1.docker.io/v2/
SOCKS5 是否可用
curl --socks5-hostname 127.0.0.1:20170 \
-I https://www.google.com/
Docker 守护进程是否继承代理
systemctl show pkg-Docker-dockerd --property=Environment
tr '\0' '\n' < /proc/$(cat /var/run/docker.pid)/environ \
| grep -i proxy
Hysteria2 是否监听
netstat -lnup | grep 8443
tail -n 100 /usr/local/var/log/hysteria2/server.log
DDNS 是否误取代理出口 IP
如果 NAS 的普通 HTTP 请求已经经过 v2rayA,下面的命令可能得到国外节点 IP:
curl -4 ifconfig.me
更新 DDNS 时应使用不会经过 HTTP 代理的方式获取真实公网地址,例如:
nslookup myip.opendns.com 208.67.222.222
十、适合拆成两期视频的讲解结构
第一期:Hysteria2 远程访问 NAS
1. 开场展示手机、Mac、iPad、Apple TV 远程播放高码率视频;
2. 展示 NAS 上传速率;
3. 解释 UDP 8443、DDNS、TLS、ACL 和私网直连;
4. Shadowrocket/v2rayN 只把 NAS 网段送进隧道;
5. 用 iperf3 对比直连、旧隧道和 Hysteria2;
6. 总结瓶颈仍受 NAS 所在网络上行带宽限制。
第二期:NAS 通过 v2rayA 访问 Docker Hub并作为国外中转站
1. 复现 Docker 注册表无法加载;
2. 部署最新版 v2rayA;
3. 解释 20170/20171/20172;
4. 配置 Docker daemon 的 systemd 代理 drop-in;
5. 演示 401 为什么代表 Registry 已连通;
6. 演示 docker pull hello-world;
7. 配置 Hysteria2 outbounds + ACL;
8. 对比“访问 NAS 私网”和“经 NAS 访问 Google”的两条链路。
十一、安全提醒
- 不要在文章、视频或分享链接中公开 Hysteria2 密码、Salamander 密码、节点 UUID、Cloudflare API Token 和真实公网 IP;
- DDNS 记录只做 DNS 解析,不要为 Hysteria2 UDP 端口开启 Cloudflare 橙云代理;
- 公网只开放必要的 UDP 端口;
- 给 Hysteria2 使用强密码和有效 TLS 证书;
20170/20171/20172建议只监听127.0.0.1,不要直接暴露到公网;- 修改 Docker 服务前先备份配置,并确保有 SSH 回退通道。
参考资料
1. 本文记录的是作者自己的设备与网络环境,示例域名、IP、密码和令牌均已脱敏;
2. 不同 DSM、Docker 和 v2rayA 版本可能存在差异,执行前请备份;
3. 请遵守所在地法律法规和网络服务条款;
4. 博客中标注原创的文章,版权归原作者 Snailszzy 所有,转载或引用请注明来源。