FooHoro.log #20230109 – 服务器搬家记

服务器搬到 Hetzner 了,顺便踩了亿点点坑。(笑)

2022 年 12 月某天, #archlinux-cn 的 Nick Cao 在群里问有没有人要接手他搬完的 Hetzner AX41 服务器(Transfer 可以省下一笔初装费),然后咱就鬼使神差的接了。

但是 Transfer 完没几天咱就被 COVID-19 袭击了 🤧,所以开始的几天一直没有动手,直到 2022 年都快过完了才开工。 😂

装 Proxmox VE

既然 AX41 算作独立服务器,配置比咱之前那个 VPS 大了好几倍,那么很自然的就想在上面分出 N 个虚拟机上去。于是也很自然的想在上面装 Proxmox VE 了。

虽然 Hetzner 没直接提供 PVE 的映像,但是可以先从 Hetzner 的恢复系统启动,装上 Debian ,然后在 Debian 上装 PVE

然后问题来了,这台服务器上只有一个 IPv4 地址。(随着 IPv4 地址吃紧,追加 IPv4 地址的价钱也越来越贵了,对了还有初装费)于是就得像家里的路由器那样设置一下 NAT 了。

所以 /etc/network/interface 大概像这个样子:(咱好怀念 systemd-networkd 啊……)

# network interface settings; autogenerated
# Please do NOT modify this file directly, unless you know what
# you're doing.
#
# If you want to manage parts of the network configuration manually,
# please utilize the 'source' or 'source-directory' directives to do
# so.
# PVE will preserve these directives, but will NOT read its network
# configuration from sourced files, so do not attempt to move any of
# the PVE managed interfaces into external files!

source /etc/network/interfaces.d/*

auto lo
iface lo inet loopback

iface lo inet6 loopback

auto enp41s0
iface enp41s0 inet static
        # 汝自己的 IP 地址和网关可以在 Hetzner Robot 上找到。
	address 1.2.3.4/32
	gateway 1.2.3.1
	up ip -6 route add default via fe80::1 dev enp41s0

auto vmbr0
iface vmbr0 inet static
        # 划分一个 NAT 用的子网,IP 地址随便选一个内网网段就行。
	address 100.64.20.1/24
	bridge-ports none
	bridge-stp off
	bridge-fd 0
#vm-lan

iface vmbr0 inet6 static
        # 选一个在汝服务器 IPv6 网段里的 IP 地址
	address aaaa::bbbb:2/64

接下来,为了实现 NAT ,还要设置 sysctl 和 iptables 规则。

/etc/sysctl.d/ 目录新建一个配置文件 (例如 99-sysctl.conf),然后加上这些属性:

# Uncomment the next line to enable packet forwarding for IPv4
net.ipv4.ip_forward=1

# Uncomment the next line to enable packet forwarding for IPv6
#  Enabling this option disables Stateless Address Autoconfiguration
#  based on Router Advertisements for this host
net.ipv6.conf.all.forwarding=1

net.ipv6.conf.all.accept_dad = 1
net.ipv6.conf.all.accept_redirects = 1

编辑完成以后可以通过 sysctl –system 命令让修改的配置生效。

而 iptables 规则是这样的 ( /etc/iptables/rules.v4 ):

 Generated by iptables-save v1.8.7 on Wed Dec 28 09:56:00 2022
*filter
:INPUT ACCEPT [202:24737]
:FORWARD ACCEPT [577:308898]
:OUTPUT ACCEPT [158:39503]
COMMIT
# Completed on Wed Dec 28 09:56:00 2022
# Generated by iptables-save v1.8.7 on Wed Dec 28 09:56:00 2022
*raw
:PREROUTING ACCEPT [17292813:4458168798]
:OUTPUT ACCEPT [62389:14737957]
COMMIT
# Completed on Wed Dec 28 09:56:00 2022
# Generated by iptables-save v1.8.7 on Wed Dec 28 09:56:00 2022
*nat
:PREROUTING ACCEPT [135462:79719080]
:INPUT ACCEPT [6851:699941]
:OUTPUT ACCEPT [365:22212]
:POSTROUTING ACCEPT [378:22968]
# 这一条是 NAT 规则,--to-source 后面是汝主机的 IP 地址。
-A POSTROUTING -s 100.64.20.0/24 -o enp41s0 -j SNAT --to-source 1.2.3.4
# 下面两对是端口转发规则,咱这里是把 80 和 443 端口转发到某台虚拟机上了。
# 其它端口可以如法炮制。
-A PREROUTING -i enp41s0 -p tcp -m tcp --dport 80 -j DNAT --to-destination 100.64.20.177
-A POSTROUTING -d 100.64.20.177/32 -o vmbr0 -p tcp -m tcp --dport 80 -j SNAT --to-source 100.64.20.1
-A PREROUTING -i enp41s0 -p tcp -m tcp --dport 443 -j DNAT --to-destination 100.64.20.177 
-A POSTROUTING -d 100.64.20.177/32 -o vmbr0 -p tcp -m tcp --dport 443 -j SNAT --to-source 100.64.20.1
COMMIT
# Completed on Wed Dec 28 09:56:00 2022
# Generated by iptables-save v1.8.7 on Wed Dec 28 09:56:00 2022
*mangle
:PREROUTING ACCEPT [17292814:4458168855]
:INPUT ACCEPT [69630:13071644]
:FORWARD ACCEPT [17220248:4442770384]
:OUTPUT ACCEPT [62389:14737957]
:POSTROUTING ACCEPT [17282637:4457508341]
-A FORWARD -o enp41s0 -p tcp -m tcp --tcp-flags SYN,RST SYN -j TCPMSS --set-mss 1460
COMMIT
# Completed on Wed Dec 28 09:56:00 2022

然后就是创建一台虚拟机,启动 ArchISO ,分好硬盘,用 rsync 把原来服务器上的系统迁移过来。最后重新配置一下 Bootloader 和网络。

因为咱之前用的是 systemd-networkd ,所以只要修改一些设定就可以了。

[Match]
Name=ens18

[Network]
# 从汝的子网中挑一个 IPv4 和 IPv6 地址,网关是汝的主机。
Address=100.64.20.177/24
Gateway=100.64.20.1
DNS=1.1.1.1

# 为了不至于因为 MAC 地址不一样而吃到 Hetzner 的警告,
# IPv6 地址也是需要网关的。
Address=aaaa:bbbb::100/64
Gateway=aaaa:bbbb::2

以及如果是和 Debian 一样用 interfaces 的系统(像是 Ubuntu 或者 Alpine 之类的),那虚拟机的 /etc/network/interfaces 可以这么写:

auto lo
iface lo inet loopback

auto eth0
iface eth0 inet static
	address 100.64.20.48
	netmask 255.255.255.0
	gateway 100.64.20.1

iface eth0 inet6 static
	address aaaa::bbbb:48/64
	gateway aaaa::bbbb:2

但是后来还是吃了警告……

(可选)和 Hetzner 客服拉锯(误)

旧服务器的系统复制过来没几个小时, Hetzner 就发邮件来抱怨说咱的服务器在扫描网络,疑似被攻击了。但是邮件里的日志记录的目标都是像 192.168.* 或者 172.16.* 之类的私有地址,再一看出口端口,4001。哦,原来是 IPFS Daemon 不知道在干啥。去 GitHub 翻了翻,发现有人遇到过类似的问题。(例如 https://github.com/ipfs/kubo/issues/4343

上面的 issue 里有提到几种方法,像是让 Swarm.AddrFilters 忽略那些 IP 地址,或者把 IPFS 设置成服务器模式(ipfs config profile apply server)之类的。但是咱设置完一圈下来发现不太管用,于是 Hetzner 的建议是用防火墙规则屏蔽。那咱就顺便把 Proxmox 的防火墙用起来了。

于是 /etc/pve/firewall/cluster.fw 大概是这个样子:(可以参考 Proxmox 关于防火墙的文档: https://pve.proxmox.com/wiki/Firewall)

当然除了解决扫描端口的问题以外还有别的规则。

[OPTIONS]
enable: 1

[RULES]
# 接受来自内网的入站和出站连接
IN ACCEPT -source 100.64.20.0/24 -log nolog
OUT ACCEPT -dest 100.64.20.0/24 -log nolog
# 为了修扫描端口的问题拒绝特定目标的出站链接
#(PVE 默认是允许所有出站连接来着)
OUT REJECT -dest 192.168.0.0/16 -log nolog
OUT REJECT -dest 172.16.0.0/12 -log nolog
OUT REJECT -dest 10.0.0.0/8 -log nolog
# 接受特定服务的入站连接
IN SPICEproxy(ACCEPT) -log nolog
IN Web(ACCEPT) -log nolog
IN SSH(ACCEPT) -log nolog
IN Ping(ACCEPT) -log nolog # ICMP

把 Docker 容器搬到 Alpine 虚拟机里

(纯粹是偷懒不想把原来 Docker 里的服务从虚拟机里搬出来) 用 Alpine 大概是因为它足够轻?

简单来说的话:

  • 新建一个虚拟机。
  • 从 Alpine Linux 的网络安装 ISO 启动,然后安装到硬盘。(alpine-setup
  • 编辑 /etc/apk/repositories , 启用 community 仓库。
  • 安装需要的软件包。(例如 nano , qemu-guest-agent 和 docker)
  • 修改 /etc/conf.d/qemu-guest-agent ,把 GA_PATH 修改到 Proxmox 提供的路径,大概是 /dev/vport1p1 这样的。
playback:~$ cat /etc/conf.d/qemu-guest-agent 
# Specifies the transport method used to communicate to QEMU on the host side
# Default: virtio-serial
#GA_METHOD="virtio-serial"

# Specifies the device path for the communications back to QEMU on the host
# Default: /dev/virtio-ports/org.qemu.guest_agent.0
GA_PATH="/dev/vport1p1"
  • 把在 alpine-setup 建立的用户加入到 docker 用户组里,这样就能以那个用户运行 docker 命令了。
  • 用 OpenRC 设置 docker 和 qemu-guest-agent 开机启动。
rc-update add docker boot
rc-update add qemu-guest-agent boot
  • 重启虚拟机,从旧系统上把对应容器的目录复制到新虚拟机里。
  • 按照各自服务的 readme 设置和启动。
  • 修改 Nginx 配置文件,把反向代理的目标指向新的虚拟机。

反向代理 PVE 管理界面

可以少打开一个端口,以及可以申请和域名匹配的证书拜托不受信任的证书的提示。

如果汝的 Nginx 安装在 PVE 的主机上的话,可以参考 PVE 的文档 : https://pve.proxmox.com/wiki/Web_Interface_Via_Nginx_Proxy 。但是咱这次是用另一台虚拟机里的 Nginx,所以需要改变一下配置文件。

upstream proxmox {
    # 汝的虚拟机的网关地址(就是主机的内网 IP 地址啦。)
    server "100.64.20.1";
}
 
server {
    listen 80 default_server;
    rewrite ^(.*) https://$host$1 permanent;
}
 
server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    ssl_certificate /path/to/your/certificate.pem;
    ssl_certificate_key /path/to/your/key.pem;
    add_header Referrer-Policy "same-origin";
    server_name your.domain.tld;
    proxy_redirect off;
    location / {
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade"; 
        proxy_pass http://proxmox:8006;
	proxy_buffering off;
	client_max_body_size 0;
	proxy_connect_timeout  3600s;
        proxy_read_timeout  3600s;
        proxy_send_timeout  3600s;
        send_timeout  3600s;
    }
}

然后汝就可以通过 https://your.domain.tld 来访问汝的 PVE 管理面板了。

如果汝没用防火墙关闭 pveproxy 默认的 8006 端口的话,也可以修改 pveproxy 的配置文件 (/etc/default/pveproxy) 来关闭。

# 只允许来自特定 IP 地址(这里是本机和内网)的连接。
POLICY="allow"
ALLOW_FROM="127.0.0.1,100.64.20.0/24"
# 指定 pveproxy 的监听地址。
LISTEN_IP="100.64.20.1"

然后重新启动 pveproxy 服务即可。


于是新服务器就这样将就跑起来了,之前还想过把原来放在一起的其他服务也分开的,但是当下懒了,日后有时间再做吧。

2条评论

  1. 我是打算用自家舊電腦
    但是用TrueNAS Scale
    Proxmox加TrueNAS VM搞起來很麻煩(還要HBA卡
    運行點簡單東西應該夠用

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据