前言
自不久前 OpenWrt 正式发布 24.10 版本以来,我一直想找个机会将手头的 NanoPi R5S 适配到该版本。近期我终于抽空从零开始构建了一次 OpenWrt,主要是为设备减轻适配负担(旧方案历史包袱过多),也是为本文创造素材。
本文是从源代码制作 OpenWrt 固件的方法,包含构建的基本流程、菜单配置、软件包定制、优化等内容。这是一篇新手向教程,内容繁多但过程简单!
准备工作
设备的基本要求:
系统:Ubuntu 24.04
较多核心的 CPU 和较大的内存!
畅通的网络(如无障碍访问 GitHub)
尽量掌握的技能:
命令行的最基本使用
Git 的最基本使用
安装依赖
在 Ubuntu 24.04 系统上,安装以下依赖:
sudo apt install -y \
build-essential \
ccache \
ecj \
fastjar \
file \
g++ \
gawk \
gettext \
git \
java-propose-classpath \
libelf-dev \
libncurses5-dev \
libncursesw5-dev \
libssl-dev \
unzip \
wget \
python3 \
python3-dev \
python3-setuptools \
python3-pyelftools \
rsync \
subversion \
swig \
time \
xsltproc \
zlib1g-dev \
clang \
golang \
llvm
如果你的系统长久未更新,请先执行 apt update 更新系统。
快速开始
确保环境已准备好。以下将经过一系列十分简洁的步骤,快速构建出第一个可用镜像!
克隆代码
首先我们需要拉取源代码,才能开始后续操作。执行 Git 命令:
git clone https://github.com/openwrt/openwrt.git -b openwrt-24.10 --depth 1
在以上命令中,我们拉取了 OpenWrt 官方仓库 openwrt-24.10 分支的最新代码。其中 -b 参数指定此次克隆的是 openwrt-24.10 分支,--depth 1 表示仅拉取最新的一次提交,无历史记录(避免仓库过大耽误时间)。
更新/安装 feeds
进入 openwrt 目录,执行命令:
./scripts/feeds update -a && ./scripts/feeds install -a
等待 feeds 的更新和安装,全部完成后就可以开始配置了。
菜单配置
执行 make menuconfig 打开构建菜单。菜单配置的基本使用:
方向键和 Tab 键移动焦点
回车进入子菜单
空格切换选择状态(<*> / [*]、
本文以 NanoPi R5S 为例,24.10 的官方代码已经适配了此设备。我们直接选择对应的 profile 即可。步骤如下:
进入 Target System --->,勾选 <*> Rockchip
进入 Subtarget --->,勾选 <*> RK33xx/RK35xx boards (64 bit)
进入 Target Profile --->,勾选 <*> FriendlyARM NanoPi R5S
其它设备请通过 OpenWrt 的 Supported devices 页面寻找对应的 profile。
完成以上三个配置后,应该是这个样子的:
留意箭头的位置,它应该对应你的设备的全名(品牌 + 型号)。
实际上我们现在就已经可以开始构建了!但是为了更直观的看出配置的简单性,我们进一步探索一下。
执行如下命令生成 diffconfig:
./scripts/diffconfig.sh > diffconfig
查看 diffconfig 文件,内容如下:
CONFIG_TARGET_rockchip=y
CONFIG_TARGET_rockchip_armv8=y
CONFIG_TARGET_rockchip_armv8_DEVICE_friendlyarm_nanopi-r5s=y
嗯,最简单的配置就是这么简洁。后续的任何新增修改,都可以导入 diffconfig。通过此文件迁移/恢复菜单配置。
构建
现在,开始第一次构建!执行如下命令:
make -j$(nproc) || { make -j1 V=s; }
有一些教程会告诉你先执行 make -j$(nproc),如果出错了就执行 make -j1 V=s。而以上命令的含义就是,当前者执行失败后,自动执行后者。
过程可能会比较漫长。如果是笔记本电脑,可能要几个小时。在我的台式电脑上,全新的构建大约 40 分钟左右。
构建输出在 bin/targets 目录,目录树如下:
bin/targets/
└── rockchip
└── armv8
├── config.buildinfo
├── feeds.buildinfo
├── openwrt-rockchip-armv8-friendlyarm_nanopi-r5s-ext4-sysupgrade.img.gz
├── openwrt-rockchip-armv8-friendlyarm_nanopi-r5s.manifest
├── openwrt-rockchip-armv8-friendlyarm_nanopi-r5s-squashfs-sysupgrade.img.gz
├── packages
├── profiles.json
├── sha256sums
└── version.buildinfo
4 directories, 8 files
可以看到我们的固件在 rockchip/armv8 目录,该目录生成文件大小如下:
4.00 KiB config.buildinfo
4.00 KiB feeds.buildinfo
4.00 KiB openwrt-rockchip-armv8-friendlyarm_nanopi-r5s.manifest
4.00 KiB profiles.json
4.00 KiB sha256sums
4.00 KiB version.buildinfo
1.03 MiB packages
8.14 MiB openwrt-rockchip-armv8-friendlyarm_nanopi-r5s-squashfs-sysupgrade.img.gz
8.91 MiB openwrt-rockchip-armv8-friendlyarm_nanopi-r5s-ext4-sysupgrade.img.gz
18.09 MiB total
这时候的固件体积还是很小的,不到 10MB。现在我们将 openwrt-rockchip-armv8-friendlyarm_nanopi-r5s-squashfs-sysupgrade.img.gz 文件通过 OpenWrt 的「系统」-「升级与备份」-「刷写固件」功能上传,即可将自己编译的固件刷入设备。
当然,刷入当前固件的意义并不大。通常我们的固件至少需要包含 LuCI,否则只能进行 SSH 命令操作。请从下一节开始,继续完善你的固件。至少完成 LuCI 基础包的配置,然后重新执行构建命令。结束后尝试将包含 LuCI 的固件刷入设备,现在访问路由器的 IP 地址应该可以看到页面了。
定制软件包
本章节是一些基础软件包和推荐软件包的配置方法,可以随意跳过没有先后和依赖关系。
切记每次完成配置后,使用底部的 < Save > 功能保存。以避免好不容易调整的配置丢失!
增加分区大小
如果在进行一定量的软件包添加后,构建发生下类错误:
ext4_allocate_best_fit_partial: failed to allocate 4996 blocks, out of space?
它提醒你调整根文件系统的分区大小。进入构建菜单中的 Target Images --->,修改 Root filesystem partition size (in MiB) 的值。当发送类似上述错误时,应该增大这个值(例如我将其设置为 1024)。
增加分区大小时不要超出路由器的实际可用空间。
LuCI
LuCI 是 OpenWrt 的 Web 管理界面,是许多功能的前端。基本上你没有理由拒绝安装它,除非你是极端的 SSH 命令行用户。
包含 LuCI 的基础包:
路径:LuCI --->,Collections --->
勾选:<*> luci
调整 LuCI 的默认语言为中文:
路径:LuCI --->,Modules --->,Translations --->
勾选:<*> Chinese Simplified (zh_Hans)
包含额外 LuCI 主题:
路径:LuCI --->,Themes --->
勾选:<*> luci-theme-material(我通常使用这个主题)
Docker
Docker 是最流行的容器化方案之一。通过 Docker 可以轻易部署很多服务端应用,而不用担心环境问题。使用 Docker 可以大幅度扩展 OpenWrt 的应用范围,不用顾及「有没有包」这种问题。
包含 Docker 基础包:
路径:Utilities --->
勾选:
<*> docker
<*> docker-compose
<*> dockerd --->
包含 LuCI 的 Docker 前端:
路径:LuCI --->,Applications --->
勾选:<*> luci-app-dockerman
可选增强功能:
返回到 <*> dockerd ---> 包的位置,回车进入子菜单,然后可以进一步启用一些可选功能了。例如 Overlay 网络驱动、对 Ext4/Ext3/Brafs 后备文件系统的支持等。
LXC
LXC 是另一个容器技术。和 Docker 不同它并非为部署单个应用进程而设计,它更像一个完整的虚拟机环境。使用 LXC 可以在 OpenWrt 这类简陋的嵌入式系统中体验各种传统 Linux 发行版(如 Ubuntu、Arch Linux、Void Linux 等),它们都比 OpenWrt 能做的多。
包含 LXC 基础包:
路径:Utilities --->
勾选:<*> lxc --->
包含必要的用户空间工具:
回车进入 <*> lxc ---> 子菜单
勾选:
<*> lxc-attach
<*> lxc-checkconfig
<*> lxc-config
<*> lxc-configs
<*> lxc-create
<*> lxc-destroy
<*> lxc-ls
<*> lxc-start
<*> lxc-stop
<*> lxc-templates
由于 R5S 空间充足,我勾选了全部的用户空间工具(lxc- 开头的包),并在 Configuration 中勾选了全部可选支持。
NFS
NFS 是 Linux 上常见的存储共享技术,在服务端应用更多。如果你有多个路由器,可以在路由器之间用 NFS 挂载彼此的远程目录,共享同一片存储。
包含必要的 NFS 包和配置:
路径:Network --->,Filesystems --->
勾选:
<*> nfs-kernel-server
<*> nfs-kernel-server-utils
Select nfs-kernel-server configuration options --->,[*] Include support for NFSv4
包含额外的 NFS 模块:
路径:Kernel modules --->,Filesystems --->
勾选:<*> kmod-fs-nfs-v3
Samba
Samba 是 SMB 的开源实现。相比于 NFS,Samba 更贴近普通用户,也更适合 Windows、Android 等操作系统。通常我们在内网共享文件,组建 NAS,主要使用 SMB 协议(Samba 服务端)。
包含必要的 Samba 软件包:
路径:Network --->
勾选:
<*> samba4-server
<*> samba4-utils
这里没有包含 Samba 的客户端(即 samba4-client),因为路由器通常是服务端角色。
包含 LuCI 的 Samba 前端:
路径:LuCI --->,Applications --->
勾选:<*> luci-app-samba4
DDNS
DDNS 即动态 DNS。它可以定期获取路由器变更的 IP,并自动更新 DNS 记录。让接入国内家庭宽带这类动态 IP 的路由器实现固定的域名访问。
包含必要的包:
路径:Network --->,IP Addresses and Names --->
勾选:
<*> ddns-scripts
<*> ddns-scripts-services
<*> ddns-scripts-utils
特定提供商支持,如 <*> ddns-scripts-cloudflare(Cloudflare)
包含 LuCI 的 DDNS 前端:
路径:LuCI --->,Applications --->
勾选:<*> luci-app-ddns
collectd
collectd 是一个用于收集系统各项指标数据的工具,以插件化的方式工作。以下勾选的插件从 CPU、硬盘等基本硬件到负载、DNS、交换空间等软件数据全面覆盖。
包含必要的包:
路径:Utilities --->
勾选:<*> collectd --->
包含必要的模块:
路径:Utilities --->,<*> collectd --->
勾选:
<*> collectd-mod-cpu
<*> collectd-mod-cpufreq
<*> collectd-mod-disk
<*> collectd-mod-dns
<*> collectd-mod-ethstat
<*> collectd-mod-interface
<*> collectd-mod-iptables
<*> collectd-mod-irq
<*> collectd-mod-iwinfo
<*> collectd-mod-load
<*> collectd-mod-memory
<*> collectd-mod-network
<*> collectd-mod-ping
<*> collectd-mod-rrdtool
<*> collectd-mod-sensors
<*> collectd-mod-swap
<*> collectd-mod-thermal
包含 LuCI 的 collectd 前端:
路径:LuCI --->,Applications --->
勾选:<*> luci-app-statistics
SQM
SQM 可以更智能的管理网络数据包队列(流量整形)。在高网络负载时,提升网络性能,有效避免网络堵塞和延迟升高。
包含必要的包:
路径:Base system --->,sqm-scripts --->
勾选:<*> sqm-scripts
包含 LuCI 的 sqm 前端:
路径:LuCI --->,Applications --->
勾选:<*> luci-app-sqm
QoS
QoS 是一种网络流量控制技术,可以根据不同的流量类型(如视频、游戏、下载等)进行优先级调整,以保证重要流量的传输质量。
包含必要的包:
路径:LuCI --->,Applications --->
勾选:<*> luci-app-qos
vnstat2
vnstat2 是一个网络流量监控工具,可以监控网络流量的上传和下载情况。vnstati 用于生成流量统计图表。
包含必要的包:
路径:Network --->
勾选:
<*> vnstat2
<*> vnstati2
包含 LuCI 的 vnstat2 前端:
路径:LuCI --->,Applications --->
勾选:<*> luci-app-vnstat2
nlbwmon
nlbwmon 也是网络流量的监控工具。它通过 ARP 协议获取设备的 MAC 地址,然后通过 iptables 规则统计流量。可以十分精细的看到每个设备的流量情况。
包含必要的包:
路径:Network --->
勾选:<*> nlbwmon
包含 LuCI 的 nlbwmon 前端:
路径:LuCI --->,Applications --->
勾选:<*> luci-app-nlbwmon
frp
frp 是一个内网穿透工具,可以将内网服务映射到公网。例如你可以通过 frp 将路由器的 LuCI 界面映射到公网,方便远程管理。当然,你需要一个公网服务器作为 frp 服务端。
包含必要的包:
路径:Network --->,Web Servers/Proxies --->
勾选:<*> frpc
包含 LuCI 的 frpc 前端:
路径:LuCI --->,Applications --->
勾选:<*> luci-app-frpc
这里没有包含 frp 的服务端(即 frps),因为路由器通常是客户端的角色。
外部存储
如果你的路由器有 USB 接口,可以通过 USB 设备扩展路由器的存储空间。以下是 USB 挂载以及尽量通用的存储支持配置,包括对其它协议和各种文件系统支持。
包含必要的 USB 支持模块:
路径:Kernel modules --->,USB Support --->
勾选:
<*> kmod-usb-storage-extras
<*> kmod-usb-storage-uas
解释:UAS 是移动硬盘所使用的协议。虽然移动硬盘作为 USB 设备,但需要 UAS 协议支持才能使用。
包含必要的挂载工具包:
路径:Base system --->
勾选:<*> block-mount
包含必要的文件系统模块:
路径:Kernel modules --->,Filesystems --->
勾选:
<*> kmod-fs-btrfs
<*> kmod-fs-exfat
<*> kmod-fs-ext4
<*> kmod-fs-f2fs
<*> kmod-fs-ntfs3
<*> kmod-fs-vfat
解释:exfat/vfat 是 U 盘/SD 卡常用的文件系统。ext4/btrfs 是 Linux 上常用的文件系统。ntfs 是 Windows 上常用的文件系统。f2fs 是为移动设备闪存优化的文件系统,被 Android 推荐。
工具集
除了以上值得详细介绍的软件之外,还有很多工具也是我们在日常路由器维护、调试中会用到的,例如:
<*> blkid:查看块设备的 UUID
<*> curl:网络请求工具
<*> exfat-mkfs:exFAT 文件系统格式化工具
<*> f2fs-tools:f2fs 文件系统工具
<*> htop:系统负载查看工具
<*> hwinfo:硬件信息查看工具
<*> iperf3:网络性能测试工具
<*> ipset:IP 地址集管理工具
<*> jq:JSON 数据处理工具(用于在脚本中解析 API 响应数据)
<*> lsblk:列出块设备列表
<*> mount-utils:挂载工具集
<*> nano-full:nano 编辑器(小巧的终端编辑器)
<*> nstat:网络统计工具
<*> openssl-util:OpenSSL 工具集
<*> rclone:云存储同步工具
<*> rclone-config:rclone 配置工具
<*> screen:终端多路复用工具
<*> smartmontools:硬盘健康信息查看工具
<*> smartmontools-drivedb:smartmontools 驱动数据库
由于工具太多,此处不再列举具体路径。在菜单配置中可通过 / 搜索功能查找。
优化
TCP BBR
BBR 是 Google 研发的 TCP 拥塞控制算法,用于提高网络利用率。尤其在网络质量不佳造成拥堵的场景下,提升极为显著。
包含必要的内核模块:
路径:Kernel modules --->,Network Support --->
勾选:<*> kmod-tcp-bbr
zram
zram 是一个内核功能,可将一部分内存虚拟为具有实时压缩功能的交换块设备(/dev/zram*)。它可以取代传统的基于硬盘的 Swap(或同时存在),显著提升交换的速度。
虽然 zram 利用内存自身作为交互空间,但不是无意义的。因为 zram 可以实时压缩交换进去的数据,理论上可以容纳数倍于物理内存的数据(指解压后),具体取决于数据的可压缩性和压缩算法。
需要注意的是:zram 的压缩/解压缩过程会消耗一定的 CPU 资源。
包含必要的 zram 包:
路径:Base system --->
勾选:<*> zram-swap
包含必要的内核模块:
路径:Kernel modules --->,Other modules --->
勾选:<*> kmod-zram
调整 zram 的 compressor(压缩器):
路径:Base system --->,Other modules --->,ZRAM Default compressor --->
选择:(X) lz4(兼具速度和压缩率,适合性能不高的 ARM 设备)
默认情况下 OpenWrt 会使用物理内存的一半作为 zram 的交换空间。它可以和基于硬盘的 Swap 同时存在。
本章节还有一些内容,缓慢更新中……
结束语
这就是从源码构建实际可用的 OpenWrt 固件(及配置方法)的入门教程了。在 24.10 之前,本文举例的设备 R5S 实际上没有得到官方支持。它通过合并其它来源的补丁适配到 OpenWrt,更复杂和麻烦。但现在已经不需要了,所有的历史包袱(如过时补丁、版本限制)也不存在了。
由我构建和定制的 R5S 固件:Hentioe/OpenWrt-NanoPi-R5S-Builds。