>

适用场景:家庭/小型办公网络,想让内网每台设备都拥有真·公网 IPv6 地址,实现直连、端口映射零配置、NAS/服务直接暴露互联网
> 前置:运营商已下发 IPv6(光猫/路由器 WAN 口能拿到 IPv6 地址/前缀)
> 核心目标:OpenWrt/iStoreOS 作为主路由/旁路网关,PD 下发前缀 → 内网 SLAAC/DHCPv6 自动获公网 IPv6 → 防火墙放行 → 服务监听 [::] → DDNS-AAAA 域名解析 → 可选 Cloudflare/HE 隧道兜底


0. IPv6 核心概念速查(只记这几个)

概念说明关键点
全球单播地址 (GUA)真·公网 IPv6,格式 2001:db8:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx运营商下发 /56/64 前缀,内网设备自动拼接后 64 位
链路本地地址fe80::/10,仅本链路通信,不路由邻居发现协议 (NDP)、路由器通告 (RA) 依赖它
前缀委派 (PD, Prefix Delegation)上级路由器把 /56/60 前缀分给下级,下级再切 /64 给各 LAN开启 PD 是全家桶的关键
SLAAC (Stateless Address Autoconfiguration)设备收到 RA → 自己拼凑 IPv6 地址,无需 DHCPv6默认开启,隐私扩展 (RFC 4941) 会生成临时地址
DHCPv6 (有状态/无状态)有状态 = 分配地址+DNS;无状态 = 仅下发 DNS/选项OpenWrt 默认「无状态 DHCPv6 + SLAAC」
DUID / IAID设备/接口唯一标识,决定同一设备拿到的 IPv6 后缀是否固定想固定后缀 → 绑定 DUID/IAID 或改用 DHCPv6 有状态
NDP (Neighbor Discovery Protocol)替代 ARP,做地址解析、路由器发现、重复地址检测 (DAD)防火墙必须放行 icmpv6 类型 ½/¾/130-136

1. 光猫/上游路由模式确认(动手前必查)

运营商模式现象你的 OpenWrt 该怎么接
光猫桥接 + 路由器拨号光猫不拨号,OpenWrt WAN 口 PPPoE 拨号获取 IPv4 + IPv6最理想,OpenWrt 直接拿 PD 前缀
光猫路由模式 + OpenWrt 旁路网关光猫拨号、DHCPv6/PD 已开启,OpenWrt 只做 LAN 网关OpenWrt WAN 口设为 DHCPv6 客户端 请求 PD,LAN 口开启 RA/DHCPv6 转发
光猫路由模式 + OpenWrt 二级路由光猫下挂 OpenWrt WAN 口,双层 NATOpenWrt WAN 口 DHCPv6 客户端 请求 PD,需光猫支持 PD 透传/下发
仅 IPv4 / 运营商拦截 IPv6WAN 口完全拿不到 IPv6 地址/前缀走隧道兜底(第 6 节:Cloudflare WARP / HE Tunnel / Tailscale IPv6)
>

自测命令(在 OpenWrt SSH 执行):

# 1. WAN 口是否拿到 IPv6 地址/前缀
ip -6 addr show dev wan
# 应看到 2001:db8::/64 之类的 GUA,且有 `scope global`

2. 是否拿到 PD 前缀(关键)

ip -6 route show table all | grep -E ‘::/56|::/60|::/64’

或查看 odhcpd 状态

logread -e odhcpd | tail -20

---

### 2. OpenWrt / iStoreOS 核心配置(主路由模式为例)

#### 2.1 网络 → 接口 → WAN / WAN6

```text
【WAN】(IPv4 PPPoE)
协议: PPPoE
用户名/密码: 运营商给的
IPv6 设置: 勾选「请求 IPv6 前缀 (PD)」
PD 请求长度: 56  (或 60,视运营商下发)
PD 分配长度: 64  (每个 LAN 切 /64)
【WAN6】(IPv6 独立接口,可选)
协议: DHCPv6 客户端
请求 IPv6 地址: 勾选
请求 IPv6 前缀 (PD): 勾选
PD 请求长度: 56
自定义 DUID: 留空(或填固定值,防重拨前缀变)
>

关键:WAN 和 WAN6 二选一或仅保留 WAN6(iStoreOS 新版建议合并为单接口双栈)。必须勾选 PD 请求,否则内网设备拿不到公网前缀。

2.2 网络 → 接口 → LAN(及其它 LAN 接口)

协议: 静态地址
IPv6 分配长度: 64  (每个 LAN /64)
IPv6 分配提示: ::1 / ::2 / ::3 ...  (不同 LAN 填不同 hint,避免冲突)
IPv6 分配模式: 「路由通告 (RA) + 无状态 DHCPv6」  (推荐)
或「有状态 DHCPv6」  (需固定后缀时)
RA 生命周期: 1800 秒
RA 最小间隔: 200 秒
>

IPv6 分配提示 很重要:::1 给主 LAN、::2 给 Guest、::3 给 IoT,不同 LAN 前缀自动区分。

2.3 网络 → DHCP/DNS → IPv6 设置(全局)

本地 IPv6 DNS 服务器: 勾选(OpenWrt 自身做 DNS)
IPv6 动态 DNS: 如需自动注册主机名 → 勾选「启用动态 DNS (DHCPv6)」
DHCPv6 服务: 「仅无状态」或「有状态」(按需)
RA 服务: 「服务器模式」
NDP 代理: 如有旁路网关/多子网需勾选

2.4 网络 → 防火墙 → 流量规则(必须放行的 ICMPv6)

名称协议来源区域目标区域动作ICMPv6 类型
Allow-ICMPv6-InputIPv6-ICMPWANDevice接受1,2,3,4,128,129,130,131,132,133,134,135,136
Allow-ICMPv6-ForwardIPv6-ICMPWANLAN接受1,2,3,4,128,129,130,131,132,133,134,135,136
Allow-NDPIPv6-ICMPWANLAN接受133,134,135,136 (Router Solicit/Advert, Neighbor Solicit/Advert)
Allow-DHCPv6UDPWANDevice接受端口 546 (DHCPv6 客户端)
Allow-IPsec-ESPESPWANDevice接受(如跑 WireGuard/IPsec over IPv6)
>

CLI 批量加规则(/etc/firewall.user 或自定义规则):

# 必放 ICMPv6 类型:1(Dest Unreach) 2(Pkt Too Big) 3(Time Exceeded) 4(Param Problem)
# 128(Echo Request) 129(Echo Reply) 130-136(NDP)
for t in 1 2 3 4 128 129 130 131 132 133 134 135 136; do
  uci add firewall rule
  uci set firewall.@rule[-1].name="Allow_ICMPv6_${t}"
  uci set firewall.@rule[-1].src='wan'
  uci set firewall.@rule[-1].dest='lan'
  uci set firewall.@rule[-1].proto='icmp'
  uci set firewall.@rule[-1].icmp_type="$t"
  uci set firewall.@rule[-1].family='ipv6'
  uci set firewall.@rule[-1].target='ACCEPT'
done
uci commit firewall && /etc/init.d/firewall restart

3. 内网设备自动获公网 IPv6(验证)

# Linux/macOS/Windows/手机连上 LAN 后,无需任何配置
ip -6 addr show scope global
# 应看到:2001:db8:abcd:1::xxxx:xxxx:xxxx:xxxx/64  (GUA)
# 以及:fe80::xxxx:xxxx:xxxx:xxxx/64  (Link-Local)
# 临时地址(隐私扩展):2001:db8:abcd:1::yyyy:yyyy:yyyy:yyyy/64 scope global temporary dynamic

# 测试直连
ping -6 ipv6.google.com
curl -6 https://ipv6.ip.sb
>

Windows 默认开启隐私扩展,每次重连后缀变,固定后缀两法:

>
  • 网卡属性 → IPv6 → 取消「使用临时地址」
  • >
  • 改用 有状态 DHCPv6(OpenWrt 开启 DHCPv6 Server → 有状态),配合 DUID/IAID 绑定

4. 服务端监听 [::](让服务同时支持 IPv4/IPv6)

4.1 Nginx / OpenResty / 1Panel / NPM

# 监听双栈
server {
    listen 80;
    listen [::]:80;          # 关键:方括号括起 IPv6
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name nas.example.com;
    # ...
}

4.2 Docker 容器网络模式

# docker-compose.yml
services:
  jellyfin:
    network_mode: host      # 直接监听宿主机 [::]:8096
    # 或 bridge 模式 + 端口映射
    # ports:
    #   - "8096:8096"
    #   - "[::]:8096:8096"  # 显式双栈映射

4.3 SSH / Samba / 其它服务

# /etc/ssh/sshd_config
ListenAddress 0.0.0.0
ListenAddress ::

# /etc/samba/smb.conf
[global]
  bind interfaces only = yes
  interfaces = lo eth0  # IPv6 自动包含
>

验证:ss -ltnp | grep -E ':80|:443|:8096' 应显示 :::8096 或 0.0.0.0:8096 与 :::8096 并存。


5. DDNS-AAAA:把域名解析到动态公网 IPv6

5.1 方案 A:OpenWrt 自带 DDNS + Cloudflare/阿里云/腾讯云 API

# 安装
opkg update && opkg install ddns-scripts_ cloudflare.com-v4v6  # 或 aliyun.com-v4v6

/etc/config/ddns(示例 Cloudflare):

config ddns 'global'
    option date_format '%F %R'
    option log_lines '250'

config service 'ipv6_cf'
    option enabled '1'
    option interface 'wan'          # 或 wan6
    option ip_source 'network'
    option ip_network 'wan6'
    option use_syslog '2'
    option use_https '1'
    option cacert '/etc/ssl/certs/ca-certificates.crt'
    option service_name 'cloudflare.com-v4v6'
    option domain 'nas.example.com'
    option username '[email protected]'
    option password 'CF_Global_API_Key_或_Token'
    option check_interval '10'
    option force_interval '72'
    option retry_interval '60'
    option ip_version 'ipv6'
/etc/init.d/ddns enable && /etc/init.d/ddns start
logread -f -e ddns

5.2 方案 B:Docker 跑 qmcgaw/ddns-updater(多服务商、Web UI)

services:
  ddns-updater:
    image: qmcgaw/ddns-updater:latest
    container_name: ddns-updater
    restart: unless-stopped
    environment:
      - TZ=Asia/Shanghai
      - PROVIDER=cloudflare
      - DOMAINS=nas.example.com,ha.example.com
      - TOKEN=your_cf_token
      - IPV4=false
      - IPV6=true
      - SCHEDULE=@every 5m
    volumes:
      - /data/config/ddns-updater:/config

5.3 方案 C:Cloudflare Tunnel(零端口、自动证书、不需要 DDNS)

见第 6 篇「安全远程访问」第 C 方案,彻底不用管公网 IP 变不变。


6. 运营商不给/拦截 IPv6 → 隧道兜底三选一

方案适用场景优点缺点
Cloudflare WARP (wireguard-go / wgcf)仅需出站访问 IPv6 资源、或给容器加 IPv6 出口免费、无限流量、全平台、自动换端点仅出站、非固定 IPv6、不适合入站服务
Hurricane Electric (HE) Tunnel Broker需要固定 /48 前缀、入站服务、BGP 玩家免费 /48、稳定、支持 rDNS、全球 PoP需注册、ICMP 必须通、延迟取决于 PoP 距离
Tailscale + IPv6 Subnet Router已有 Tailscale 组网、想给尾网设备分发 IPv6复用尾网、自动 NAT64、零配置仅尾网内可用、非公网原生 IPv6

6.1 HE Tunnel Broker 落地(OpenWrt)

# 1. HE 官网创建 Tunnel → 记下 Server IPv4、Client IPv6、Routed /48
# 2. OpenWrt 安装 6in4 包
opkg install 6in4
# 3. 网络 → 接口 → 新建接口 HE-IPv6
# 协议: 6in4
# 对端 IPv4: HE 给的 Server IPv4
# 本地 IPv6: HE 给的 Client IPv6 (如 2001:470:xxxx:xxxx::2/64)
# 路由前缀: HE 给的 Routed /48 (如 2001:470:yyyy::/48)
# 防火墙区域: wan
# 4. 启用 → 自动在 LAN 下发 /64 子网
>

HE 隧道必须放行协议 41 (IPv6-in-IPv4):
> 防火墙 → 流量规则 → 新增 → 协议 41、来源 WAN、目标 Device → 接受


7. 常见坑 & 一句话解决

现象原因修正
内网设备只有 fe80:: 链路本地地址PD 未生效 / RA 未发送检查 WAN6 是否拿到 PD、odhcpd 日志、RA 服务 是否「服务器模式」
设备有公网 IPv6 但 Ping 不通外网防火墙拦截 ICMPv6 / 转发规则缺失必放 ICMPv6 类型 ½/¾/128/129/130-136,检查 FORWARD 链
重拨后前缀变、DDNS 还指向旧地址DUID 未固定 / 运营商强制换前缀OpenWrt WAN6 填「自定义 DUID」;DDNS 缩短检查间隔
Nginx 监听 [::]:443 报 Address already in useIPv4/IPv6 双栈冲突、或 systemd-resolved 占 53listen [::]:443 ipv6only=on; 或关闭 net.ipv6.bindv6only=1
访问 http://[2001:db8::1] 浏览器报错地址需加方括号、且证书 CN/SAN 必须含 IPv6域名解析 AAAA 记录 → 走域名访问;自签证书需把 IPv6 加入 SAN
运营商拦截 IPv6(只给 IPv4)地区/套餐限制跑隧道兜底(HE / WARP / Tailscale)
多 LAN 接口 IPv6 前缀冲突IPv6 分配提示 填相同值每个 LAN 填不同 hint:::1、::2、::3…
Docker 容器拿不到 IPv6Docker daemon 未启用 IPv6/etc/docker/daemon.json 加 "ipv6": true, "fixed-cidr-v6": "2001:db8:abcd:ffff::/64" 重启 Docker

8. 一键自检脚本(放 /usr/local/bin/check-ipv6.sh,定时跑)

#!/usr/bin/env bash
set -euo pipefail
LOG=/var/log/ipv6-check.log
exec >>"$LOG" 2>&1
echo "===== $(date -Is) IPv6 健康检查 ====="

# 1. WAN 口 IPv6
WAN6=$(ip -6 addr show dev wan scope global 2>/dev/null | head -1)
echo "WAN IPv6: ${WAN6:-无}"

# 2. PD 前缀
PD=$(ip -6 route show table all | grep -E '::/56|::/60' | head -1)
echo "PD 前缀: ${PD:-无}"

# 3. LAN 设备 IPv6
LAN6=$(ip -6 addr show dev br-lan scope global 2>/dev/null | head -1)
echo "LAN IPv6: ${LAN6:-无}"

# 4. 外网连通性
ping -6 -c 2 -W 3 ipv6.google.com >/dev/null 2>&1 && echo "IPv6 连通: ✅" || echo "IPv6 连通: ❌"

# 5. DDNS 解析是否匹配当前 WAN IPv6
CURRENT=$(ip -6 addr show dev wan scope global | awk '/inet6/{print $2}' | cut -d/ -f1 | head -1)
DNS=$(dig +short AAAA nas.example.com @1.1.1.1 | head -1)
if [[ "$CURRENT" == "$DNS" ]]; then
    echo "DDNS 同步: ✅ ($CURRENT)"
else
    echo "DDNS 同步: ❌ 当前 $CURRENT vs DNS $DNS"
fi

# 6. 防火墙关键规则
for t in 1 2 3 4 128 129 130 131 132 133 134 135 136; do
    iptables -t filter -C forwarding_wan_rule -p ipv6-icmp --icmpv6-type $t -j ACCEPT 2>/dev/null || echo "缺失 ICMPv6 type $t 转发规则"
done

echo "===== 检查结束 ====="
chmod +x /usr/local/bin/check-ipv6.sh
# 加入 crontab 每 10 分钟
echo "*/10 * * * * /usr/local/bin/check-ipv6.sh" >> /etc/crontabs/root
/etc/init.d/cron restart

9. 进阶:给容器/虚拟机分发独立公网 IPv6(MACVLAN / IPVLAN / SR-IOV)

# docker-compose.yml:macvlan 让容器直接拿 LAN 侧公网 IPv6
networks:
  macvlan_net:
    driver: macvlan
    driver_opts:
      parent: br-lan      # 或 eth0
      mode: bridge
    ipam:
      config:
        - subnet: "2001:db8:abcd:1::/64"   # 必须是 LAN 实际前缀
          gateway: "2001:db8:abcd:1::1"

services:
  jellyfin:
    image: jellyfin/jellyfin:latest
    networks:
      macvlan_net:
        ipv4_address: 192.168.10.50
        ipv6_address: 2001:db8:abcd:1::50
    # 容器内直接拥有公网 IPv6,无需端口映射
>

前提:宿主机网卡支持混杂模式、交换机允许 MAC 地址透传(家用交换机通常默认允许)。


10. 资源 & 参考


— 感谢阅读 —

一起交流

分享你的思考,让讨论更进一步。