基于 GitHub Actions 的 ImmortalWrt 固件自动构建系统(当前仅 NanoPi R2S)。架构设计支持未来扩展为多源码、多设备。
| 功能 | 状态 |
|---|---|
| ImmortalWrt + R2S 构建 | ✅ 已验证 |
| 多源码切换(workflow input) | ✅ 架构就绪,仅 ImmortalWrt 已验证 |
| 多设备支持(profile 系统) | ✅ 架构就绪,仅 R2S 已实现 |
| 并行矩阵构建 | |
| dev 推送 → Artifacts | ✅ 已实现 |
| main 每月两次定时 → Artifacts | ✅ 已实现 |
| 仅官方 Actions | ✅ 已实现 |
- 开发分支 (dev): 推送到
profiles/、configs/或 workflow 文件时自动构建,产物保留 14 天 - 主分支 (main): 每月 2、16 号 04:00 HKT 自动构建,产物保留 14 天
- 进入 Actions 页面
- 选择 Dev Build 或 Biweekly Build workflow
- 点击 "Run workflow",可选指定设备 profile
构建完成后,在 Actions 页面对应的 workflow run 中下载 Artifacts(包含固件镜像、sha256sums、config.buildinfo 和 manifest)。
镜像刻意不包含 UU 插件、UU/OpenClash 共存补丁、Tailscale 登录态等运行时内容。刷机后需要补什么、 哪些会自动延续,见 RUNTIME-CHECKLIST.md(分“保留配置升级”与“全新刷入”两种场景)。
RUNTIME-CHECKLIST.md # 刷机后运行时手动清单(UU/OpenClash 共存补丁、Tailscale 认证、ddnsto)
configs/
immortalwrt/ # 按固件源码分目录 (build.yml 按 source_name 读取对应子目录)
packages.conf # ImmortalWrt 共享插件清单 (基础镜像模式:未注释=生效,注释=暂缓待验证)
profiles/
r2s/ # NanoPi R2S
config # 硬件配置 (target, 分区, USB 网卡驱动)
files/ # 自定义固件文件 (开机自动应用)
etc/
hotplug.d/iface/
98-gro-forwarding # ifup 后应用 Tailscale 官方 UDP GRO 转发优化($DEVICE 过滤,依赖 ethtool 包)
99-rps-tune # ifup 后重应用 RPS 散核(防御运行时改写)
init.d/
rps-tune # 收包软中断 CPU0 → CPU1-3 散核 + RFS 流表
tailscale-tune # START=99:按 network.lan 动态推导子网并 tailscale set 广播
sysctl.d/
99-tune.conf # conntrack 32万/TCP 缓冲 32MB/软中断配额翻倍
uci-defaults/
99-custom-lan-ip # 首启设 LAN 192.168.10.1 (避开上级路由 192.168.1.x)
99-tailscale-firewall # fw4 tailscale0 专用 zone + LAN 转发 + LuCI 放行 + OpenClash CGNAT 绕过
.github/workflows/
build.yml # 可复用构建工作流 (核心引擎,仅官方 actions,零外部脚本)
dev-build.yml # dev 分支触发器
biweekly-build.yml # main 分支每月两次定时触发 (2、16 号 04:00 HKT)
基础镜像模式:configs/immortalwrt/packages.conf 中未注释的行才会编入固件,注释行为暂缓启用的候选插件(先在测试机验证,满意后取消注释并推 dev 即可启用,构建逻辑自动过滤 # 行)。除 ddnsto 外均为 ImmortalWrt 官方 feed 自带;第三方源由 build.yml Feeds 阶段按需配置——仅当 packages.conf 中对应插件未注释(=y)时才添加对应 feed。当前 ddnsto 处于暂缓注释状态,构建不拉取其 feed(linkease/nas-packages);tailscale 的 LuCI 界面包(luci-app-tailscale-community)同理按需拉取,tailscale 后端本身来自官方 feed。
| 项 | 说明 |
|---|---|
| luci-app-openclash | 科学上网代理客户端 (Clash.Meta 内核) |
| tailscale | Tailscale 异地组网后端(已在路由器实测:子网路由 + GRO 转发优化;官方 feed) |
| ethtool | GRO 优化的热插拔脚本依赖(98-gro-forwarding) |
| luci-theme-argon | Argon 现代主题 |
| luci-app-argon-config (+zh-cn i18n) | Argon 主题设置(含中文语言包) |
| luci-app-ttyd (+zh-cn i18n) | 网页终端(LuCI 内开 shell,浏览器应急入口) |
| bash / curl / ip-full / unzip / ruby 全家 | OpenClash 运行时依赖(含 YJIT) |
| zram-swap | 1GB 内存防 OOM 兑底 |
| 206 个网络类 kmod | netfilter/ipt/nft 全家、crypto、隧道、cake/bbr、oaf —— 运行时装 kmod 零阻力 |
| nano | 友好文本编辑器 |
| htop | 交互式进程监控 |
| mtr-nojson | 路由追踪(轻量版) |
| tcpdump | 网络抓包(断网诊断刚需) |
| iperf3 | 内网测速 |
除 ttyd 为后续增补外,其余与本地调试版
openclash-24.10.6-r2s的 249 行增量严格对齐(逐行对账零差异)。
| 项 | 暂缓原因 |
|---|---|
| luci-app-tailscale-community (+zh-cn i18n) | LuCI 图形面板,未真机验证(线上仅 CLI);真机验证后取消注释启用,第三方 feed 由 build.yml 联动自动拉取 |
| luci-app-smartdns | DNS 加速,待试验田验证 |
| luci-app-adblock | 与 openclash reject 规则重叠,待验证 |
| luci-app-attendedsysupgrade | 仅适用官方 ASU 服务器,自编译固件用不上 |
| luci-app-ramfree | Linux 内存管理自足,收益存疑 |
| luci-app-watchcat | 日志实证 5 天零重启,待验证 |
| luci-app-autoreboot | 与 watchcat 功能重叠 |
| luci-app-netdata | 实时监控,待验证 |
| luci-app-nlbwmon | 流量记账,待验证 |
| luci-app-upnp | 日志显示仅失效订阅刷屏,场景存疑 |
| luci-app-irqbalance | 双核收益边际 |
| luci-app-arpbind | 内网无 ARP 欺骗史 |
| luci-app-sqm | R2S 跑不动千兆 CAKE,低带宽才考虑 |
| luci-app-appfilter | 家庭管控场景,待验证 |
| luci-app-zerotier | 大陆裸连不稳 |
| luci-app-nps | 需自备 VPS |
| ddnsto + luci-app-ddnsto | 改用 koolcenter 脚本按需安装(每次固件升级后需重跑) |
| luci-app-wol | 无远程开机需求 |
| luci-app-wechatpush | 通知推送,待验证 |
R2S 的 4 核 Cortex-A53 在默认配置下,所有网络中断都由 CPU0 处理。本固件启用多级优化:
- IRQ Affinity (ImmortalWrt 内置):
eth0→CPU1,eth1→CPU2 - RPS/RFS 散核 (
init.d/rps-tune): 收包软中断从 CPU0 散到 CPU1-3,配合 sysctlnet.core.rps_sock_flow_entries=32768按流亲和分发;hotplug.d/iface/99-rps-tune在接口 ifup 后自动重应用,防御运行时改写 - sysctl 调优 (
99-tune.conf): conntrack 32万、TCP 缓冲 32MB、软中断配额翻倍、min_free_kbytes 32MB(参照 unifreq/openwrt_packit 实战值)
- 仅使用官方
actions/*包(checkout、cache、upload-artifact),清理使用 GitHub CLI (gh) - 仅缓存
dl/(源码包)和.ccache(编译缓存),避免工具链缓存与新源码不兼容 - 三级重试: 并行编译 → 单线程 → 详细单线程日志
- 自动清理 Runner 磁盘空间
- 所有构建逻辑内联于
build.yml,零外部脚本依赖 - 构建产物包含
config.buildinfo和manifest,便于审计
以添加 NanoPi R4S 为例:
1. 创建设备配置 profiles/r4s/config
CONFIG_TARGET_rockchip=y
CONFIG_TARGET_rockchip_armv8=y
CONFIG_TARGET_rockchip_armv8_DEVICE_friendlyarm_nanopi-r4s=y
CONFIG_CCACHE=y
CONFIG_CCACHE=y是必选项。其余配置参考对应源码的make menuconfig输出。
2.(可选)添加自定义固件文件
profiles/r4s/files/
etc/uci-defaults/
99-custom-lan-ip # 首次启动自动执行的 uci 脚本(示例名)
3. 第三方软件源(当前无需)
当前 ImmortalWrt 构建的插件全部自带于 ImmortalWrt 官方 feed,无需任何第三方源。若未来某设备/源码确实需要,参考下文“添加第三方软件源”的三种方式,在 build.yml 的 Feeds 阶段添加。
4. 手动触发测试
gh workflow run dev-build.yml --ref dev -f profile=r4s5.(未来)加入矩阵构建
待矩阵构建实现后,在 dev-build.yml / biweekly-build.yml 的 matrix 中添加 r4s 即可自动构建。
build.yml 通过 workflow inputs 实现源码无关设计,无需修改 build.yml 本身。只需在调用时传入不同参数。
手动指定源码触发构建:
# OpenWrt 官方源码
gh workflow run dev-build.yml --ref dev \
-f source_repo_url='https://github.com/openwrt/openwrt.git' \
-f source_branch='v24.10.x' \
-f source_name='openwrt'
# 其他 fork
gh workflow run dev-build.yml --ref dev \
-f source_repo_url='https://github.com/username/custom-openwrt.git' \
-f source_branch='main' \
-f source_name='custom'注意事项:
- 不同源码的默认 feeds 和软件包不同,切换源码时需在
configs/<source_name>/packages.conf提供对应清单(缺失会在构建时报错中止) - 当前 ImmortalWrt 的插件全部自带;其他源码可能需要第三方软件源(在
build.ymlFeeds 阶段按需添加) - 首次使用新源码建议先手动触发测试,确认构建通过后再用于定时构建
第三方软件源配置直接内联于 build.yml 的 Feeds 阶段。当前 ImmortalWrt 构建无需第三方源(全部自带);如未来需要,支持三种方式:
方式一:添加为正式 feed(推荐)
适用于包含多个软件包的源,依赖关系由 feed 系统自动处理:
echo "src-git feedname https://github.com/user/repo.git;branch" >> feeds.conf.default
# 在 feeds install 阶段安装
./scripts/feeds install -f -p feedname package_name方式二:clone 到 package/ 目录
适用于独立的数据文件包或不需要 feed 依赖解析的简单包:
git clone --depth=1 https://github.com/user/repo.git package/repo-name方式三:覆盖已有 feed 中的包
适用于需要用自定义版本替换源码自带包的场景(如 golang 工具链升级):
rm -rf feeds/packages/lang/golang
git clone --depth=1 -b 25.x https://github.com/user/golang.git feeds/packages/lang/golang
./scripts/feeds update -i packages
./scripts/feeds install -f -p packages golang- 默认地址: http://192.168.10.1 或 http://immortalwrt.lan(uci-defaults 首启自动设置,上级网络为 192.168.1.x)
- 分区布局: kernel 16MB + rootfs 512MB(与本地调试版 openclash-24.10.6-r2s 严格对齐)
- 内核模块: 预装 206 个网络类 kmod(netfilter/ipt/nft 全家、crypto、隧道、cake/bbr、oaf),运行时装 kmod 无阻力
- 配套 opkg 源: 每次构建附带
opkg-repo-*artifact(vermagic 精确匹配的 kmod + 软件包仓库),解压后可直接作 opkg feed - 用户名: root
- 密码: 无