由于需要为旁路由安装一些特定插件,我决定自行编译。如果只需要一些官方仓库提供的插件,可以使用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 服务器是否正确。