目录
问题背景
在部署 v2raya 代理服务时遇到一个典型问题:
- 容器部署的网站可以通过 http://[宿主机IPv6]:端口 访问
- 但代理模式无法访问 IPv6-only 网站
- 根本原因是:代理容器本身需要具备 IPv6 能力
核心概念:为什么代理需要容器 IPv6
两种访问模式的本质区别
| 模式 | 数据流 | 谁需要 IPv6 |
|---|---|---|
| 直接访问容器服务 | 浏览器 → 宿主机(NAT) → 容器 | 宿主机 |
| 代理访问外部网站 | 浏览器 → 代理容器 → 目标网站 | 代理容器 |
关键区别详解
直接访问(端口映射模式):
浏览器(IPv6) ──→ 宿主机:8080 ──→ Docker NAT ──→ 容器:80(IPv4)
↑ ↓
浏览器以为在和IPv6服务通信 容器只看到172.17.0.1(宿主机IPv4)
真相:宿主机做翻译,容器完全不知情
代理模式:
浏览器 ──→ v2raya:2017 ──→ v2raya自己连接 ──→ ipv6.google.com
↑
容器必须自己能发起IPv6连接
否则无法连接IPv6-only目标
一句话总结
端口映射是"宿主机的门面",代理是"容器亲自出马"
配置步骤
第一步:检查宿主机 IPv6 环境
# 查看宿主机 IPv6 地址
ip -6 addr show scope global
# 输出示例:240e:39b:2be4:2160:2e0:4cff:fe68:b270/64
# 检查 IPv6 转发
sysctl net.ipv6.conf.all.forwarding
# 必须为 1,否则执行:sysctl -w net.ipv6.conf.all.forwarding=1
# 查看路由
ip -6 route show | head -5
第二步:配置 Docker 守护进程
编辑 /etc/docker/daemon.json:
{
"ipv6": true,
"fixed-cidr-v6": "fd00:39b:2be4:2160::/64",
"experimental": true,
"ip6tables": true
}
子网选择原则:
- 不要使用宿主机的公网 /64(避免冲突)
- 使用 ULA 地址 fd00::/8 范围
- 建议保留原网段特征便于识别,如 fd00:39b:2be4:2160::/64
重启 Docker:
systemctl restart docker
第三步:配置 NDP 代理或 NAT66
由于运营商通常只分配一个 /64,需要额外配置让容器访问外网。
方案 A:NDP 代理(推荐)
# 安装 ndppd
apt-get install ndppd
# 配置 /etc/ndppd.conf
proxy enp3s0-ovs {
rule fd00:39b:2be4:2160::/64 {
static
}
}
systemctl enable ndppd
systemctl start ndppd
方案 B:NAT66(更简单)
ip6tables -t nat -A POSTROUTING -s fd00:39b:2be4:2160::/64 ! -o enp3s0-ovs -j MASQUERADE
第四步:Docker Compose 配置
最简单的 docker-compose.yml:
version: '3'
services:
v2raya:
image: mzz2017/v2raya
container_name: v2raya
privileged: true
ports:
- "2017:2017"
- "20170-20172:20170-20172"
restart: always
# 关键:启用 IPv6,子网自动分配
networks:
default:
enable_ipv6: true
关键操作:
# 必须重新创建网络,现有容器不会自动获得 IPv6
docker-compose down
docker network rm v2raya_default 2>/dev/null || true
docker-compose up -d
第五步:验证
# 检查网络 EnableIPv6
docker network inspect v2raya_default | grep EnableIPv6
# 应显示:true
# 检查容器 IPv6 地址
docker exec v2raya ip -6 addr
# 应显示:inet6 fd00:39b:2be4:2160::x/64 scope global
# 测试外网连通性
docker exec v2raya ping6 -c 3 2001:4860:4860::8888
# 检查 v2raya 监听 :::2017
docker exec v2raya netstat -tuln | grep :::2017
常见问题排查
问题 1:Docker 网络有 IPv6 配置,但容器没有地址
原因: 容器在启用 IPv6 前已创建
解决: 重新创建容器
docker-compose down
docker network rm <网络名>
docker-compose up -d
问题 2:容器有 IPv6 地址,但无法访问外网
原因: 缺少 NDP 代理或 NAT66
解决:
# 检查 NDP 代理状态
systemctl status ndppd
# 或添加 NAT66
ip6tables -t nat -A POSTROUTING -s fd00:39b:2be4:2160::/64 ! -o enp3s0-ovs -j MASQUERADE
问题 3:IPv6 转发未开启
# 临时开启
sysctl -w net.ipv6.conf.all.forwarding=1
# 永久生效
echo "net.ipv6.conf.all.forwarding=1" >> /etc/sysctl.conf
问题 4:1Panel 等面板配置被覆盖
现象: 手动修改 daemon.json 后配置丢失
解决: 在面板界面中配置 IPv6,或确保面板不管理 Docker 网络
关键原理总结
网络架构对比
┌─────────────────────────────────────────────────────────┐
│ 宿主机 (HP-FNOS) │
│ ┌─────────────┐ ┌─────────────────────────┐ │
│ │ 浏览器 │────────→│ v2raya 容器 │ │
│ │ (双栈IPv4/6)│ IPv4 │ ┌─────────────────┐ │ │
│ └─────────────┘ │ │ 监听 :::2017 │ │ │
│ ↓ │ │ 访问外部网站 │ │ │
│ 直接访问容器 │ │ - IPv4: 直接访问 │ │ │
│ http://[IPv6]:8080 │ │ - IPv6: 必须容器 │ │ │
│ ↓ │ │ 自己有IPv6 │ │ │
│ 宿主机NAT翻译 │ └─────────────────┘ │ │
│ (容器不知情) └─────────────────────────┘ │
│ │
│ 关键区别: │
│ • 端口映射 = 宿主机当翻译,容器被动接收 │
│ • 代理模式 = 容器主动发起连接,必须自己支持IPv6 │
└─────────────────────────────────────────────────────────┘
配置 checklist
| 检查项 | 命令 | 预期结果 |
|---|---|---|
| 宿主机 IPv6 地址 | ip -6 addr show scope global | 有公网 IPv6 |
| IPv6 转发 | sysctl net.ipv6.conf.all.forwarding | = 1 |
| Docker IPv6 启用 | docker network inspect bridge | grep EnableIPv6 |
| 容器 IPv6 地址 | docker exec <容器> ip -6 addr | 有 fd00::/64 |
| NDP/NAT66 | systemctl status ndppd 或 ip6tables -t nat -L | 运行中 |
| 外网连通性 | docker exec <容器> ping6 2001:4860:4860::8888 | 通 |
参考配置速查
daemon.json:
{
"ipv6": true,
"fixed-cidr-v6": "fd00:39b:2be4:2160::/64",
"experimental": true,
"ip6tables": true
}
docker-compose.yml(最小配置):
version: '3'
services:
v2raya:
image: mzz2017/v2raya
privileged: true
ports:
- "2017:2017"
restart: always
networks:
default:
enable_ipv6: true
ndppd.conf:
proxy enp3s0-ovs {
rule fd00:39b:2be4:2160::/64 {
static
}
}
结语
Docker IPv6 配置的核心在于理解网络命名空间的隔离特性:
- 每个容器有自己的网络栈
- 端口映射是宿主机内核的 NAT 行为
- 代理应用必须在容器内发起新连接
掌握这一原理,就能理解为什么"直接访问通,代理不通"的现象,并正确配置 IPv6 支持。