BuyVM VPS /48 IPv6 子网配置

背景

BuyVM / frantech 家 VPS 的一大特点就是送一个 /48 段的 IPv6 的子网。这个 /48 子网不是开箱即用的,需要一些配置才能用起来

buyvm

下文介绍在 Ubuntu 系统环境下,使用 netplan 配置 BuyVM IPv6 的方法。 最终效果是:应用程序可任意使用此 /48 子网里的 IP 来访问互联网,无需任何额外配置

注意:此方案可能只对 BuyVM 有效,不一定适用于其他家的 VPS

环境

  • 一台 Las Vegas 的 BuyVM 机子,配置无所谓,都有 /48 IPv6 子网
  • 系统是 Ubuntu 24.04

应该适用于 Ubuntu >= 18 的,使用 netplan 来管理网络环境的 Ubuntu 发行版

要重装系统的话,可以去 Stallion 面板里重装

初始状态

VPS 刚开始是未分配 IPv6 地址,也没有配置 IPv6 子网的。因此 VPS 无法访问 IPv6 地址的服务,只能访问 IPv4 的服务

可通过下面命令来验证这点:

1
2
3
4
5
6
7
8
9
10
11
12
root@localhost:~# ifconfig eth0
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 1.2.3.4 netmask 255.255.255.0 broadcast 1.2.3.255
inet6 fe80::216:bff:fe73:2998 prefixlen 64 scopeid 0x20<link>
ether 00:16:0b:73:29:98 txqueuelen 1000 (Ethernet)
RX packets 1418533 bytes 295931477 (295.9 MB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 1408074 bytes 152883531 (152.8 MB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

root@localhost:~# curl ipv6.ip.sb
curl: (7) Failed to connect to ipv6.ip.sb port 80 after 1 ms: Couldn't connect to server

如果默认网卡不是 eth0 的话,可以直接输入 ifconfig 来列出全部网卡。默认网卡可能会是 eth1, ens18

如果显示 ifconfig 命令不存在,可以 apt 装一下:sudo apt install -y net-tools

Stallion 面板操作

首先,需要去 BuyVM 的 Stallion 面板那,进行一些 VPS 的网络配置

添加主 IPv6 地址

去 Stallion 面板的 VPS 管理界面,Networking - IPv6 栏,添加一个主 IPv6 地址。

这个 IPv6 地址将会是 VPS 访问 IPv6 服务时,默认用的 IPv6 地址,并非是那个 /48 IPv6 子网

IPv6

点 “Assign IPv6 Address” 分配一个,后 4 段就写 0 0 0 1 就好,比较简单,用起来也方便

配置

然后启用,保存

保持

不妨假设这个分配的 IPv6 地址是 2605:6400:aaaa:bbbb::1,后面要用到

理论上这个时候,去 VPS 上配置下 netplan,就能用这个主 IPv6 地址来访问 IPv6 服务了。 不过不急着现在就去配,可以在搞好了 /48 IPv6 子网后一步到位

配置 IPv6 子网

在 Stallion 面板里,前往往 Networking - Routed Subnets 栏,能看到有一个 /48 的子网。这个子网就是那个 /48 IPv6 子网了

不妨设此子网为 2605:6400:cccc::/48。下面配置开始配置此子网的路由

Routed Subnets

Nexthop IP address 的下拉栏里应该能看到刚才新增的那个 2605:6400:aaaa:bbbb::1

配置

Delegated Nameserver #1、Delegated Nameserver #2 这俩都可以不填

然后点 Save、Save Changes 一路保存。这个 Subnet 状态变成 ENABLED 就代表 OK 了

保存

至此,BuyVM 的 Stallion 后台的操作已完成

VPS 配置

下面操作需 SSH 连上 VPS 来进行

netplan

先改 netplan,配置好那个主 IPv6 地址,以及 IPv6 池

1
2
# 用任意编辑器打开此文件
sudo vim /etc/netplan/01-netcfg.yaml

如果 /etc/netplan/01-netcfg.yaml 文件不存在的话,可以去 /etc/netplan 找找有没有其他的。至少 BuyVM 后台重装的 Ubuntu 24 是有这个配置的

这个配置文件的内容参考如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
network:
version: 2
ethernets:
# "eth0" 是默认网卡名字,可以 ifconfig 看。一些可能的取值:eth0、ens3
eth0:
addresses:
# 配置 eth0 网卡绑定的地址
# `1.2.3.4` 是 VPS 的 IPv4 地址。BuyVM 的 IPv4 都在 /24 的子网里,因此有 /24 后缀
# `2605:6400:aaaa:bbbb::1` 是 VPS 的 IPv6 地址。BuyVM 的 IPv6 都在 /48 的子网里,因此有 /48 后缀
# 注意这里的 IPv6 地址并非 VPS 独享的那个 /48 IPv6 子网,而是上面说的“主 IPv6”
# 参考 BuyVM 官网 wiki:
# https://wiki.buyvm.net/doku.php/kvm#ipv4
# https://wiki.buyvm.net/doku.php/kvm#ipv6
- '1.2.3.4/24'
- '2605:6400:aaaa:bbbb::1/48'
nameservers:
addresses:
# 这里用 Google 和 Cloudflare 的 IPv4 / IPv6 DNS 服务器。你想用其他的当然也行
# https://developers.google.com/speed/public-dns/docs/using
# https://developers.cloudflare.com/1.1.1.1/ip-addresses/
- 8.8.8.8
- 1.1.1.1
- 2001:4860:4860::8888
- 2606:4700:4700::1111
routes:
# 默认的 IPv4 出口。填写 IPv4 网关地址
# IPv4 网关是把 VPS 的 IPv4 地址最后一节改成 1。比如 1.2.3.4 就把最后的 4 改成 1
# 参考 BuyVM 官网 wiki:https://wiki.buyvm.net/doku.php/kvm#ipv4
- to: default
via: '1.2.3.1'

# 默认的 IPv6 出口。填写 IPv6 网关地址
# BuyVM 每个地域的 IPv6 网关都是固定的,可以去 wiki 看:https://wiki.buyvm.net/doku.php/kvm#ipv6
# 比如 Las Vegas 的 IPv6 网关地址是 2605:6400:20::1
- to: default
via: '2605:6400:20::1'

# /48 IPv6 子网配置
# 将这个 IPv6 子网分配给 eth0 网卡
- to: '2605:6400:cccc::/48'
scope: link
type: local

无注释版本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
network:
version: 2
ethernets:
eth0:
addresses:
- '1.2.3.4/24'
- '2605:6400:aaaa:bbbb::1/48'
nameservers:
addresses:
- 8.8.8.8
- 1.1.1.1
- 2001:4860:4860::8888
- 2606:4700:4700::1111
routes:
- to: default
via: '1.2.3.1'
- to: default
via: '2605:6400:20::1'
- to: '2605:6400:cccc::/48'
scope: link
type: local

配置完后,就准备应用这个配置了

(可选)先改一下 /etc/netplan/01-netcfg.yaml 的权限位,这样 netplan 不会有 warning

1
sudo chmod 600 /etc/netplan/01-netcfg.yaml

建议用 netplan try 来应用配置,这样如果配错了导致 VPS 断网,过一会也可恢复。 如果用 netplan apply(不推荐)来配置还配错了的话,可能就得去 BuyVM 后台 VNC 上去抢救了

1
sudo netplan try

如果上面命令执行完后,ssh 没卡死,就输入回车,让这个配置生效

这个时候,主 IPv6 地址就已生效了。可用下面命令检查一下

1
2
3
4
5
6
7
8
9
10
11
12
13
$ ifconfig eth0
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 209.141.54.202 netmask 255.255.255.0 broadcast 209.141.54.255
inet6 fe80::216:bff:fe73:2998 prefixlen 64 scopeid 0x20<link>
inet6 2605:6400:20:6c4::1 prefixlen 48 scopeid 0x0<global> # <--- 看这,主 IPv6 地址出现了
ether 00:16:0b:73:29:98 txqueuelen 1000 (Ethernet)
RX packets 19727111 bytes 2939632909 (2.9 GB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 1911160 bytes 225866689 (225.8 MB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

$ curl ipv6.ip.sb
2605:6400:aaaa:bbbb::1

sysctl

最后,在配置下 sysctl 的 net.ipv6.ip_nonlocal_bind=1,用于允许进程绑定到本地未配置的 IPv6 地址。 这样应用程序就可以直接用用 IPv6 池里任意的 IPv6 地址来访问互联网

1
2
3
4
5
# 临时配置,重启后失效
sudo sysctl -w net.ipv6.ip_nonlocal_bind=1

# 临时配置 + 持久化
sudo sysctl -w net.ipv6.ip_nonlocal_bind=1 | sudo tee /etc/sysctl.d/ipv6_ip_nonlocal_bind.conf

完工。可以用 curl 验证下下

1
2
3
4
5
6
7
8
$ curl ipv6.ip.sb --interface 2605:6400:cccc::1
2605:6400:cccc::1

$ curl ipv6.ip.sb --interface 2605:6400:cccc::1234
2605:6400:cccc::1234

$ curl ipv6.ip.sb --interface 2605:6400:cccc:a:b:c:d:e
2605:6400:cccc:a:b:c:d:e

完整流程的示例输出

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
root@localhost:~# sudo sysctl -w net.ipv6.ip_nonlocal_bind=1 | sudo tee /etc/sysctl.d/ipv6_ip_nonlocal_bind.conf
net.ipv6.ip_nonlocal_bind = 1
root@localhost:~# sudo chmod 600 /etc/netplan/01-netcfg.yaml
root@localhost:~# sudo vim /etc/netplan/01-netcfg.yaml
root@localhost:~# sudo netplan try
Do you want to keep these settings?


Press ENTER before the timeout to accept the new configuration


Changes will revert in 119 seconds
Configuration accepted.
root@localhost:~# curl ipv6.ip.sb
2605:6400:aaaa:bbbb::1
root@localhost:~# curl ipv6.ip.sb --interface 2605:6400:cccc::1234
2605:6400:cccc::1234

Aeza

Aeza 分配的 /48 IPv6 和其主 IPv6 是在同一个 /48 子网里的。不像 BuyVM 那样是单独分一个 Routed /48 IPv6 出来

不妨设分配了 aaaa:bbbb:cccc::/48,其中:

  • aaaa:bbbb:cccc::1 是网关
  • aaaa:bbbb:cccc::2 是主 IPv6

通用

记得配置 sysctl net.ipv6.ip_nonlocal_bind

由于不是独立的 Routed /48 IPv6,需要配一下 ndppd

1
2
3
4
yum install -y ndppd
apt install -y ndppd

systemctl enable --now ndppd

编辑 /etc/ndppd.conf

1
2
3
4
5
6
proxy ens3 {
router yes
rule aaaa:bbbb:cccc::/48 {
static
}
}

写完配置文件后重启 ndppd

1
systemctl restart ndppd`

Ubuntu

给 netplan 的配置 /etc/netplan/50-cloud-init.yaml 加一个 route。下面 yaml 为新增的部分

1
2
3
4
5
6
7
network:
version: 2
ethernets:
ens3:
routes:
- to: "aaaa:bbbb:cccc::/48"
type: local

RHEL9

临时方法(重启后失效)

1
ip -6 route add local aaaa:bbbb:cccc::/48 dev lo

永久方法 1(重启 VPS 后可能因 lo 的 uuid 变动而失效)

1
2
nmcli connection modify lo +ipv6.routes "aaaa:bbbb:cccc::/48 :: type=local"
nmcli connection up lo

永久方法 2(依赖 NetworkManager 版本 >= 1.41.6。可用 nmcli --version 检查)

参考:https://access.redhat.com/solutions/2108251

1
2
3
nmcli connection add connection.id lo connection.type loopback connection.interface-name lo connection.autoconnect yes
nmcli connection modify lo +ipv6.routes "aaaa:bbbb:cccc::/48 :: type=local"
nmcli connection up lo

执行第一条命令好像有个 warning Warning: There is another connection with the name 'lo'. Reference the connection by its uuid,似乎无伤大雅的样子

netcup + HE Tunnel Broker

netcup 自带一个 IPv6 /64 子网

目标:

  • 不影响默认 /64 子网

    • 默认 IPv6 出口仍为 netcup 的 IPv6
  • 配置好 HE Tunnel Broker 的 IPv6

    • 可绑定 HE Tunnel 分配的 Client IPv6 Address
    • 可任意绑定 HE Tunnel 的 /64 IPv6 子网
    • 可任意绑定 HE Tunnel 的 /48 IPv6 子网

    即下面这些命令均可成功

    1
    2
    3
    curl ipv6.ip.sb --interface he-ipv6
    curl ipv6.ip.sb --interface 2001:470:aaa:bbb::2
    curl ipv6.ip.sb --interface 2001:470:aaa:bbb::abcd

记得配置 sysctl net.ipv6.ip_nonlocal_bind

Ubuntu

加一个 /etc/netplan/99-he-tunnel.yaml,配置 he tunnel,就行了

这里的 routes 都加了个 metric: 200,这样不会和主路由(如 /etc/netplan/50-cloud-init.yaml 里的配置)冲突

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
network:
version: 2
tunnels:
he-ipv6:
mode: sit
remote: 5.6.7.8 # HE Tunnel 的服务器 IPv4 (Server IPv4 Address)
local: 1.2.3.4 # VPS 的 IPv4 (Client IPv4 Address)
addresses:
- "2001:470:aaa:bbb::2/64" # HE Tunnel 分配的主 IPv6 (Client IPv6 Address)
routes:
- to: default
via: "2001:470:aaa:bbb::1" # HE Tunnel 分配的 IPv6 网关 (Server IPv6 Address)
metric: 200
- to: "2001:470:ccc:ddd::/64" # HE Tunnel 分配的 /64 Pv6 子网 (Routed /64)
scope: link
type: local
metric: 200
- to: "2001:470:eee::/48" # HE Tunnel 分配的 /48 Pv6 子网 (Routed /48)
scope: link
type: local
metric: 200

RHEL

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# config tunnel
ip tunnel add he-ipv6 mode sit remote 5.6.7.8 local 1.2.3.4 ttl 255
ip link set he-ipv6 up
ip addr add 2001:470:aaa:bbb::2/64 dev he-ipv6

# config table (basic)
# TODO: /etc/iproute2/rt_tables might not exists
echo "100 he-tunnel" >> /etc/iproute2/rt_tables
ip -6 route add default via 2001:470:aaa:bbb::1 dev he-ipv6 table he-tunnel
ip -6 rule add from 2001:470:aaa:bbb::/64 lookup he-tunnel

# config table (/64 subnet)
ip -6 route add local 2001:470:ccc:ddd::/64 dev lo table local
ip -6 rule add from 2001:470:ccc:ddd::/64 lookup he-tunnel

# config table (/48 subnet)
ip -6 route add local 2001:470:eee::/48 dev lo table local
ip -6 rule add from 2001:470:eee::/48 lookup he-tunnel

# test
ip -6 route get 2001:db8::1 from 2001:470:aaa:bbb::2
ip -6 route get 2001:db8::1 from 2001:470:ccc:ddd::abcd

curl ipv6.ip.sb --interface 2001:470:aaa:bbb::2
curl ipv6.ip.sb --interface 2001:470:ccc:ddd::abcd

# fix --interface he-ipv6
# TODO