# 在 Docker 中配置 IPV6 NAT

## 概述

由于公网 IP 的获取比较困难，本人的 NAS 上的各种 Docker 应用都是通过路由器的公网 IPV6 地址进行代理的，使用的是在 OpenWrt 上部署到一款名为 [Lucky](https://lucky666.cn/) 的应用，[Github项目地址](https://github.com/gdy666/lucky)， 这款应用聚合了端口转发、动态域名、自动证书等功能，一个应用就能解决将服务部署到公网的全部流程。

因为 Lucky 集成了 `socat` 的功能，可以进行 IPV6 到 IPV4 的端口转发，所以通常 NAS 上的应用只要能通过 IPV4 地址访问到就可以部署到公网。

但是这样会存在一个问题：

>[!info]  信息
>Docker 默认情况下不会配置 IPV6 功能，因而在 Docker 容器内无法通过域名（IPV6）去访问别的容器，只能使用本地的 IPV4 地址来访问。这样不方便，并且有的应用需要`SSL`或者设置了`BaseURL`，直接用 IPV4 地址访问可能会有问题。

不过，一直以来，本人并不知道 Docker 默认没有 IPV6 ，主要原因如下：

- 我在 OpenWrt 上安装了Clash，而 Clash 为了保证访问的私密性，配置了 FakeIP 功能。
- 我没有设置 FakeIP Filter，所以即便是本地网络之间的访问，地址也会被转成 FakeIP。
- 访问的 IPV6 地址也会被转成 FakeIP，并且 FakeIP 是保留 IP 段的 IPV4 地址。
- 路由器负责解析 FakeIP，并且 Lucky 将解析后的结果代理到了对应的 IPV4 地址。

所以，阴差阳错之下，本人一直在容器内正常使用着 IPV6 功能。

![](https://img.papergate.top:5000/i/2025/08/68a0b70cc317c.webp)

不过，也许是因为 Clash 时常可能访问不了，或者别的原因，容器内访问 IPV6 时常也会访问不了。并且用这种方式会增加通信之间的消耗，增加网络的复杂性，容易出现各种未知的问题，所以只好想办法来解决这一问题。

查看 OpenWrt 上的路由器网络，WAN6 IP 地址的掩码是 64 位的，这说明运营商只给我分配了这一个 IPV6 公网地址，我不可以通过前缀委派（Prefix Delegation,PD）给其他内网设备分配公网 IPV6 地址，所以从路由器开始，我的后续所有的设备的 IPV6 地址都只能通过网络地址转换（Network Address Translation,NAT）来分配。

![](https://img.papergate.top:5000/i/2025/08/689583678e125.webp)

本人的 Docker 容器基本全都是桥接的，于是解决这个问题有 3 个步骤：

- Nas 本身要配置 IPV6
- Docker 的虚拟网口和 NAS 之间要配置 NAT
- Docker 容器内要配置 IPV6 并且和 Docker 网口之间配置 NAT

在下文中，本人将依次讲述这些如何配置。

## 路由器网络

本人使用的是威联通的 NAS，登录 NAS 系统，来到`控制台->网络与虚拟交换机->网络适配器`，配置 IPV6 如下：

![](https://img.papergate.top:5000/i/2025/08/689583dddf657.webp)

## NAS 网络

通过 `ssh` 连接到 NAS，通过测试，威联通的 NAS 安装了`iptables`和`ip6talbes`，但是没有安装`ip6tables_nat`，所以不可以进行 IPV6 的 NAT。

Github 上有人编译了威联通的 `ip6tables_nat` 包，[项目地址](https://github.com/mammo0/qnap-ip6tables_nat-module)。去 `release` 里头下载`modules.zip`并解压得到`ip6table_nat.ko`即可。

通过 `ssh` 连接到 NAS，执行以下命令，将对应目录挂载到`/tmp/config`，具体参照[网址](https://www.qnap.com/zh-tw/how-to/faq/article/running-your-own-application-at-startup)：

```shell
sudo -i mount $(/sbin/hal_app --get_boot_pd port_id=0)6 /tmp/config
```

在目录下新建文件`autorun.sh`，填入以下内容

```shell
/sbin/modprobe ip6_tables
/sbin/modprobe nf_nat
/sbin/modprobe xt_MASQUERADE
insmod /「PATH」/ip6table_nat.ko
```

将文件修改为可执行，并解除挂载：

```shell
chmod +x /tmp/config/autorun.sh
umount /tmp/config
```

登录 NAS 系统，来到`控制台->硬件->常规`，对应选项上打勾：

![](https://img.papergate.top:5000/i/2025/08/689587f7ae60a.webp)

重启 NAS 或者手动执行`autorun.sh`中的内容。

在 Docker 中创建支持 IPV6 的网络：

```shell
docker network create \
  --ipv6 \
  --subnet=xxxx:xxxx:xxxx::/64 \
  --gateway=xxxx:xxxx:xxxx::1 \
  --subnet=xx.xx.xx.xx/24 \
  --gateway=xx.xx.xx.1 \
  --opt com.docker.network.bridge.name=ipv6 \
  ipv6
```

NAT分为 SNAT 和 DNAT 两种：

- DNAT 修改目标 IP 地址，主要用来进行端口转发，将公网IP端口映射到内网IP端口
- SNAT 修改源 IP 地址，用来解决 IP 地址不足的问题，将内网IP端口修改为公网IP端口

这里要实现的目标不是通过内网的 IPV6 地址访问内网的服务，因为 Docker 原本就有 IPV4 的端口转发，更加简单好记。

所以，只考虑配置 SNAT，使得容器内访问 IPV6 地址，修改 IP 端口，变为 NAS 访问 IPV6 地址，进而交由路由器来处理，方法如下：

```shell
sudo ip6tables -A FORWARD -i ipv6 -o eth0 -j ACCEPT
sudo ip6tables -A FORWARD -i eth0 -o ipv6 -j ACCEPT
sudo ip6tables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
```

## 容器内部

Docker 在创建容器时，一般就自动创建好了容器内的防火墙和NAT规则，规则也比较简单，通常不需要进行任何设置就可以访问 NAS。

一个比较特殊的容器是 `WireGuard`，其内部可能存在多个网口，比如`wg0、wg1、wg2`等，需要配置相关的 NAT 规则，这种方式的目的是隔离多个网口，并且每个网口分别做防火墙，提供给不同的人使用。

Docker 部署方式如下：

```dockerfile
docker run -itd --name=WireGuard --restart always \
--network ipv6 \
--cap-add=NET_ADMIN \
-e PUID=「PUID」 \
-e PGID=「PGID」 \
-e TZ=Asia/Shanghai \
-e SERVERURL=「URL」 \
-e SERVERPORT=「POST」 \
-e PEERS=3 \
-e PEERDNS=「DNS」 \
-e INTERNAL_SUBNET=xx.xx.xx.0 \
-e INTERNAL_SUBNET6=xxxx:xxxx:xxxx:: \
-e ALLOWEDIPS=0.0.0.0/0,::/0 \
-e PERSISTENTKEEPALIVE_PEERS=25 \
-e LOG_CONFS=true \
-p 51820:51820/udp \
-p 51821:51821/udp \
-p 51822:51822/udp \
-v /「PATH」/config:/config \
--sysctl="net.ipv4.conf.all.src_valid_mark=1" \
--sysctl="net.ipv6.conf.all.disable_ipv6=0" \
--sysctl="net.ipv6.conf.all.forwarding=1" \
--sysctl="net.ipv6.conf.default.forwarding=1" \
linuxserver/wireguard:latest
```

需要在容器内使用 IPV6 时，需要添加的有：

```shell
--sysctl="net.ipv6.conf.all.disable_ipv6=0" \
--sysctl="net.ipv6.conf.all.forwarding=1" \
--sysctl="net.ipv6.conf.default.forwarding=1" \
```

其他项不是必备的配置，可以创建以后手动进行修改。

服务器端的配置如下：

```text
[Interface]
Address = xx.xx.xx.1/24, xxxx:xxxx:xxxx::1/64
ListenPort = 51820
PrivateKey = xxxxx
PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -A FORWARD -o %i -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE; ip6tables -A FORWARD -i %i -j ACCEPT; ip6tables -A FORWARD -o %i -j ACCEPT; ip6tables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -D FORWARD -o %i -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE; ip6tables -D FORWARD -i %i -j ACCEPT; ip6tables -D FORWARD -o %i -j ACCEPT; ip6tables -t nat -D POSTROUTING -o eth0 -j MASQUERADE

[Peer]
PublicKey = xxxxx
PresharedKey = xxxxx
AllowedIPs = xx.xx.xx.2/32, xxxx:xxxx:xxxx::2/128
```






---

> 作者: Aphros  
> URL: https://blog.papergate.top/posts/%E5%9C%A8-docker-%E4%B8%AD%E9%85%8D%E7%BD%AE-ipv6-nat/  

