目录

  1. 问题背景
  2. 核心概念:为什么代理需要容器 IPv6
  3. 配置步骤
  4. 常见问题排查
  5. 关键原理总结

问题背景

在部署 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 支持。