去年买了块友善的 NanoPi R3S 当家庭路由器。一开始也是刷现成的iStoreOS固件,后来想从内核到镜像完整做一遍,于是有了这篇记录。希望能够尽量写清楚每一步在做什么,以及我为什么思考这么做。
一、为什么用 Linux 自建路由器?
1.1 我为什么不直接用 OpenWrt
OpenWrt、LEDE、iStoreOS 这些名字,玩软路由的人应该都很熟。LEDE 本来是 OpenWrt 的一个分叉,后来两边又合并回去了;iStoreOS 则是基于 OpenWrt 做的家用衍生版。它们的内核都是基于 Linux,但用户空间是为路由器专门定制的一套生态:opkg 包管理(新版本已经迁移到了 apk )、BusyBox 工具集、procd 初始化、UCI 配置体系和 LuCI 网页界面,和传统的 Linux 发行版有很大不同。
这套东西的好处是刷完基本就能用,插件多,教程也多。尤其是带 Wi-Fi 的路由器,OpenWrt 对常见无线芯片的支持通常比通用发行版省心。
但对我来说有个很实际的问题:这套生态和我平时用的常规 Linux 发行版差别比较大,在工具链和软件生态上迥然不同。多年的玩 Linux 我已经比较数据apt install 、pacman -S、apk add等方式安装和管理软件、systemctl、rc-service 来管服务、写 nftables 规则、改 sshd 配置,这些习惯到了 OpenWrt 上全要换一套思路。我只是想要一台路由器,并不想专门再学一套路由器操作系统,虽然绝大部分都可以通过 Web 操作,但大部分时候还是不太习惯。
1.2 我希望路由器上跑的是普通 Linux
于是想法就变成:让 R3S 上跑的,就是一台普通的 Alpine/Debian/Void甚至是Gentoo等一些常规的发行版。理由其实很朴素:
- 工具链通用。
apk add、rc-update、nftables、sshd、cron,服务器上怎么写,路由器上就怎么写。遇到问题搜到的资料、以前积累的经验,都能直接拿来用; - 装软件方便。Docker、sing-box、tailscale、cloudflared 这些,主流发行版基本都有现成的包或者官方二进制,不用等哪位作者出路由器插件;
- 配置就是文件,服务就是进程。没有 UCI 这类封装,出了问题直接看配置和日志就行;
- 内核可以自己裁剪[[DeepSeek V4试用:基于linux的内核裁剪和路由系统构建的小尝试]],用户空间可以自己选发行版;
- 整个构建过程可以脚本化,想要一个干净的系统随时重来。
一句概括:OpenWrt 是别人装好的成品,但我想从零件开始装一台。
1.3 OpenWrt 系和通用 Linux 的差别
| OpenWrt / LEDE / iStoreOS | 通用 Linux(Alpine / Debian / Void 等) |
|---|
| | |
| | apt / apk / xbps / emerge |
| | |
| | |
| | |
| | |
| | |
区别不在于能不能当路由器,而在于出问题的时候,你用哪一套知识去排查。OpenWrt 的知识基本只在路由器上有用;通用 Linux 的每一条命令,放到服务器上还是一样的。
1.4 各自的优缺点(个人看法)
OpenWrt 系好的地方
- LuCI 界面、插件、QoS、上网行为管理、科学上网方案都很成熟,装好就能用;
不太顺手的地方
- 生态相对独立,一些新的通用软件适配慢,想用新版本经常得自己编译;
- 系统封装比较深,排查问题绕不开 UCI、procd 这些;
- 默认面向几十 MB 闪存、一两百 MB 内存的机器设计,放到 2GB 内存的 R3S 上有点浪费;
- 固件版本比较碎,OpenWrt 和各家衍生版各维护各的。
通用 Linux 好的地方
- 工具链、日志、防火墙、SSH、定时任务,和服务器同一套;
- 想装什么装什么,标准仓库没有的,官方静态二进制基本也有;
- 内核跟主线比较近,WireGuard、BBR、nftables、flowtable、eBPF 都用得上,不满意还能自己裁;
- 要 Docker 就装 Docker,要面板就自己写,都不要也行;
麻烦的地方
- 没有 LuCI 这种现成的网页界面,基础服务都得自己配(后面我会写自己搭了一个简单的 dashboard);
- 某些路由器无线芯片的驱动支持不如 OpenWrt(R3S 是双千兆有线口,没有 Wi-Fi,正好避开这个坑);
- 上手有门槛,DHCP、防火墙、DNS 这些需要自己理解;
- 默认比 OpenWrt 占地方,不过 2GB 内存、大 TF 卡的开发板根本不在乎这点;
- 出问题得靠真正的 Linux 基础,不是点网页能解决的。
1.5 Linux 内核本身在路由器上的优势
即便不用通用发行版,路由器系统大多也跑在 Linux 内核上 (甚至pf都有迹象往 Linux 迁移),特别是近年来基于 eBPF 的各种网络工具涌现,说明这一层本身足够可靠:
- 路由、NAT、conntrack、nftables、流量整形、策略路由都是内核原生功能,经过大量场景验证;
- WireGuard 已经合入主线,BBR、flowtable、eBPF/XDP 这些新特性也都在主线里,用不用、怎么用由自己决定;
- RK3566 这类主流 SoC 的主线支持比较完善,还能用 Armbian 这类构建框架稳定产出专用内核;
- 内核可以按需裁剪,根据实际需求定制内存提高性能,甚至可以显著地提高网络流量的吞吐;
- 安全、审计、日志、容器隔离这些运维能力都是现成的,镜像也完全可以复现。
- 新工具的支持,比如在 R3S 这种路由器上能够部署 ZeroClaw 这种非常轻量化的 AI Agent 工具。
1.6 什么情况不建议这么搞
反过来也要说清楚:
- 路由器要带 Wi-Fi 而且芯片比较偏,OpenWrt 的驱动支持更省心;
如果你和我一样,能接受折腾、想要一台完全看得懂的系统,那继续往下看。
二、硬件选型:NanoPi R3S
自建路由器不一定需要一台大机器,一块开发板就够了。我选的这块是友善电子的 NanoPi R3S:
| |
|---|
| Rockchip RK3566,四核 Cortex-A55,最高 1.8GHz |
| |
| 2× 千兆以太网:板载 RTL8211F + PCIe 接口的 RTL8111H |
| |
| USB 3.0 × 1、USB-C(5V/2A 供电兼数据)、调试串口 |
| 板载 RTC(HYM8563)、电源/用户/MASK 按钮、WAN/LAN/SYS 三颗 LED |
选它的原因很简单:两个千兆网口天生就是路由器的一进一出,2GB 内存跑这些服务绰绰有余,整板功耗低,丢弱电箱里不心疼。另外 RK3566 是主流 SoC,主线 Linux 支持完善,可以直接跑标准的 aarch64 发行版。
系统默认网络约定:
| |
|---|
| |
| |
| 192.168.8.100 – 192.168.8.200 |
| |
当然,如果可以选择 x86 的机器也更好,路由器的转发很吃 CPU 的单核频率,所以 x86 在软路由上也是不错的选择。
三、整体架构:三层各司其职
整个项目按从内核到镜像的顺序拆成了三个独立工程:
第一层 内核裁剪工程:裁剪 Linux 内核 + U-Boot + 设备树(DTB)
│ 产出 boot bundle(vmlinuz / dtb / u-boot / 内核模块)
▼
第二层 用户空间工程:构建最小化 rootfs(基础系统 + 网络工具 + 配置文件 + 服务管理)
│ 产出 rootfs 压缩包
▼
第三层 镜像组装工程:分区、写引导、拷贝 rootfs、校验
│ 产出可烧录的 SD 卡镜像 .img.gz
每一层都可以独立构建、独立复用。内核编译一次要 20-30 分钟,但产物能长期保存;rootfs 每个发行版几分钟到半小时不等;两份半成品都有了以后,组装镜像只要几分钟。改动哪一层就重做哪一层,不用全部推倒。
四、第一层:把内核裁到“刚够用”
4.1 为什么要裁剪
开发板发行版(比如 Armbian)自带的内核面向“什么都能跑”,桌面、无线、虚拟化、各种冷门文件系统全在里面。路由器用不到这些,还占空间、扩大攻击面。
这套方案基于 Armbian 的构建框架,通过 userpatches 机制接管内核配置,将内核编译选项裁到 860~906 项,同时将必备的驱动和组件直接编译进内核,提升加载速度和执行性能。
裁剪效果(minimal 模式与上游对比):
4.2 裁剪策略
原则就一条:路由器用不到的东西整段关掉,核心功能一个都不能少。
关闭的大类:
- iptables/xtables/ipset/ebtables 兼容层——只用 nftables;
- 冷门文件系统、服务器存储控制器、调试/BTF 等;
- 不必要的驱动,只保留 R3S 需要的 GMAC(板载)和 RTL8169(PCIe 千兆);
- 根据实际情况可以考虑裁剪掉 docker / eBPF 等支持
保留的红线功能:WireGuard 及其密码学依赖、ext4、TUN(透明代理必需)、nftables/NAT、VLAN、PPPoE、bonding、板载 RTC 驱动等。
裁剪脚本的核心动作很直白:
# 关闭整段 iptables 兼容层(只保留 nftables 路线)
unset_k NETFILTER_XTABLES
unset_k IP_SET
unset_k BRIDGE_NETFILTER
# 把路由器核心功能强制设为 =y(编进内核)
set_y NF_TABLES_INET
set_y NFT_FLOW_OFFLOAD # 软件快速转发
set_y TUN # sing-box / VPN 必需
set_y WIREGUARD
set_y DWMAC_ROCKCHIP # 板载 GMAC 驱动
set_y RTC_DRV_HYM8563 # 板载 RTC
4.3 四种裁剪模式
不是所有人只需要“纯路由”,所以做了四种档位:
4.4 红线检查:防止“裁过头”
内核配置有个经典坑:关掉 A,结果 B 通过 select 又把 A 拉回来;或者关掉 C,结果 D 悄悄依赖 C,编译出来功能缺失。
所以我让裁剪脚本每次跑完都做红线检查:WireGuard 的密码学依赖链必须完整、ext4/TUN/GMAC/RTC 必须为 =y、nftables/NAT/PPPoE 等至少为 =m,任何一条不满足就构建失败。镜像组装后的校验脚本还会检查“本应编进内核的模块没有残留成 .ko 文件”。
说实话,裁内核的过程没少踩坑,有一阵子甚至把路由器启动内核 panic,最后只能上串口调试线才逐步的排查具体原因。这也是为什么后面会把校验做进构建流程里。
五、第二层:构建最小化 rootfs
内核决定能跑什么,rootfs 决定系统长什么样。这一层要解决的是:在裁剪好的内核之上,装一个只包含路由器所需软件的最小 Linux 用户空间。
5.1 选哪个发行版?
这套方案支持五种发行版作为底座,覆盖 Linux 生态的几个典型分支:
我主力用的是 Alpine,体积最小,只有 glibc 系的一半;其他发行版也保留着,随时能切换。选哪个完全看个人偏好:想精简到底选 Alpine,想要最大软件仓库选 Debian,想折腾 USE flag 选 Gentoo。
5.2 每个发行版只拆四个文件
一开始所有逻辑都堆在一个 build.sh 里,很快就没法维护。后来拆成四个职责明确的文件:
distros/<发行版>/
├── build.sh # 生命周期:下载基础系统 → chroot → 清理 → 打包
├── setup.sh # 配置:安装包、写配置、设置密码
├── service.sh # 服务声明:按 init 系统启用哪些服务
└── package.list # 物料清单:每行一个包的声明式列表
package.list 是这套设计里比较有意思的部分。它用两种前缀区分安装方式,五种发行版共用同一套语法:
# ========== base ==========
[pm] openssh
[pm] chrony
[pm] dnsmasq
[pm] nftables
[pm] tailscale
[dl@https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-arm64] cloudflared
# ========== sing-box ==========
[pm] sing-box
[pm] 走系统包管理器(apk / xbps / apt / emerge),[dl@URL] 直接下载静态二进制。新增发行版时只需要适配包管理器语法,整体架构不用重新设计。
5.3 网络配置:一个数据源,处处生效
路由器最烦的事情之一:改一个 LAN IP,要同时改网络接口文件、DHCP 配置、防火墙变量,漏一个就出诡异故障。
解决办法是把网络拓扑收敛到一个文件 network.env:
WAN_IFACE=eth0
WAN_MODE=dhcp
LAN_IFACE=eth1
LAN_IP=192.168.8.1
LAN_NETMASK=255.255.255.0
LAN_CIDR=24
LAN_NETWORK=192.168.8.0/24
DHCP_RANGE_START=192.168.8.100
DHCP_RANGE_END=192.168.8.200
DHCP_LEASE_TIME=12h
各发行版在部署阶段读取它,生成自己的原生网络配置,同时把 dnsmasq、nftables 模板里的占位符替换掉:
configure_network() {
. /network.env
cat > /etc/network/interfaces <<EOF
auto lo
iface lo inet loopback
auto ${WAN_IFACE}
iface ${WAN_IFACE} inet dhcp
auto ${LAN_IFACE}
iface ${LAN_IFACE} inet static
address ${LAN_IP}
netmask ${LAN_NETMASK}
EOF
_replace_placeholders # 替换 dnsmasq / nftables 中的 __LAN_IP__ 等
}
构建结束前还会扫一遍配置文件,只要有 __XXX__ 占位符残留就直接中止构建,把“配置没生效”的问题挡在生成镜像之前。
5.4 服务启动顺序
服务按依赖关系排序,特别是防火墙必须最先加载,不然每次重启都有一段裸奔窗口,处理逻辑全部写在 service.sh 脚本中,不同发行版的服务一致,只是启动命令根据 init 系统修改即可:
# base版本
nftables → dnsmasq → ssh/chrony → tailscale/cloudflared
# sing-box版本
nftables → dnsmasq → ssh/chrony → sing-box → tailscale/cloudflared
5.5 精简与打包
rootfs 构建完会做一轮瘦身:删掉 locale、man、文档,清空包管理器缓存,strip 调试符号,最后用 xz 极限压缩。这也是最终 rootfs 只有几十 MB 的原因。
六、第三层:组装成可启动镜像
6.1 引导链
RK3566 的启动过程大致是:U-Boot → extlinux.conf → 内核 vmlinuz + 设备树 DTB → ext4 根文件系统。
组装时生成的关键引导文件:
TIMEOUT 10
DEFAULT alpine
LABEL alpine
MENU LABEL Alpine Linux (default)
KERNEL /boot/vmlinuz-*
FDT /boot/dtb/rockchip/rk3566-nanopi-r3s.dtb
APPEND root=/dev/mmcblk1p1 rootwait rw rootfstype=ext4 \
console=ttyS2,1500000 net.ifnames=0 loglevel=4
在这里配置 extlinux.conf 时因为 root 目录配置错误导致内核启动成功,但一直不能进入用户空间,后来还是靠串口调试看日志才发现解决问题,所以尽量选择但输出端口的设备就很好啊。
6.2 镜像布局
SD 卡镜像的分区布局:
sector 0 GPT 分区表头
sector 64 (32KB) U-Boot(写在 GPT 保留区,不进分区表)
16MB 起 ext4 根分区(rootfs,label 为发行版名)
组装脚本干的事就是:建 GPT 分区表 → 把 U-Boot 写到第 64 扇区 → 格式化 ext4 → 挂载并拷贝 rootfs → 压缩成 .img.gz。整个流程可以一条命令串起来,方便在构建机或 CI 里反复执行。
6.3 校验:不校验就不算构建完成
组装完还会跑一遍自动化校验,检查:
- GPT 分区表是否存在、U-Boot 是否真的写入了指定扇区(magic 校验);
- extlinux.conf 的串口、root 设备参数是否正确;
- vmlinuz 是否为合法的 ARM64 ELF、DTB 是否为合法 FDT;
- nftables / dnsmasq / sing-box 等关键服务是否已配置并启用;
任何必选项失败就不发布。比刷到卡里再发现坏了强。
6.4 烧录
拿到最终镜像后,写卡一条命令:
gunzip -c rk3566-sd-alpine-sing-box-minimal-*.img.gz | sudo dd of=/dev/sdX bs=4M status=progress
插入 TF 卡、接好网线和电源,从串口(ttyS2,1500000 波特率)或局域网 SSH 登录即可。
七、运行时的网络架构
这是整个过程中最重要的部分,因为开机之后才是路由器真正干活的地方。整体拓扑:
互联网 ── eth0(WAN,DHCP)
│
┌───┴───┐
│ R3S │ nftables / dnsmasq / sing-box[1] / tailscale / cloudflare ...
└───┬───┘
│
eth1(LAN,192.168.8.1)
│
交换机
│
手机 / 电脑 / PVE服务器 / IoT ...
[1]: sing-box是一个强大的综合网络管理平台,能够提供完整的网络服务,一般能够单程序提供多个工具联合提供的能力
7.1 DHCP:dnsmasq
LAN 口用 dnsmasq 提供 DHCP 和 DNS。DHCP 模板:
dhcp-range=eth1,192.168.8.100,192.168.8.200,255.255.255.0,12h
dhcp-option=eth1,3,192.168.8.1 # 网关
dhcp-option=eth1,6,192.168.8.1 # DNS 指向路由器自身
基础模式下 DNS 上游用的是阿里云和腾讯 DNS,国内解析够快够稳。 如果选择了 sing-box 可以使用其本身提供的 DNS 服务,这样只需要一个提供 DHCP 服务的工具即可,可以在 dnsmasq 中禁用 DNS 服务,只使用其 DHCP 服务,也可以使用 udhcpd 等更轻量的工具代替 dnsmasq 。
7.2 防火墙:nftables
防火墙策略是“默认丢弃、显式放行”。接口、端口、网段先定义成变量,规则看起来清楚很多:
define WAN = eth0
define LAN = eth1
define WG_PORT = 51820
define TS_PORT = { 41641, 41642 }
define SSH_PORT = 22
define LAN_NET = 192.168.8.0/24
NAT 部分只有两条核心规则:
# LAN/VPN/TUN 的流量出 WAN 时统一做源地址伪装
meta nfproto ipv4 oifname @wan_interfaces masquerade;
# VPN 客户端访问内网时,以内网地址对内通信
meta nfproto ipv4 iifname @vpn_interfaces oifname @lan_interfaces masquerade;
过滤部分的几个设计点:
- INPUT 默认
drop:WAN 侧只开放 WireGuard/Tailscale 握手 UDP 端口和受限 ICMP; - SYN flood 限速(超过 100/秒)自动把来源 IP 加入 1 小时动态黑名单;
- SSH 按来源限速(LAN 30 次/分钟,VPN 60 次/分钟),防暴力破解刷屏;
- FORWARD 默认
drop,显式允许 LAN → TUN、TUN → WAN 等路径; - 用 flowtable 做 TCP/UDP 转发卸载,跑满千兆时减轻 CPU 压力;
- MSS Clamping 保证 PPPoE 这类场景下 TCP 不被 MTU 问题卡死;
7.3 系统调优:sysctl
针对 2GB 小内存设备做过一轮内核参数调优:
# 核心转发
net.ipv4.ip_forward = 1
# 收紧连接跟踪超时,加速回收空闲连接
net.netfilter.nf_conntrack_tcp_timeout_established = 3600
net.netfilter.nf_conntrack_tcp_timeout_syn_recv = 15
# 内存上限,防止网络栈挤占内存导致 OOM
net.ipv4.tcp_mem = 32768 43690 65536
# BBR 拥塞控制 + fq 队列
net.core.default_qdisc = fq
net.ipv4.tcp_congestion_control = bbr
# 反向路径过滤:全局兼容 tproxy,物理口用宽松模式,VPN 口显式关闭
net.ipv4.conf.all.rp_filter = 0
net.ipv4.conf.default.rp_filter = 2
net.ipv4.conf.wg0.rp_filter = 0
net.ipv4.conf.ts0.rp_filter = 0
这里最容易忽略的是 rp_filter:透明代理会给流量打标,按默认严格模式过滤会把回包丢掉,所以按“全局兼容 + 物理口宽松 + VPN 口关闭”来设。
7.4 透明代理与分流:sing-box
sing-box 可以全面管理网络,也可以只作为透明代理和分流工具,路由器内置 sing-box,通过 TUN 模式接管 LAN 流量,这样能够统管网络流程处理:
{
"type": "tun",
"tag": "tun-in",
"interface_name": "tun0",
"address": ["172.19.0.1/30"],
"mtu": 1280,
"auto_route": true,
"include_interface": ["eth1"],
"auto_redirect": true,
"strict_route": false
}
DNS 做分流:广告域名直接返回 NXDOMAIN,代理白名单域名走代理 DNS 防污染,其他域名走国内 DNS:
"dns": {
"servers": [
{ "tag": "local", "server": "223.5.5.5" },
{ "tag": "tencent","server": "119.29.29.29" },
{ "tag": "google", "server": "8.8.8.8", "detour": "ss-out" }
],
"rules": [
{ "rule_set": ["adblock-reject", "geosite-ads", "adblock-cnlite"],
"rcode": "NXDOMAIN" },
{ "rule_set": ["proxy-list"], "server": "google" }
],
"final": "local"
}
路由决策是“默认直连、白名单代理”,不是全局代理。规则顺序很关键:
1. 代理服务器自身流量 → 直连(防止死循环,必须最优先)
2. BT 流量 → 直连
3. 广告规则集命中 → 阻断
4. 代理白名单命中 → 走代理
5. Tailscale 进程流量 → 直连
6. Tailscale/Headscale 网段 → 走 Headscale endpoint
7. 私网 → 直连
8. 兜底 → 直连
有一点要分清楚:流量经过 TUN 不等于经过代理。TUN 只是把流量交给 sing-box 决策,最终直连还是代理由规则决定。
7.5 组网与隧道
- Tailscale / Headscale:组网工具用来构建 site-to-site 星型网络;
- 以上可以单独部署,也可以在 sing-box 中集中管理,如果使用 sing-box 就不需要安装以上工具,单一的 sing-box 二进制文件提供所有的服务
八、把构建变成可重复的流水线
手工构建一遍没问题,但要长期维护,得让构建可重复、可复用、可验证。
8.1 资产复用
内核和 rootfs 都是昂贵的“半成品”,构建一次后长期复用。组装镜像时可选四种组合:
8.2 一键构建
本地一条命令就能完成“编译内核 → 构建 rootfs → 组装镜像”:
sudo bash local-build.sh --kernel-mode minimal --dist-os alpine --infra sing-box
也可以跳过已有环节,直接复用上次的产物:
sudo bash local-build.sh --skip-kernel --skip-rootfs \
--rootfs-file ./alpine-sing-box-aarch64-rootfs.tar.xz
8.3 密钥注入
root 密码、SSH 密钥、Tailscale/Headscale 认证信息都通过环境变量注入,构建完烧录就能联网。密钥不进版本库,临时文件构建完也会清掉。
九、踩过的坑
1. 改 IP 要联动三个文件
最开始 LAN IP 硬编码在网络接口、DHCP、防火墙三个文件里,改一次漏一次。后来收敛到 network.env + 占位符替换,构建结束再检查残留,问题才算根治。
2. 内核裁剪会被“偷偷恢复”
make olddefconfig 会按依赖关系把关掉的选项拉回来,尤其是 iptables 兼容层。办法是关掉根因选项(比如 BRIDGE_NETFILTER)、直接改 .config,最后靠红线检查兜底。
3. 服务启动顺序就是安全策略
防火墙必须在任何网络服务之前加载,不然每次重启都有裸奔窗口。顺序直接写死在构建脚本里。
4. 跨架构构建的坑
在 x86 主机上构建 aarch64 rootfs 需要 qemu-user-static 和带 F flag 的 binfmt 注册,否则 chroot 里跑不了 ARM64 程序。构建脚本会预先检测并给出提示。
5. 镜像必须校验
“能构建出来”和“能启动”是两回事。校验脚本查分区、U-Boot magic、引导参数、内核格式、服务自启,把问题留在构建机,而不是用户的 TF 卡里。
十、另一个值得关注的方向:Landscape
上面这套组合(dnsmasq + nftables + sing-box + tailscale)是把现成的通用组件一个个拼起来,每个组件负责一件事。如果你不想自己拼,也可以关注 Landscape Router——一个基于 Rust 和 eBPF 的路由系统,可以直接安装到通用 Linux 发行版上。
它和 sing-box 体系的区别在于一体化:DNS、DHCP、分流引擎、虚拟组网、隧道都是它自带的能力,需要什么通过插件系统扩展,不用再各自维护 dnsmasq、sing-box、tailscale、cloudflared 这四套配置。数据面走 eBPF,在高并发转发场景下比纯用户态方案更有优势。
十一、结语
从一块开发板开始,裁剪内核、构建 rootfs、组装镜像、配置防火墙和代理,最后得到一台完全自己控制的 Linux 路由器。整个过程不算多高深,但每一层都得想清楚:内核管硬件能力,rootfs 管系统形态,镜像组装管交付,运行配置管实际体验。
对我来说最大的收获不是省了台路由器,而是这台路由器里每个环节都可解释、可复现、可修改。Linux 的好处就在这:没什么是必须当黑盒接受的。
如果你也有一块闲置的 ARM 开发板 / x86 主机,不妨试试。
参考链接
- Armbian 构建框架:https://github.com/armbian/build
- nanopi-r3s-kernel(R3S 内核裁剪工具链):https://github.com/allenmagic/nanopi-r3s-kernel
- nanopi-r3s-rootfs(多发行版 rootfs 构建):https://github.com/allenmagic/nanopi-r3s-rootfs
- Landscape Router(eBPF 路由系统):https://github.com/ThisSeanZhang/landscape