绿联云NAS Docker透明代理完全指南
绿联云 NAS Docker 透明代理完全指南:从入门到精通
设备环境:绿联云 DH4300PLUS(ARM64)· UGOS Pro(Debian 定制)· Docker · v2rayA 2.2.7.5 + Xray 26.1.23
目标:在绿联云 NAS 上部署 v2rayA 透明代理,实现局域网设备(手机、电脑、游戏主机等)仅修改网关即可科学上网,同时支持 IPv6 双栈和安全加固。
本文是四次深度排障实战的完整记录,涵盖 Docker 网络模式选型、macvlan 网络配置、IPv6 SLAAC 获取、透明代理模式选择、DNS 防污染、安全加固等全部核心话题。
目录
- 背景与目标
- 踩坑之路:从 bridge 到绿联云面板 macvlan 再到命令行 macvlan
- 正确创建 Macvlan 网络(命令行方式)
- v2rayA 容器部署与 IPv4 验证
- IPv6 双栈配置:ULA + SLAAC 方案
- 透明代理模式选择:tproxy / redirect / TUN
- v2rayA 面板配置详解
- 安全加固:封锁公网 IPv6 暴露
- Macvlan 宿主机通信:vlink 桥接
- 其他容器走代理(青龙面板等)
- 持久化与开机自启
- 完整命令参考与 docker-compose
- 常见问题与排障速查
1. 背景与目标
家庭网络中,想让所有设备(手机、平板、电视、游戏主机)无感科学上网,最优雅的方案是旁路由 / 透明网关:
- 路由器负责基本的 DHCP 和 WiFi;
- NAS 运行代理容器,作为局域网设备的网关;
- 设备只需把网关指向 NAS 的 IP,即可自动走代理。
绿联云 NAS(UGOS Pro)底层基于 Debian,原生支持 Docker,硬件性能足以胜任透明代理的加解密负载。但由于 UGOS 在内核、Docker 配置、网络架构上做了大量定制,实际部署中会遇到诸多”绿联专属”的坑。本文将逐一记录并给出解决方案。
2. 踩坑之路:从 bridge 到绿联云面板 macvlan 再到命令行 macvlan
本节记录真实的实验路径。如果你只想看结论,可以直接跳到第 3 节。
2.1 第一步:bridge / host 模式——此路不通
最初的想法很简单:用 Docker 默认的 bridge 网络或 host 模式跑 v2rayA。结果两条路都走不通:
| 模式 | 尝试结果 |
|---|---|
| bridge(默认) | 容器 IP 在 docker0 虚拟网段内,局域网设备无法直接访问容器 IP,无法用作网关 |
| host | v2rayA 启动透明代理时会执行 sysctl -w net.ipv4.ip_forward=0,直接关闭宿主机 IP 转发,导致 NAS 上所有 bridge 容器(qBittorrent、Jellyfin 等)瞬间断网 |
结论:透明代理需要容器拥有独立的局域网 IP,只能用 macvlan 模式。
2.2 第二步:用绿联云可视化面板创建 macvlan——掉入深坑
知道要用 macvlan 后,自然的想法是通过绿联云的 Docker 可视化管理界面来创建。然而面板在引导创建 Macvlan 时,会强制要求先创建一个虚拟网桥来桥接物理网卡、系统虚拟网卡和 Macvlan 网络。
创建后发现透明代理完全不工作——流量转发全部被拦截。尝试了大量排查:
- 检查 iptables 规则,发现 FORWARD 链默认 DROP;
- 手动
iptables -F清空规则后暂时能通,但 NAS 其他 Docker 服务又全挂了; - 怀疑是 v2rayA 配置问题,反复调整代理模式、DNS 设置,均无效。
经过反复排查,最终定位到根因:
绿联云 UGOS 系统会将物理网卡 eth0 包裹在一个虚拟网桥 bridge0 中。UI 创建的 macvlan 实际上挂载在 bridge0 上而非 eth0 上,导致所有 macvlan 流量经过 bridge0 时被 bridge-nf-call-iptables 强制送入宿主机 iptables 链,被 Docker 的默认 FORWARD DROP 策略拦截。
eth0 → bridge0 (虚拟网桥) → 宿主机 IP
↑
macvlan 挂在这里 → 流量被 bridge-nf-call-iptables 拦截!
# ❌ UI 创建的 macvlan 等效于
docker network create -d macvlan -o parent=bridge0 ...
2.3 第三步:弃用面板,命令行直接绑定 eth0——跑通 IPv4
明白了根因后,操作分两步:
- 先在绿联云的 Docker 可视化面板中删除之前创建的 Macvlan 网络,然后进入 系统设置 → 网络 中删除 UI 自动创建的虚拟网桥(这一步是关键——删除网桥后
eth0才会从bridge0中释放出来); - 通过 SSH 命令行直接绑定物理网卡
eth0重新创建 macvlan:
# ✅ 正确做法:命令行创建,直接绑定 eth0
docker network create -d macvlan \
--subnet=192.168.31.0/24 \
--gateway=192.168.31.1 \
-o parent=eth0 \
macvlan_v2raya
启动 v2rayA 容器,手机设置网关为容器 IP,IPv4 透明代理一次跑通。
2.4 第四步:进一步跑通 IPv6 双栈
IPv4 成功后,继续攻克 IPv6(详见第 5 节)。
2.5 macvlan 的核心优势
回顾整个过程,macvlan 模式(正确绑定到 eth0)的核心优势:
- 容器拥有独立的局域网 IP(如
192.168.31.2),手机可以直接把网关指向它; - 容器拥有独立的网络命名空间,iptables 规则只作用于容器内部,不影响宿主机和其他容器;
- 直接绑定物理网卡时,完全绕过
bridge-nf-call-iptables等内核参数干扰。
3. 正确创建 Macvlan 网络(命令行方式)
3.1 创建命令
# ✅ 直接绑定物理网卡 eth0
docker network create -d macvlan \
--subnet=192.168.31.0/24 \
--gateway=192.168.31.1 \
-o parent=eth0 \
macvlan_v2raya
3.2 释放 eth0:删除绿联云的虚拟网桥
绿联云系统默认将 eth0 包裹在虚拟网桥 bridge0 中。如果 eth0 仍被 bridge0 占用(brctl show bridge0 可查看),macvlan 将无法直接绑定 eth0。需要先释放:
方法一(推荐):通过绿联云系统 UI 删除
进入绿联云管理界面 → 系统设置 → 网络,找到之前创建的虚拟网桥并删除。删除后系统会自动将网络切换回物理网卡 eth0 直连,无需手动配置 IP 和路由。
注意:删除网桥的瞬间 NAS 管理连接会短暂中断,刷新页面即可恢复。
方法二(备选):通过命令行手动拆除
如果 UI 中找不到删除选项,可以通过 SSH 手动操作:
# 查看 bridge0 是否包含 eth0
brctl show bridge0
# 如果包含,将 eth0 从 bridge0 中移除
ip link set bridge0 down
brctl delif bridge0 eth0
ip link del bridge0
# 将 IP 迁移到 eth0
ip addr add 192.168.31.178/24 dev eth0
ip link set eth0 up
ip route add default via 192.168.31.1
⚠️ 风险提示:命令行操作时 NAS 的管理 IP 会暂时中断,建议通过物理连接或 SSH 多开一个会话操作。此方式未经本文作者实测,仅作为理论参考。
3.3 替代方案:关闭 bridge-nf-call-iptables
⚠️ 未实测:本文作者未实际尝试此方案,仅作为理论备选。
如果不想拆 bridge0,可以关闭内核参数:
sysctl -w net.bridge.bridge-nf-call-iptables=0
sysctl -w net.bridge.bridge-nf-call-ip6tables=0
这样 bridge 上的流量不再被送入 iptables,但可能影响 Docker 的其他网络隔离功能。
4. v2rayA 容器部署与 IPv4 验证
命令行创建 macvlan 后(第 2.3 步),下一步就是启动 v2rayA 容器,验证 IPv4 透明代理是否跑通。如果你计划直接部署 IPv6 双栈版本,可以跳到第 5 节和第 12 节的终极命令。
4.1 启动容器
假设已按第 3 节创建好 macvlan 网络:
docker run -d \
--name v2raya \
--restart=always \
--privileged \
--network=macvlan_v2raya \
--ip=192.168.31.2 \
--sysctl net.ipv4.ip_forward=1 \
-v /volume1/docker/v2raya/etc:/etc/v2raya \
mzz2017/v2raya
关键参数说明:
| 参数 | 作用 |
|---|---|
--privileged |
授予完整内核权限,透明代理需要操作 iptables/路由表 |
--network=macvlan_v2raya |
使用 macvlan 网络 |
--ip=192.168.31.2 |
指定固定 IP,作为局域网网关地址 |
--sysctl net.ipv4.ip_forward=1 |
容器内启用 IP 转发 |
-v ...:/etc/v2raya |
持久化配置文件 |
4.2 访问 Web 面板
浏览器打开 http://192.168.31.2:2017,首次访问需设置管理员密码。
4.3 客户端配置
手机/电脑的 WiFi 设置:
- IP:手动或自动(保持局域网段即可)
- 网关:
192.168.31.2(v2rayA 容器 IP) - DNS:
192.168.31.2或保持默认均可(v2rayA 会劫持 DNS 流量)
5. IPv6 双栈配置:ULA + SLAAC 方案
IPv4 透明代理跑通后(第 2.3 步),下一个目标就是让 IPv6 也走代理。这对应踩坑之路的第四步,也是整个部署中最”反直觉”的环节——Docker 对 IPv6 的支持远不如 IPv4 开箱即用,需要一套”ULA 激活 + SLAAC 获取”的组合拳。
5.1 问题背景
家用宽带的 IPv6 前缀(如 2408:xxxx:xxxx:xxxx::/64)是动态的,每隔 48-72 小时或重启路由器后会变化。如果在 macvlan 网络中写死公网 IPv6 前缀,前缀变化后容器 IPv6 立刻失效。
5.2 解决方案:ULA 激活 + SLAAC 获取公网地址
核心思路:
- 使用 ULA 地址(
fd00:8::/64) 作为 macvlan 的 IPv6 子网,仅用于激活 Docker 的 IPv6 协议栈; - 通过 SLAAC(
accept_ra=2) 让容器自动从路由器获取公网 IPv6 地址; - 删除 Docker 自动生成的 ULA 默认路由,避免路由冲突。
5.3 创建双栈 macvlan 网络
docker network create -d macvlan \
--subnet=192.168.31.0/24 \
--gateway=192.168.31.1 \
--ipv6 \
--subnet=fd00:8::/64 \
--gateway=fd00:8::1 \
-o parent=eth0 \
macvlan_v2raya
关键发现:Docker 默认不为 macvlan 接口启用 IPv6。必须在
docker network create时加上--ipv6参数,否则容器网卡的 IPv6 协议栈不会被激活,无法接收 RA(Router Advertisement)。
5.4 daemon.json 配置(可选)
对于 macvlan 模式,通常不需要修改 daemon.json。以下配置仅在使用 bridge 网络的 IPv6 时需要:
{
"data-root": "/volume1/@docker",
"ipv6": true,
"fixed-cidr-v6": "fd00:1::/64",
"experimental": true,
"ip6tables": true
}
5.5 启动带 IPv6 支持的容器
docker run -d \
--name v2raya \
--restart=always \
--privileged \
--network=macvlan_v2raya \
--ip=192.168.31.2 \
--sysctl net.ipv4.ip_forward=1 \
--sysctl net.ipv6.conf.all.forwarding=1 \
--sysctl net.ipv6.conf.all.accept_ra=2 \
--sysctl net.ipv6.conf.default.accept_ra=2 \
--sysctl net.ipv6.conf.eth0.accept_ra=2 \
-v /volume1/docker/v2raya/etc:/etc/v2raya \
--entrypoint sh \
mzz2017/v2raya \
-c "echo 1 > /proc/sys/net/ipv4/ip_nonlocal_bind; ip -6 route del default via fd00:8::1 2>/dev/null || true; ip6tables -I INPUT -p tcp --dport 2017 -j DROP; exec v2raya"
关键 sysctl 参数解析
| 参数 | 作用 |
|---|---|
net.ipv6.conf.all.forwarding=1 |
启用 IPv6 转发(旁路由必需) |
net.ipv6.conf.all.accept_ra=2 |
值为 2 表示即使在 forwarding 开启时也接受 RA |
net.ipv6.conf.eth0.accept_ra=2 |
对容器内 eth0 接口单独设置 |
为什么
accept_ra必须是 2? Linux 内核的默认行为是:当forwarding=1时自动忽略 RA(因为转发节点不应该动态获取地址)。设为2可以强制覆盖这一行为。
entrypoint 启动脚本解析
# 1. 开启 ip_nonlocal_bind(tproxy 透明代理必需,否则 connect: invalid argument)
echo 1 > /proc/sys/net/ipv4/ip_nonlocal_bind
# 2. 删除 Docker 自动创建的 ULA 默认路由(避免 IPv6 流量走 fd00:8::1 黑洞)
ip -6 route del default via fd00:8::1 2>/dev/null || true
# 3. 在 IPv6 防火墙中拦截对 2017 端口的入站连接(安全加固,详见第 8 节)
ip6tables -I INPUT -p tcp --dport 2017 -j DROP
# 4. 启动 v2rayA 主进程
exec v2raya
5.6 验证 IPv6
# 进入容器
docker exec -it v2raya sh
# 查看网卡地址,应看到 2408 开头的公网 IPv6
ip -6 addr show eth0
# 测试 IPv6 连通性
ping6 ipv6.google.com
成功获取公网 IPv6 地址示例:
inet6 2408:xxxx:xxxx:xxxx:42:acff:fe12:3456/64 scope global dynamic
inet6 fd00:8::2/64 scope global ← ULA 地址(仅用于激活协议栈)
inet6 fe80::42:c0ff:fea8:1f02/64 scope link ← 链路本地地址
6. 透明代理模式选择:tproxy / redirect / TUN
IPv4 和 IPv6 网络层面都跑通后,接下来需要选择和调优透明代理的工作模式。看似只是 v2rayA 面板上选一个选项的事,实际上又踩了不少坑——tproxy 模式一度因为
connect: invalid argument和 DNS 死锁被误判为”在 macvlan 上不可用”,最终经过深度排查才定位到ip_nonlocal_bind这个隐藏的内核参数。
6.1 三种模式对比
| 模式 | 工作层级 | TCP | UDP | 性能 | macvlan 兼容性 |
|---|---|---|---|---|---|
| redirect | iptables NAT 表 | ✅ | ❌ | 高 | ✅ 好 |
| tproxy | iptables mangle 表 | ✅ | ✅ | 最高 | ✅ 需正确配置 |
| system tun | 虚拟 TUN 网卡 | ✅ | ✅ | 中高 | ✅ 好 |
| gvisor tun | 用户态 TUN 模拟 | ✅ | ✅ | 中 | ✅ 最好 |
6.2 tproxy 在 macvlan 中的排障实录
在最初的测试中,tproxy 模式在 macvlan 容器内会遇到 connect: invalid argument 错误。经过多轮深度排查,最终定位到两个根因,并全部解决:
根因一:ip_nonlocal_bind 未开启(关键!)
tproxy 需要绑定非本机 IP(冒充被劫持流量的目标地址)。绿联云系统的 net.ipv4.ip_nonlocal_bind 默认为 0,这直接导致了 connect: invalid argument 错误。修复方法:
# 在容器内开启(必须在 v2rayA 启动前执行)
echo 1 > /proc/sys/net/ipv4/ip_nonlocal_bind
# 或
sysctl -w net.ipv4.ip_nonlocal_bind=1
这是整个 tproxy 问题的核心根因,并非 macvlan 与 tproxy 不兼容,而是缺少这个内核参数。
根因二:DNS 自拦截死锁
macvlan 容器拥有独立的网络命名空间,tproxy 的 iptables 规则会劫持容器自身发出的 DNS 请求,形成死循环:
v2rayA 需要解析代理节点域名 → DNS 请求被自己的 tproxy 规则拦截 → 再次交给 v2rayA 处理 → 无限循环
解决方案:
- 代理节点配置使用 IP 地址而非域名;
- DNS 服务器使用直连 IP(如
223.5.5.5、8.8.8.8),避免经过域名二次解析; - v2rayA 中将”防止 DNS 污染”设为关闭或 DoH(DoH 更安全但首屏可能稍慢);
- DNS 设置中排除代理节点域名的解析。
内核兼容性验证
通过 ping -m 255 和 ip rule add fwmark 测试,确认绿联云内核完整支持 SO_MARK 和策略路由(CONFIG_IP_MULTIPLE_TABLES=y)。实际验证中,tproxy 所需的 xt_TPROXY 模块、table 100 策略路由、fwmark 0x40/0xc0 标记规则均正常工作,iptables 链(TP_PRE、TP_OUT、TP_RULE、TP_MARK)的包计数器持续增长,日志中出现 [transparent -> proxy] 记录,证明 tproxy 在 macvlan 环境中完全可用。
6.3 最终推荐:tproxy 模式
经过完整排障,tproxy 在 macvlan 环境中完全可用,并且是性能最优的选择:
- 完美支持 TCP + UDP(游戏主机联机无忧);
- 内核级透明代理,性能最高,CPU 开销最低;
- 相比 TUN 模式少约 10-20% 的 CPU 使用率(TUN 需要用户态 ↔ 内核态数据拷贝);
- IPv4 和 IPv6 双栈 tproxy 均可正常工作。
tproxy 的前置条件(缺一不可):
# 1. 开启 ip_nonlocal_bind(核心!否则 connect: invalid argument)
sysctl -w net.ipv4.ip_nonlocal_bind=1
# 2. 开启 IP 转发
sysctl -w net.ipv4.ip_forward=1
# 3. 确保容器以 --privileged 运行(需要操作 iptables mangle 表和策略路由)
备选方案:如果因任何原因无法使用 tproxy(如内核缺少 xt_TPROXY 模块),可退而求其次选择 system tun 或 gvisor tun 模式,兼容性好但性能略低。
7. v2rayA 面板配置详解
7.1 核心设置
在 v2rayA 的 设置 (Settings) 页面:
| 设置项 | 推荐值 | 说明 |
|---|---|---|
| 透明代理/系统代理实现方式 | tproxy | 性能最优;如不可用改 system tun |
| 透明代理/系统代理 | 启用:大陆白名单模式 | 国内直连,其余走代理 |
| 防止 DNS 污染 | 关闭 或 DoH | 关闭最稳;DoH 更安全但首屏可能稍慢 |
| 特殊模式 | 关闭 | 非软路由环境无需开启 |
| TCPFastOpen | 关闭或保持默认 | 部分线路不支持会导致连接失败 |
| 多路复用(Mux) | 关闭 | 开启会增加延迟,仅在线路极差时考虑 |
| 流量嗅探 | 启用 | 关键!用于纠偏被污染的 DNS 结果 |
7.2 流量嗅探(Sniffing)的重要性
嗅探功能是 v2rayA 透明代理的”灵魂”:
- 手机向路由器发起 DNS 请求,可能拿到被污染的错误 IP;
- 手机向错误 IP 发起连接,流量经过 v2rayA;
- v2rayA 嗅探 TLS ClientHello 中的 SNI(域名信息),发现实际要访问
youtube.com; - v2rayA 丢弃错误 IP,在远端重新解析正确地址并建立连接。
必须开启 QUIC 嗅探:YouTube App 大量使用 QUIC(UDP 443)协议。如果不开启 QUIC 嗅探,App 可能无限转圈。
7.3 白名单模式注意事项
“大陆白名单”模式会在 iptables 中注入数千条中国 IP 段的 RETURN 规则。在 ARM 架构的 NAS 上,这可能导致:
- 规则注入时间极长(数十秒甚至数分钟);
- 每个数据包都要遍历所有规则,造成显著的 CPU 负载和延迟。
如果遇到性能问题,建议改用 GFWList 模式(仅代理被墙域名),规则数量大幅减少,性能压力显著降低。(⚠️ 本文作者使用的是白名单模式,GFWList 模式未实测。)
8. 安全加固:封锁公网 IPv6 暴露
IPv6 双栈跑通、tproxy 模式调通之后,本以为大功告成。然而在一次偶然的测试中,用手机 5G 流量直接访问容器的公网 IPv6 地址,竟然打开了 v2rayA 管理面板——这意味着任何人都可以从公网控制你的代理服务。
8.1 问题发现
配置 IPv6 双栈后,v2rayA 容器获得了公网 IPv6 地址(如 2408:xxxx:xxxx:xxxx:42:acff:fe12:3456)。由于 v2rayA 默认监听所有网络接口,Web 管理面板直接暴露在公网:
手机 5G 流量访问 http://[2408:...]:2017 → 直接打开管理面板!
8.2 尝试过的方案
| 方案 | 结果 |
|---|---|
设置环境变量 V2RAYA_ADDRESS=0.0.0.0:2017 |
❌ 无效,v2rayA 仍监听所有地址 |
启动参数 --address 0.0.0.0:2017 |
❌ 无效,Go 程序仍遍历所有 IP 并监听 |
v2rayA 基于 Go 语言开发,其监听逻辑会遍历所有网络接口并绑定。日志中打印的地址列表实际反映了真实的监听状态。
8.3 终极解决方案:ip6tables 内核级封锁
既然应用层无法控制,直接在容器内的 IPv6 防火墙拦截:
ip6tables -I INPUT -p tcp --dport 2017 -j DROP
将这条命令写入容器的 entrypoint 脚本,在 v2rayA 启动之前执行:
--entrypoint sh mzz2017/v2raya \
-c "echo 1 > /proc/sys/net/ipv4/ip_nonlocal_bind; \
ip -6 route del default via fd00:8::1 2>/dev/null || true; \
ip6tables -I INPUT -p tcp --dport 2017 -j DROP; \
exec v2raya"
8.4 为什么这样做是安全的?
- 只拦截 INPUT 入站:不影响容器通过 IPv6 出站连接代理节点;
- 内核级拦截:数据包在到达 v2rayA 进程之前就被丢弃,效率极高;
- 随容器自动生效:写在 entrypoint 中,容器重启后自动恢复。
8.5 验证
# 局域网 IPv4 访问(应成功)
curl http://192.168.31.2:2017
# 公网 IPv6 访问(应超时)
# 手机关闭 WiFi,使用 5G 流量
# 浏览器访问 http://[2408:xxxx:xxxx:xxxx:...]:2017
# 预期:连接超时
9. Macvlan 宿主机通信:vlink 桥接
⚠️ 未实测:本节内容为理论方案,作者尚未在自己的环境中实际配置 vlink。
代理功能完善、安全加固完成后,日常使用中又发现了一个问题:从 NAS 本机竟然访问不了 v2rayA 的 Web 面板,NAS 上的其他容器也无法通过 v2rayA 上网。这是 macvlan 的一个”设计特性”——宿主机与自己创建的 macvlan 容器天然隔离。
9.1 问题
Macvlan 有一个设计层面的限制:宿主机与其自身创建的 macvlan 容器无法直接通信。这意味着:
- NAS 本机无法访问
192.168.31.2:2017(v2rayA 面板); - NAS 本机的应用(如青龙面板的脚本)无法通过 v2rayA 代理上网。
9.2 解决方案:创建 vlink 子接口
# 创建 macvlan 子接口
ip link add vlink link eth0 type macvlan mode bridge
# 分配一个局域网 IP(不要与其他设备冲突)
ip addr add 192.168.31.100/32 dev vlink
# 启用接口
ip link set vlink up
# 添加到 v2rayA 容器的路由
ip route add 192.168.31.2/32 dev vlink
现在宿主机可以通过 vlink 接口与 macvlan 容器通信了。
9.3 如果需要 NAS 本机也走代理
⚠️ 未实测 + 高风险:此操作未经作者实测,且风险较高,请谨慎操作。
# 将 vlink 设为默认网关(宿主机流量走 v2rayA)
ip route del default
ip route add default via 192.168.31.2 dev vlink
⚠️ 风险提示:如果 v2rayA 容器停止,宿主机将完全断网。建议仅在测试时使用,生产环境建议为 NAS 本机保留直连路由。
10. 其他容器走代理(青龙面板等)
⚠️ 未实测:本节两种方案均为理论指导,作者尚未实际将青龙等容器接入代理。
10.1 方案一:加入 macvlan 网络
将需要走代理的容器也加入同一个 macvlan 网络,并将网关指向 v2rayA:
docker run -d \
--name qinglong \
--network=macvlan_v2raya \
--ip=192.168.31.3 \
whyour/qinglong
容器内手动设置路由:
docker exec qinglong ip route replace default via 192.168.31.2
10.2 方案二:使用 HTTP 代理环境变量
如果不想改网络模式,可以在容器启动时注入代理环境变量:
docker run -d \
--name qinglong \
-e HTTP_PROXY=http://192.168.31.2:20171 \
-e HTTPS_PROXY=http://192.168.31.2:20171 \
-e ALL_PROXY=socks5://192.168.31.2:20170 \
whyour/qinglong
注意:需要在 v2rayA 设置中确认 SOCKS5(20170)和 HTTP(20171)代理端口已开启。
11. 持久化与开机自启
11.1 Docker 自动重启
容器使用 --restart=always 参数,Docker 服务启动时会自动拉起容器。macvlan 网络和容器配置均持久化存储,重启 NAS 后自动恢复。
11.2 vlink 和内核参数的持久化
⚠️ 未实测:以下启动脚本为理论方案,作者尚未在绿联云上实际配置开机自启脚本。
Docker 容器内的 entrypoint 脚本(ip6tables 规则、路由删除)会随容器启动自动执行。但宿主机上的 vlink 和内核参数需要通过启动脚本持久化:
# /etc/rc.local 或绿联云的自启动脚本
#!/bin/bash
# 如果通过绿联云系统设置删除了虚拟网桥,系统会自动切回 eth0 直连,通常无需额外配置
# 如果是命令行手动拆除 bridge0,则需要手动恢复 eth0 的 IP:
# ip addr add 192.168.31.178/24 dev eth0
# ip route add default via 192.168.31.1
# 创建 vlink(如需宿主机访问 v2rayA)
ip link add vlink link eth0 type macvlan mode bridge
ip addr add 192.168.31.100/32 dev vlink
ip link set vlink up
ip route add 192.168.31.2/32 dev vlink
# 确保宿主机 ip_forward 开启(bridge 容器依赖)
sysctl -w net.ipv4.ip_forward=1
# 注意:ip_nonlocal_bind 无需在宿主机设置,已在容器 entrypoint 中配置(容器有独立的网络命名空间)
注意:绿联云系统升级可能覆盖自定义启动脚本。建议升级前备份。
12. 完整命令参考与 docker-compose
12.1 完整 Docker 命令(终极版)
# 1. 创建双栈 macvlan 网络
docker network create -d macvlan \
--subnet=192.168.31.0/24 \
--gateway=192.168.31.1 \
--ipv6 \
--subnet=fd00:8::/64 \
--gateway=fd00:8::1 \
-o parent=eth0 \
macvlan_v2raya
# 2. 启动 v2rayA 容器(IPv6 + 安全加固)
docker run -d \
--name v2raya \
--restart=always \
--privileged \
--network=macvlan_v2raya \
--ip=192.168.31.2 \
--sysctl net.ipv4.ip_forward=1 \
--sysctl net.ipv6.conf.all.forwarding=1 \
--sysctl net.ipv6.conf.all.accept_ra=2 \
--sysctl net.ipv6.conf.default.accept_ra=2 \
--sysctl net.ipv6.conf.eth0.accept_ra=2 \
-v /volume1/docker/v2raya/etc:/etc/v2raya \
--entrypoint sh \
mzz2017/v2raya \
-c "echo 1 > /proc/sys/net/ipv4/ip_nonlocal_bind; ip -6 route del default via fd00:8::1 2>/dev/null || true; ip6tables -I INPUT -p tcp --dport 2017 -j DROP; exec v2raya"
12.2 docker-compose.yml
⚠️ 未实测:以下 docker-compose 配置由
docker run命令等价转换而来,作者实际使用的是docker run命令行方式。
version: "3.9"
services:
v2raya:
image: mzz2017/v2raya
container_name: v2raya
restart: always
privileged: true
networks:
macvlan_v2raya:
ipv4_address: 192.168.31.2
sysctls:
- net.ipv4.ip_forward=1
- net.ipv6.conf.all.forwarding=1
- net.ipv6.conf.all.accept_ra=2
- net.ipv6.conf.default.accept_ra=2
- net.ipv6.conf.eth0.accept_ra=2
volumes:
- /volume1/docker/v2raya/etc:/etc/v2raya
entrypoint: sh
command: >
-c "echo 1 > /proc/sys/net/ipv4/ip_nonlocal_bind;
ip -6 route del default via fd00:8::1 2>/dev/null || true;
ip6tables -I INPUT -p tcp --dport 2017 -j DROP;
exec v2raya"
networks:
macvlan_v2raya:
driver: macvlan
driver_opts:
parent: eth0
enable_ipv6: true
ipam:
config:
- subnet: 192.168.31.0/24
gateway: 192.168.31.1
- subnet: fd00:8::/64
gateway: fd00:8::1
13. 常见问题与排障速查
Q1:v2rayA 启动后,NAS 上其他 Docker 容器全部断网
原因:v2rayA 以 host 模式运行,启动透明代理时关闭了 ip_forward。
解决:改用 macvlan 模式部署 v2rayA。
Q2:手机设置网关后能上百度,但不能上 Google
排查步骤:
- 检查手机是否关闭了 IPv6(IPv6 流量会绕过 IPv4 透明代理);
- 检查 v2rayA 日志是否有
[transparent -> proxy]记录; - 检查代理节点是否正常连通。
Q3:手机设置网关后百度和 Google 都打不开
常见原因:
- tproxy 模式下
ip_nonlocal_bind=0,导致直连流量报invalid argument; - DNS 死锁:代理节点使用域名,DNS 请求被代理自身拦截形成环路。
解决:
- 确保
ip_nonlocal_bind=1(sysctl -w net.ipv4.ip_nonlocal_bind=1); - 将”防止 DNS 污染”设为关闭;
- 代理节点使用 IP 地址而非域名。
Q4:YouTube App 无限转圈,但浏览器正常
原因:YouTube App 使用 QUIC(UDP 443)协议,v2rayA 未嗅探 QUIC 流量。
解决:在 v2rayA 设置中开启 QUIC 嗅探。
Q5:iptables -F 能”修复”透明代理,但 NAS 其他服务挂了
原因:macvlan 绑定在 bridge0 上,bridge-nf-call-iptables=1 导致 bridge 流量被 iptables FORWARD DROP 规则拦截。iptables -F 清空了 DROP 规则所以暂时通了,但也清掉了 Docker 的其他必要规则。
解决:macvlan 绑定到 eth0 而非 bridge0(参见第 2.2 和第 3 节)。
Q6:容器获取不到公网 IPv6 地址
排查清单:
- macvlan 创建时是否加了
--ipv6参数; - 容器启动时是否设置了
accept_ra=2; - 是否删除了 ULA 默认路由(否则 SLAAC 的路由会被覆盖);
- 路由器是否开启了 IPv6 RA 广播。
# 容器内检查
ip -6 addr show eth0 # 查看地址
ip -6 route show # 查看路由表,default 应指向路由器
Q7:v2rayA 面板可以通过公网 IPv6 访问(安全隐患)
解决:在容器 entrypoint 中添加 ip6tables -I INPUT -p tcp --dport 2017 -j DROP。
Q8:DoH 开启后首屏加载变慢
原因:DoH 需要 TCP + TLS 握手,且请求还要经过代理隧道,首次解析延迟较高。后续请求受益于连接复用和 DNS 缓存,速度恢复正常。
优化方案:
- 使用 DNS 分流:国内域名走 UDP DNS(
223.5.5.5),海外域名走 DoH; - 如果手机同时开了代理软件(Fake-IP 模式),NAS 上可以关闭 DoH,因为 DNS 解析已被手机代理接管。
Q9:宿主机访问不了 v2rayA 面板
原因:macvlan 的设计限制——宿主机与自身的 macvlan 容器隔离。
解决:创建 vlink 子接口(参见第 9 节)。
Q10:NAS 重启后 IPv6 前缀变化,容器 IPv6 失效
解决:使用 ULA + SLAAC 方案(参见第 5 节)。macvlan 使用固定的 ULA 子网 fd00:8::/64,公网 IPv6 通过 SLAAC 动态获取,无需手动更新。
总结
本文完整记录了在绿联云 NAS 上从零搭建 Docker 透明代理的全过程,核心结论如下:
- 网络模式:必须使用 macvlan,避免 host 模式破坏其他容器;
- macvlan 绑定:直接绑定到
eth0,避免bridge0带来的 iptables 干扰; - IPv6 方案:ULA 激活协议栈 + SLAAC 获取公网地址 + 删除 ULA 默认路由;
- 透明代理模式:推荐 tproxy 模式,性能最优;关键前置条件为
ip_nonlocal_bind=1、DNS 直连 IP、--privileged权限; - 安全加固:ip6tables 封锁公网 IPv6 入站,防止管理面板暴露;
- DNS 策略:开启嗅探(含 QUIC),避免 DNS 死锁,按需开启 DoH/分流。
这套方案经过反复实测验证,可以稳定运行,实现全家设备仅改网关即可无感科学上网的终极目标。