本文记录梅林固件华硕路由器配置ipv6、防火墙、DDNSv6、Cloudflare代理与Nginx配置。

原本自2017年以来使用的联通300M宽带,EPON,有公网IP、可以多拨,能稳定700M下行,于是利用端口转发内网的文件服务器使用了很长时间。但自2023年9月起,天津联通部分地区拨号不再提供公网ipv4地址,因此将路由改为获取ipv6使用。

本例中光猫桥接,路由拨号并获取到公网ipv6,服务器获取到全球单播地址。域名配置 AAAA 记录指向服务器ipv6,服务器定期向域名DNS更新ip,并且正确配置路由器ipv6防火墙使只允许指向服务器的特定端口放行。

graph LR
1(域名) --> |AAAA| 2[[路由器防火墙]] -->|放行| 3[服务器]
3 -.-> |DDNS更新| 1

ipv6构成

2408:8210:8433:160::1/642408:8210:8f03:20ed:6d4:c49d:2c42:a650/64

ipv6为128位ip地址,上面为两个典型的示例ipv6地址,/64为子网掩码表示该地址前64位是固定的。一般前64位为子网ID,表示某个具体的子网;后64位为接口ID,可以由设备MAC地址计算得到,表示用户的唯一标识。

上网设备的ipv6地址分为单播组播任播地址。由运营商得到每个设备的ipv6全球唯一单播地址,均为公网ip,以二进制001开头,即16进制2000::/3,如2408:8xxx 即为联通的网络。除此之外还有链路本地地址fe80::1/10、私网地址 fc0d::/7(类比ipv4的192.168.x.x)。

一般可以从运营商处获得/60的子网,有空余的4位可以最多再划分成最多16个子网,不过一般路由器倾向于只保留一个子网。

240e:3c1:5665:1cd/60子网可划分成:

240e:3c1:5665:1cdf/64给IoT设备、240e:3c1:5665:1cd3/64给语音、240e:3c1:5665:1cd0/64用于上网

接口ID可以由MAC自动生成(如EUI-64算法),无需DHCPv6,这也是ipv6无状态自动配置的一大特点。华硕路由中ipv6地址的获取分为statelessstateful,无状态获得的地址会自动变化,而有状态的地址可以划定地址池固定不变。为了能更好地写路由器ipv6防火墙配置,本文中采用stateful获取ipv6地址。

image-20230929031021788

路由器设置

在华硕/梅林路由器中,开启ipv6,获取模式为native,状态为stateful,这样每个设备能获取到不变的接口ID。

image-20231005040504714

IPV6防火墙

参考:路由器梅林固件如何设置IPV6端口转发_路由器_什么值得买 (smzdm.com)

服务器有后缀不变的公网ipv6后,还需配置路由器的ipv6防火墙使得服务器对应端口能被正确访问。在ipv6防火墙规则处添加你想放行的端口,内网ip和子网掩码实测这样写能够正常配置,注意前面ip的0不可省略。

0:0:0:0:0:0:0:1234/::FFFF:FFFF:FFFF:FFFF

(上面参考文章中的方法实测iptables会录入不全,可以ssh进路由器,使用 ip6tables --list 查看记录)

image-20231005040556607

外网访问 DDNSv6

你内网的服务器现在有了公网ipv6,如何能访问到它呢?因为这是一个纯ipv6站,所以需要你的访问设备也支持ipv6,没有ipv6地址的设备是无法访问纯ipv6站点的。

可以使用 https://ipw.cn/https://ipv6ready.me/ 来检测自己设备对ipv6的支持状况。

image-20231107050016747

image-20231107050116516

若显示OK则您的设备可以正常访问ipv6网站!倘若您的设备没有通过测试(像是使用纯ipv4的代理服务器访问时)也是有办法能公网访问ipv6服务器的。

这里我们采用DNSPOD做域名解析,在服务器上使用ddns-go程序负责DDNSv6。

先在DNSPOD上配置一条指向服务器的AAAA记录

AAAA ddnsv6.example.com 2408:8210:8333:4cda::1234

之后在服务器上配置DDNS项目,本次使用ddns-go项目: https://github.com/jeessy2/ddns-go

ddns-go也可以很方便的使用docker部署:

sudo docker run -d --name ddns-go --restart=always --net=host -v /opt/ddns-go:/root jeessy/ddns-go

启动成功后通过 http://[server ip]:9876 访问web界面

image-20231107050800485

这里填入DNSPOD的domain id和API Token,勾选启用IPV6并填如你需要DDNS到的子域名。

ddns-go也可以使用webhook启用通知功能,下面以方糖Server酱为例,可传入的参数可参考ddns-go说明文档

https://sctapi.ftqq.com/YOUR_KEY.send?title=你的公网IP变了&desp=主人IPv6变了#{ipv6Addr},域名更新结果:#{ipv6Result},涉及变更的子域名为#{ipv6Domains}

这样每当ip地址变化时,你可以通过微信公众号等方式得到通知。

Nginx 反代

在ipv4配合端口转发使用时,我们采取单一子域名,使用不同映射端口配合Nginx反向代理来实现外网访问服务器的不同功能。而在使用ipv6+防火墙放行时,可以采用固定传输端口,不同子域名对应不同业务的方式访问服务器。

对于某些地区ipv6开放80、443端口,使用后者方法会更加方便,而天津联通矢志不渝地封禁80、8080和443端口,这一方法似乎也不很优雅。不过事实上固定传输端口有另外的好处

前面说过纯ipv4设备无法直接访问纯ipv6站点,这一困境可以通过Cloudflare CDN来实现,即通过Cloudflare的代理实现6to4,让你的源站拥有ipv4,而Cloudflare仅能代理固定的几个端口

我们给不同服务安排了不同的子域名,并在DNSPOD上申请了免费证书(期限一年不用白不用),在nginx中配置反向代理,把https端口挪到8443,在路由器防火墙只放行https端口,不放行http端口。

子域名与反向代理可以灵活搭配,例如访问 https://ddns.example.com:8443/ 为提示页面
访问 https://ddns.example.com:8443/ddns-go为ddns-go管理页面
访问https://ha.example.com:8443/为homeassistant管理页面

下面是一个含有反向代理地示例:

# ddns.example.com
server
{
    listen [::]:880;
    listen [::]:8443 ssl http2;
    server_name ddns.example.com; #填写你需要的泛域名
    charset utf-8;
    ssl_certificate     /root/cert/ddns.example.com_nginx/ddns.example.com_bundle.pem;
    ssl_certificate_key /root/cert/ddns.example.com_nginx/ddns.example.com.key;

    ssl_protocols TLSv1.1 TLSv1.2 TLSv1.3;
    ssl_ciphers EECDH+CHACHA20:EECDH+CHACHA20-draft:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:!MD5;
    ssl_prefer_server_ciphers on;
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 10m;
    add_header Strict-Transport-Security "max-age=31536000";

###### MCS Daemon deepin Reverse Proxy ######
  location /mcs-daemon {
    #proxy_redirect off;
    proxy_pass http://127.0.0.1:24444/;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    #proxy_set_header Host $Host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Sec-WebSocket-Protocol wss;
        }
}

阻止纯ip访问:

在Nginx 1.19.4或更高版本中可以直接使用ssl_reject_handshake on阻止握手,防止通过IP访问握手获得网站证书,进而同时获得网站域名与IP地址,参见 Cloudflare证书与Nginx安全

不过本deepin服务器使用debian10的古老源,只能设置返回错误页面来阻止纯ip访问。

# default ip access
server {
    listen [::]:880 default_server;
    listen [::]:8443 ssl http2 default_server;
    server_name _;
    #SSL-START SSL相关配置,请勿删除或修改下一行带注释的404规则
    # 阻止握手
    # ssl_reject_handshake on;
    return 444;
}

Cloudflare 6to4

为了使无ipv6设备也能访问你的纯ipv6服务器,我们可以借助Cloudflare提供的免费的CDN代理,缺点是你需要另外一个域名,而且流量会在国外绕一圈,延迟更高。

在Cloudflare的DNS中新建一条CNAME记录,记得要开启小云朵Proxy

CNAME ddnscf.cloudflare.com ddns.example.com

之后我们就可以通过访问https://ddnscf.cloudflare.com:8443到达源服务器了。注意Cloudflare支持代理的端口有限,一定要将https端口设置成Cloudflare支持的端口:

Network ports · Cloudflare Fundamentals docs

Cloudflare可代理端口

你可以直接使用Cloudflare解析做DDNS,也可以使用443转8443来绕过端口限制等等。