PVE 编译、部署 OpenWrt

由于需要为旁路由安装一些特定插件,我决定自行编译。如果只需要一些官方仓库提供的插件,可以使用Openwrt Image Builder
本文记录了完整的编译过程和部署过程,包括配置编译,设置 vlan 等。

编译 OpenWrt

准备了一台用于编译的主机,我配置了一台 Ubuntu 23.10,内存为 8GB,硬盘容量为 120GB 的虚拟机。
在进行编译之前,需要切换到非 root 用户,因为编译 OpenWrt 需要使用非 root 权限,还要确定虚拟机是否可以访问外网。

替换为国内源

sudo sed -i_$RANDOM.bak 's@//.*archive.ubuntu.com@//mirrors.ustc.edu.cn@g' /etc/apt/sources.list
sudo sed -i_$RANDOM.bak 's/security.ubuntu.com/mirrors.ustc.edu.cn/g' /etc/apt/sources.list
sudo sed -i_$RANDOM.bak 's/http:/https:/g' /etc/apt/sources.list
sudo apt update && apt upgrade

安装编译所需组件

sudo apt install build-essential clang flex bison g++ gawk \
gcc-multilib g++-multilib gettext git libncurses-dev libssl-dev \
python3-distutils rsync unzip zlib1g-dev file wget

准备 OpenWrt 仓库

拉取 Openwrt 仓库。

git clone https://git.openwrt.org/openwrt/openwrt.git
cd openwrt

切换仓库到最新 release tag。

git tag | grep v23
git checkout v23.05.2

更新 OpenWrt 软件包仓库。

./scripts/feeds update -a

配置固件

生成默认固件编译配置 .config。

make defconfig

安装自己所需软件包。

# luci中文界面
./scripts/feeds install luci luci-i18n-base-zh-cn
# 常用软件
./scripts/feeds install luci-i18n-opkg-zh-cn \
luci-i18n-firewall-zh-cn \
luci-i18n-sqm-zh-cn \
luci-i18n-statistics-zh-cn \
luci-i18n-wol-zh-cn \
luci-i18n-advanced-reboot-zh-cn \
luci-i18n-commands-zh-cn \
luci-i18n-ttyd-zh-cn \
luci-i18n-dashboard-zh-cn
# keepalived
./scripts/feeds install keepalived
# qemu guest agent
./scripts/feeds install qemu-ga

打开图形化配置。

make menuconfig

设置目标系统架构

Target System,Subtarget,Target Profile 选 x86_64。

调整固件分区大小

-> Target Image
  -> Kernel partition size 调整 root 分区大小为 512m。
  -> Root filesystem partition size 调整 root 分区大小为 2048m。

内置软件包

上面安装的软件还需要在编译配置中设置。[*] 表示内置进固件,按 Y 设置,按 / 搜索软件包所在位置,注意不要选错了,选中会把依赖的包都选上,取消的时候不会帮取消 ( 。

App

大部分 app 都在下面这个位置。
-> LuCI
  -> Application

Luci 中文界面

-> LuCI
  -> Collections
    -> luci luci 界面。
  -> Modules
    -> luci-compat luci 兼容库。
    -> Translations
        -> zh luci 中文。

IPV6(可选,nftables)

-> Base system
  -> dnsmasq 取消。
  -> dnsmasq-dhcpv6 取消。
  -> dnsmasq-full 选择。
-> Network
  -> odhcp6c
  -> odhcpd
  -> Firewall
    –> ip6tables-nft
-> LuCI
  -> Protocols
    -> luci-proto-ipv6

keepalived

-> Network
  -> keepalived

qemu-ga

-> Utilities
  -> Virtualzation
    -> qemu-ga

备份编译配置(可选)

保存配置更改。

./scripts/diffconfig.sh > diffconfig

设置固件自定义选项

mkdir -p files/etc/uci-defaults
cat > files/etc/uci-defaults/98_custom <<EOF
uci -q batch << EOI
set luci.main.lang='zh_cn'
# 设置时区
set system.@system[0].timezone='UTC-8'
set system.@system[0].zonename='Asia/Shanghai'
set system.ntp=timeserver
uci add_list system.ntp.server='ntp.aliyun.com'
uci add_list system.ntp.server='ntp1.aliyun.com'
uci add_list system.ntp.server='ntp2.aliyun.com'
uci add_list system.ntp.server='ntp3.aliyun.com'
# 设置后台地址
set network.lan.ipaddr='192.168.88.1'
EOI
EOF

编译

Screen 会话(可选)

使用 screen 会话来编译,中途按 Ctrl + a + d 分离会话,让编译在后台继续运行。
screen 新建一个会话。

sudo apt install screen
screen -S build-openwrt

分离后恢复会话。

screen -r build-openwrt

开始编译

预下载依赖。

make -j $(($(nproc)+1)) download

编译。

make -j $(($(nproc)+1)) || make -j1 V=s

编译成功后固件在 bin/targets/x86/64/ 目录,先备份下 bin 目录。

cp -r bin $(date +'%Y_%m_%d_%H_%M_%S')_bin

编译旁路由 OpenWrt

清空上次编译产物。

make clean

切换配置环境

OpenWrt env 基于 git,所以需要配置一下 git 信息。

git config --global user.name "Your Name"
git config --global user.email "user@email.com"

新建一个配置环境。

./scripts/env new main
./scripts/env new bypass

沿用原来的配置。

Do you want to start your configuration repository with the current configuration? (Y/n): Y

后续可以通过 ./scripts/env switch main 切换回原来的配置。

准备第三方软件仓库

拉取 vlmcsd

cd package
git clone https://github.com/cokebar/openwrt-vlmcsd.git
git clone https://github.com/cokebar/luci-app-vlmcsd.git
cd ..

拉取 OpenClash

最新步骤可以参考项目主页

# Clone 项目
mkdir package/luci-app-openclash
cd package/luci-app-openclash
git init
git remote add -f origin https://github.com/vernesong/OpenClash.git
git config core.sparsecheckout true
echo "luci-app-openclash" >> .git/info/sparse-checkout
git pull --depth 1 origin master
git branch --set-upstream-to=origin/master master

# 编译 po2lmo (如果有po2lmo可跳过)
pushd luci-app-openclash/tools/po2lmo
make && sudo make install
popd
cd ../..

配置固件

安装 OpenClash 依赖包。

./scripts/feeds install coreutils-nohup bash dnsmasq-full curl ca-certificates ipset ip-full libcap libcap-bin ruby ruby-yaml kmod-tun kmod-inet-diag unzip kmod-nft-tproxy luci-compat luci luci-base

安装主题。

./scripts/feeds install luci-theme-material

打开图形配置。

make menuconfig

内置软件包

主题

-> LuCI
  -> Themes
    -> luci-theme-material

vlmcsd

-> LuCI
  -> Application
    -> luci-app-vlmcsd

OpenClash (nftables)

-> LuCI
  -> Application
    -> luci-app-openclash
-> Base system
  -> dnsmasq 取消
  -> dnsmasq-full 选择
-> LuCI
  -> Modules
    -> luci-compat
-> Kernel modules
  -> Network Support
    -> kmod-inet-diag
  -> Netfilter Extensions
    -> kmod-nft-tproxy

设置旁路由的自定义选项

cat > files/etc/uci-defaults/99_bypass <<EOF
uci -q batch << EOI
# 设置主题
set luci.main.mediaurlbase='/luci-static/material'
# 设置后台地址
set network.lan.ipaddr='192.168.88.2'
EOI
EOF

编译

make -j $(($(nproc)+1)) || make -j1 V=s

成功后备份下固件。

cp -r bin $(date +'%Y_%m_%d_%H_%M_%S')_bypass_bin

PVE 部署 Openwrt

首先上传编译 Openwrt 生成的 ext4、efi 固件到 PVE,一般是 openwrt-x86-64-generic-ext4-combined-efi.img.gz

解压转换固件

假设固件名是 openwrt-x86-64-generic-ext4-combined-efi 。

export IMGNAME=openwrt-x86-64-generic-ext4-combined-efi
gunzip $IMGNAME.img.gz
qemu-img convert -f raw -O qcow2 $IMGNAME.img $IMGNAME.qcow2

配置 OpenWrt 虚拟机

创建一个虚拟机,假设 vmid 是101。

export VMID=101
qm create $VMID --name openwrt \
--machine q35 \
--memory 512 \
--bios ovmf \
--ostype l26 \
--agent 1,fstrim_cloned_disks=1 \
--cpu x86-64-v2-AES \
--scsihw virtio-scsi-single \
--startup order=1 \
--cores 4

导入 OpenWrt 固件,假设存储名为 local-zfs。

qm importdisk $VMID $IMGNAME.qcow2 local-zfs

打开 PVE 管理后台。 虚拟机 openwrt -> 硬件 -> 未使用的磁盘 -> 配置磁盘。

虚拟机 openwrt -> 硬件 -> 添加一个 efi 磁盘。

虚拟机 openwrt -> 选项 -> 引导顺序 -> 设置磁盘为第一引导。

虚拟机 openwrt -> 硬件 -> 添加一个网络设备 vmbr0 ,用作 lan 口连通 PVE 内虚拟机。

虚拟机 openwrt -> 硬件 -> 添加 PCI设备,选要硬件直通的网卡设备。

OpenWrt 配置 lan 口

默认 PVE 配置的 OpenWrt 网络设备为空,如果配置了网络设备 vmbr0 ,且直通 PCIe 网卡设备,那么 vmbr0 在 OpenWrt 内是 eth0,后面的直通的网口按顺序从 eth1 开始递增。
OpenWrt 第一次开机后,默认配置 eth0 为 lan 口,eth1 为 wan 口,所以网线先插 vmbr0 绑定的网口上就能获取 IP。
默认除了 eht0、eht1,其他网口不会被配置,可以打开 OpenWrt 管理界面后,网络 -> 接口 -> 设备 -> br-lan -> 配置 -> 网桥设备 -> 添加其他 lan 口。
如果暂时网口不能连通,也可以在 PVE 下为 openwrt 添加 lan 口。

qm set $VMID -serial0 socket
qm stop $VMID
qm start $VMID
qm terminal $VMID
vi /etc/config/network

在 config bridge-vlan 下添加对应 lan 口,保存后重启网络服务。

config bridge-vlan
        option device 'br-lan'
        list ports 'eth0'
        list ports 'eth2'
        list ports 'eth3'
        list ports 'eth4'

配置 VLAN

按照构想的网络架构,需要新建三个 vlan 段。

网段 vlan id 用途
home 192.168.88.1/24 192 无线接入和其他家庭设备
pri_server 10.0.10.1/24 10 内网服务器
pub_server 10.0.20.1/24 20 暴露在公网的服务器(无论内网穿透或者转发)

除了home 网段可以单向访问其他网段外,其他网段都相互隔离。

新的 Openwrt 使用 DSA 框架 (Distributed Switch Architecture),具体区别可以查找相关 Openwrt 文档或者 Linux 内核文档,下面配置按 DSA 设置。

当前的 Openwrt 有5个网口:

  • eth0:vmbr0,PVE 网桥,包含全部网段。
  • eth1:直通的网口,eth1 为 wan 口。
  • eth2~4:直通的网口,连接无线 AP 和电脑,只设置192网段。

网口和 vlan 关系表:

eth0 eth2~4
192 U U
10 T
20 T

U: Untagged,T: Tagged

下面配置过程 都只选保存,最后一步才保存并应用,openwrt 检测到 90秒没有设备连接会自动还原配置。

配置 VLAN 设备

网络 -> 接口 -> 设备 -> br-lan -> 配置 -> 网桥 VLAN 过滤。
启动 VLAN 过滤,按下图添加 vlan id。

新建 VLAN 防火墙规则

网络 -> 防火墙 -> 常规设置 -> 添加。

依次添加全部 vlan 区域对应防火墙规则。

新建 VLAN 接口

网络 -> 接口 -> 删除原来 lan接口。
网络 -> 接口 -> 添加新接口。

设置 对应vlan IP段。

设置防火墙区域。

开启 DHCP ,选配置 DHCP 服务器。

依次添加全部接口。 保存并应用。

其他防火墙规则

允许 home 区域访问其他区域。
编辑 home 区域的防火墙规则,允许转发目标区域中选中其他区域。

禁止 pub_server 访问 Openwrt 后台。
防火墙 -> 通信规则 -> 添加。

PVE 配置 VLAN

PVE 节点 -> 系统 -> 网络 -> 选择对应网桥 – 开启 VLAN 感知。 应用配置。

然后在虚拟机 -> 网络设备 -> 网桥中设置 VLAN Tag 就可以划分到对应 vlan 段。

或者直接在PVE 节点 -> 系统 -> 网络中添加一个 Linux VLAN 设备。

IPV6 配置(可选)

因为我上级还有个不可控的路由器,所以没有分配 IPV6-PD 地址,只能先用中继模式配置。
网络 -> wan6 -> DHCP服务器。打开 IPV6 的 DHCP。

然后打开需要分配 IPV6 地址的接口配置。

最后,重启 Openwrt 和 设备网络。

PVE 部署 旁路由 OpenWrt

除了网络设备不用直通网卡,其他创建步骤和前面 PVE 部署 OpenWrt 基本一致。
创建虚拟机的内存可以开大一点,比如 1G。

export VMID=102
qm create $VMID --name bypass \
--machine q35 \
--memory 1024 \
--bios ovmf \
--ostype l26 \
--agent 1,fstrim_cloned_disks=1 \
--cpu x86-64-v2-AES \
--scsihw virtio-scsi-single \
--startup order=1 \
--cores 4

旁路由开机后,打开 192.168.88.2 后台。
网络 -> 接口 -> lan -> 网关,指向主路由。

网络 -> 接口 -> lan -> 高级设置 -> 自定义DNS 指向主路由。

网络 -> 接口 -> lan -> DHCP 服务器 -> 常规设置 -> 忽略此接口。

禁用 lan 接口 IPv6。
网络 -> 接口 -> lan -> 高级设置 -> IPv6 分配长度 -> 禁用。

网络 -> 接口 -> lan -> DHCP 服务器 -> IPv6 设置,全部禁用。

设置好 OpenClash后,修改电脑的网关和 DNS 服务指向旁路由,测试网络是否正常。

配置 keepalived

keepalived 可以实现在旁路由宕机时自动切换到主路由。
SSH 分别连接上主路由和旁路由,执行下面命令。

uci set keepalived.globals.alt_config_file='/etc/keepalived/keepalived.conf'
uci commit

下面这份配置主路由和旁路由有所不同。
修改 interface 为对应的网段的接口设备名,比如 br-lan.192 。
根据需要修改 auth_pass 和 virtual_ipaddress,virtual_ipaddress 需在对应接口的网段内。

主路由配置:

cat > /etc/keepalived/keepalived.conf <<EOF
! Configuration File for keepalived
global_defs {
    router_id LVS_DEVEL
    max_auto_priority 99
    vrrp_no_swap
}

vrrp_instance VI_1 {
   state BACKUP
   interface br-lan
   virtual_router_id 1
   priority 100
   authentication {
       auth_type PASS
       auth_pass 123456
   }
   virtual_ipaddress {
       192.168.88.8
   }
}
EOF

旁路由配置:

cat > /etc/keepalived/keepalived.conf <<EOF
! Configuration File for keepalived
global_defs {
    router_id LVS_DEVEL
    max_auto_priority 99
    vrrp_no_swap
}

vrrp_instance VI_1 {
   state MASTER
   interface br-lan
   virtual_router_id 1
   priority 101
   authentication {
       auth_type PASS
       auth_pass 123456
   }
   virtual_ipaddress {
       192.168.88.8
   }
}
EOF

重启主路由和旁路由,测试 192.168.88.8 是否 ping通。

配置主路由网络,选择设置的 lan 接口, DHCP 服务器 -> 高级设置,设置通告192.168.88.8 为网关和 DNS服务器。

重新连接网线或者 wifi 查看 DHCP 获取的网关和 DNS 服务器是否正确。

发表评论

目录