目前找到了两个解决方案
socat 端口转发
很早就和QNAP官方反馈请求支持IPV6,但一直没反应
socat 端口转发
环境
系统:QTS 4.3.6
网络:IPV4 & IPV6
Docker: 由Container Station提供
问题
通过ipv6地址可以打开NAS的管理页面,但是无法访问Docker对应端口的服务。
排查
QTS中Docker使用的虚拟交换机网络没有启动IPV6,且无法在虚拟交换机设置中手动启动。
这样一来,Docker只监听了tcp4的端口,对于主机上tcp6的端口的访问无法映射到docker容器上。
解决方案
在主机上开一个tcp6的端口,将其转发到主机上与docker关联的tcp4端口。
即:
docker(tcp4)–>host(tcp4)–>host(tcp6)
在qts上安装包管理器:Entware. https://github.com/Entware/Entware/wiki/Install-on-QNAP-NAS
执行
opkg update
,更新安装端口转发工具,这里使用socat:
opkg install socat
设置转发host(tcp6)–>host(tcp4)
socat TCP6-LISTEN:6880,reuseaddr,fork TCP4:127.0.0.1:7880 &
大功告成
docker-ipv6nat
- IPv4 & IPv6 可以平等使用(端口可以在主机系统上共享)
- 容器并不完全在线,因为 Docker 容器并不总是以安全着称
步骤1:
为 ip6tables NAT 安装内核模块。不幸的是,QNAP 没有自带这些模块,所以你必须自己构建它们。
谢天谢地,有人已经这样做并在 github 上发布了它。qnap-ip6tables_nat-module。在 Release 下,您已经可以在此处下载当前构建的模块。我将它们放在 Docker 容器的应用程序目录中:
/share/CACHEDEV1_DATA/Container/container-station-data/application/ipv6nat/kernel_mods/
然后,您必须确保在启动时加载这些模块。为此,必须在您的 autorun.sh 中输入以下行。
# ipv6-tables
/sbin/modprobe ip6_tables
/sbin/modprobe nf_nat
/sbin/modprobe xt_MASQUERADE
insmod /share/CACHEDEV1_DATA/Container/container-station-data/application/ipv6nat/kernel_mods/ip6t_NPT.ko
insmod /share/CACHEDEV1_DATA/Container/container-station-data/application/ipv6nat/kernel_mods/nf_reject_ipv6.ko
insmod /share/CACHEDEV1_DATA/Container/container-station-data/application/ipv6nat/kernel_mods/ip6t_REJECT.ko
insmod /share/CACHEDEV1_DATA/Container/container-station-data/application/ipv6nat/kernel_mods/ip6table_nat.ko
您可以在 QNAP Wiki 中了解如何在您的 QNAP 模型上编辑此文件:Running_Your_Own_Application_at_Startup
添加模块后,您需要重新启动 NAS。
第2步:
为了设置 docker-ipv6nat 容器,我准备了一个 docker-compose 文件。您可以通过 Create 简单地将其插入 ContainerStation:
version: '3'
services:
ipv6nat:
container_name: ipv6nat
restart: always
image: robbertkl/ipv6nat
privileged: true
network_mode: host
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- /lib/modules:/lib/modules:ro
容器应该在终端上没有任何输出的情况下启动。不起眼……现在呢?创建也应该可以通过 IPv& 访问的容器时是否需要一些手动工作。至少我还没有通过 QNAP 界面找到更简单的方法。
如果需要,您必须为每个容器创建至少一个支持 IPv6 的网络。
为此,请通过 SSH 登录 QNAP 并创建一个新的 Docker 网络:
docker network create --ipv6 --subnet fd00:dead:beef::/48 ipv6net-1
当然,您也可以使用任何其他 ULA 范围 (fc00::/7)。
现在只需使用 ipv6net-1 作为容器的外部网络。这是一个小例子:
version: "3"
services:
alp1:
image: yeasy/simple-web:latest
ports:
- 80:80
networks:
- ipv6net-1
networks:
ipv6net-1:
external: true
现在您的容器端口来自 IPv4:
nmap <ipv4 ip> -p 80
PORT STATE SERVICE
80/tcp open http
也可以通过 IPv6 访问:
nmap <ipv6 ip> -6 -p 80
PORT STATE SERVICE
80/tcp open http
享受通过 IPv4 和 IPv6 托管您的服务的乐趣!
实操
遇到问题: robbertkl/ipv6nat 启动日志报错
开启防火墙使用到了geoip会遇到如下错误
iptables exit status 1: Can't find library for match `geoip'
可能的解决方案
- 编译支持 geoip
不使用 geoip
把防火墙中的规则设计到geoip 的都修改为任何地区,防火墙规则设计的好,针对一个地区开发某些端口和针对所有地区开发端口基本一样的风险。
使用第二种方案,实际测试使用发现丢包率还不低!
# 在开启了ipv6的docker中运行如下命令
# ping6 2409:804c:2000:2::1
PING 2409:804c:2000:2::1 (2409:804c:2000:2::1): 56 data bytes
ping: getnameinfo: Temporary failure in name resolution
64 bytes from unknown: icmp_seq=1 ttl=57 time=4.073 ms
...
^Cping: getnameinfo: Temporary failure in name resolution
64 bytes from unknown: icmp_seq=24 ttl=57 time=3.654 ms
--- 2409:804c:2000:2::1 ping statistics ---
25 packets transmitted, 22 packets received, 12% packet loss
round-trip min/avg/max/stddev = 3.606/4.100/5.562/0.608 ms
Temporary failure in name resolution 似乎是DNS配置问题
测试IPV6
Windows
以下Windows版本的ping
命令支持ping IPv6地址:
- Windows XP with SP1 及以上
- Windows Vista 及以上
- Windows Server 2003 及以上
ping ipv6主机名
ping -6 ipv6.google.com
ping -6 ipv6.test-ipv6.com
ping -6 ipv6.baidu.com
**/!\注意:**当ping ipv6主机名时,必须加上参数-6
;直接ping IPv6地址时可以省略。
ping ipv6地址
ping IPv6Address[%ZoneID]
例如:
ping 2001:4860:0:2001::68
如果要ping link-local地址,则需要指定网络接口索引,如:
ping fe80::260:97ff:fe02:6ea5%4
其中**%4**表示“用索引为4的网络接口”ping目标计算机。
Linux
在Linux发行版中,使用ping6
命令ping IPv6主机或者地址。
ping ipv6主机名
ping6 ipv6.google.com
ping ipv6地址
ping6 IPv6Address[%InterfaceName]
如果要ping link-local地址,则需要指定网络接口名称,如:
ping fe80::260:97ff:fe02:6ea5%eth0
其中**%eth0**表示“用网络接口eth0 ping目标计算机”。
ping dns
ping6 2409:804c:2000:2::1
ssh
ssh root@fe80::c09a:4363:5763:32%enpxxx(网卡名称)
chrome IPV6
Chrome 地址栏输入
about:net-internals/#dns
nginx支持ipv6
nginx 1.14 开始就默认支持ipv6了,不再需要添加编译参数 --with-ipv6,可以直接配置监听 ipv6
检查nginx是否监听了ipv6
netstat -tuln
同时监听IPV4和IPV6
server {
....
listen [::]:80;
listen [::]:443;
...
}
只监听IPV6
server {
....
listen [::]:80 default ipv6only=on;
listen [::]:443 default ipv6only=on;
...
}
监听指定IPV6地址
{
....
listen [3608:f0f0:3002:31::1]:80;
listen [3608:f0f0:3002:31::1]:443;
...
}
重启nginx
nginx -s reload
安全设置
暴露Nas到公网是会有很大安全隐患的,请注意你已经做好了安全防范!
- 开启动态安全码
- 开启防火墙,最好最高安全级别,自己控制端口开启
- 开启IP访问保护 失败登录尝试阻止时间调整
- 暴露出去的服务全部采用高强密码,最好所有服务全部采用高强度密码
- 尽量使用Docker,而不是套件版软件服务
- 重要数据定期离线备份
IPv6: 为什么Link-local地址后面要有百分号(%)?
由于所有的link-local地址都有相同的前缀FE80::/64,并且每个网络接口都必须分配一个link-local地址,因而导致当发送数据包到一个link-local地址时,如果路由器使用普通的路由方法就无法决定选用哪个网络接口。因此,引入了一种被叫做zone index的标识符,它提供额外的路由信息,这个标识符通常指网络接口,并且通过一个百分号(%)被附加在IPv6地址后面。但是准确的表示方法还取决于操作系统:
Windows: 使用网络接口索引表示
如:
fe80::3%1
fe80::260:97ff:fe02:6ea5%4
要查看网络接口索引,请执行该命令:
netsh interface ipv6 show address
Linux: 使用网络接口名称表示
如:
fe80::3%eth0
fe80::260:97ff:fe02:6ea5%tun0
Linux只需要ifconnfig
命令就可列出所有网络接口名称。
参考
系列教程
Docker系列
- Docker使用简明教程
- 使用jeckett,sonarr,iyuu,qt,emby打造全自动追剧流程
- 为知笔记私有化Docker部署
- Earthly 一个更加强大的镜像构建工具
- 使用 Shell 脚本实现一个简单 Docker
- 如何使用Traefik V2 在Ubuntu20.04 上面来做 Dockers
- 通过IPV6访问Qnap NAS中Docker的服务
附赠
alpine linux 使用国内镜像源进行加速
Alpine 的源文件为:
/etc/apk/repositories
这里面的默认配置例如:
http://dl-cdn.alpinelinux.org/alpine/v3.11/main
http://dl-cdn.alpinelinux.org/alpine/v3.11/community
可以使用以下命令来进行源的切换(阿里云源):
sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories
中国科技大学的源:
sed -i 's/dl-cdn.alpinelinux.org/mirrors.ustc.edu.cn/g' /etc/apk/repositories
清华源:
sed -i 's/dl-cdn.alpinelinux.org/mirrors.tuna.tsinghua.edu.cn/g' /etc/apk/repositories
目前 Docker 官方已开始推荐使用 Alpine 替代之前的 Ubuntu 做为基础镜像环境。
Alpine 使用 apk 来进行包管理。
可以在 Docker file 中添加以下语句,来加速 apk 的包管理。
...
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.tuna.tsinghua.edu.cn/g' /etc/apk/repositories
RUN apk add --no-cache gcc musl-dev linux-headers
...
注: sed 可依照脚本的指令来处理、编辑文本文件。 Sed 主要用来自动编辑一个或多个文件、简化对文件的反复操作、编写转换程序等。