opkg 包管理与软件源
刷好 OpenWrt 之后,第一件要做的事往往不是改网络,而是搞清楚怎么往路由器里装软件。OpenWrt 的软件体系围绕着 opkg 这个轻量包管理器运转,理解了它,后面装插件、配服务都会顺理成章。本篇把 opkg 的日常用法、软件源的结构以及常见报错的处理讲清楚,后续所有篇章都会建立在这些基础之上。
opkg 是什么
opkg 全称 Open Package Management,是 OpenWrt 从 Oh/Embeddable Linux 发行版继承下来的轻量级包管理器,思路上和 Debian 的 apt、红帽的 dnf 类似,但体积小得多,适合闪存只有几兆到几十兆的路由器。每个软件包是一个 .ipk 文件,本质是 ar 归档,里面包含程序文件、配置脚本和依赖声明。opkg 的核心能力有四个:从软件源拉取索引、解析依赖关系、执行安装卸载、在 LuCI 界面背后提供底层支持。你在网页管理界面里点的一切安装按钮,最终都会翻译成 opkg 命令。
opkg 的配置集中在 /etc/opkg 目录下,几个关键文件如下表所示。
| 文件 | 作用 | 是否常改 |
|---|---|---|
| opkg.conf | 全局选项,含签名校验开关 | 偶尔 |
| distfeeds.conf | 发行版官方源地址 | 换镜像时改 |
| customfeeds.conf | 用户自定义源 | 加第三方源时改 |
| keys/ | 软件源签名公钥 | 加源时配套放 |
在动手之前,建议先通过 SSH 登录路由器,命令行比网页界面更透明,排错也方便。如果你对命令行操作还不熟悉,可以先读 SSH 远程登录 这一篇补补基础。
常用命令一览
opkg 的命令语法很简短,下面这张表覆盖了九成日常场景。
| 命令 | 含义 | 典型示例 |
|---|---|---|
| opkg update | 更新软件源索引 | opkg update |
| opkg install | 安装某个包 | opkg install tmux |
| opkg remove | 卸载某个包 | opkg remove tmux |
| opkg list | 列出源里全部包 | opkg list |
| opkg list-installed | 列出已安装的包 | opkg list-installed |
| opkg list-upgradable | 列出可升级的包 | opkg list-upgradable |
| opkg find | 精确查找某个包 | opkg find luci-app-ddns |
| opkg info | 查看包的依赖与描述 | opkg info sqm-scripts |
| opkg upgrade | 升级指定包 | opkg upgrade sqm-scripts |
这里有一个几乎人人都会问的问题:能不能像 apt upgrade 那样一键升级所有软件?答案是可以,但不建议无脑执行。规范写法是先看清单,再决定升哪些:
opkg update
opkg list-upgradable | cut -f 1 -d ' ' | xargs -r opkg upgrade
路由器不是服务器,核心包(比如 dnsmasq、防火墙组件、内核模块)升级失败可能导致断网甚至无法启动。比较稳妥的做法是只升级应用类插件,内核相关的 kmod-* 包除非确认版本匹配,否则不要随意动。升级前最好备份配置,相关内容可以参考 系统备份与恢复。
另外提一句查询技巧:opkg list 的输出非常长,直接看会刷屏,配合管道过滤更高效,例如 opkg list | grep -i upnp。如果你想确认某个软件包依赖哪些库,opkg info 包名 会完整列出 Depends 字段,这对后面排查依赖冲突非常有用。
软件源的结构与切换
opkg 的软件源是分目录组织的。以官方 23.05 稳定版为例,源地址分为 targets(平台相关固件包)、packages(通用软件)、luci(网页界面插件)、base(基础库)等几大类,每个大类下再按 CPU 架构细分。你的路由器是什么架构,决定了应该用哪个目录。查询本机架构的命令是:
opkg print-architecture
ubus call system board
前者列出 opkg 支持的架构名,后者会返回主板、发行版、内核版本等完整信息,排错时经常需要把这段输出发给别人看。
默认的 distfeeds.conf 指向 downloads.openwrt.org 官方服务器,国内访问速度不太稳定,表现为 opkg update 卡住或超时。解决办法是替换为镜像站,比如清华大学和南京大学都提供 OpenWrt 官方源的完整镜像。替换方法是把 distfeeds.conf 里的官方域名改成镜像域名,路径保持不变。改完执行 opkg update 验证,只要不再报超时就算成功。具体的镜像目录结构属于网络基础知识,想深入了解可以看 网络分层与域名解析。

动手:添加一个第三方软件源
有时候你想装的插件官方源里没有,就需要添加第三方源。规范流程分三步:放签名公钥、写源地址、更新并安装。以添加一个第三方源为例:
# 第一步:把源的 usign 公钥放到 keys 目录,文件名必须小写
echo 'untrusted comment: OpenWrt usign key of example repo
RWR//HUXxMwMVnx7fESOKO7x8XoW4/dRidJPjt91hAAU2L59mYvHy0Fa' > /etc/opkg/keys/7ffc7517c4cc0c56
# 第二步:在 customfeeds.conf 里写源地址
echo 'src/gz example_packages https://example.com/releases/23.05.3/packages/x86_64/packages' >> /etc/opkg/customfeeds.conf
# 第三步:更新索引并安装
opkg update
opkg install luci-app-example
如果第三方源没有签名或者签名校验失败,又确实信任这个源,可以注释掉 opkg.conf 里的 option check_signature 行来跳过校验。但这会降低安全性,只建议在确认来源可靠的前提下临时使用。
安装完成后有两件收尾的事:一是看 LuCI 界面有没有多出对应菜单,很多插件需要刷新页面甚至重新登录才出现;二是确认磁盘空间,opkg install 前可以用 df -h 看一下 /overlay 剩余容量,闪存小的设备装几个大插件就满了。至于空间不够怎么办,一种办法是卸载用不上的预装语言包和输入法组件,另一种更彻底的办法是自编译固件把插件直接打包进去,这会在后面的篇章讲到。

常见报错与处理
用 opkg 最怕的不是装不上,而是看不懂报错。下面这张表收集了最高频的几种情况。
| 报错信息 | 含义 | 处理思路 |
|---|---|---|
| wget: server returned error | 源地址不通或超时 | 换镜像源,检查网络 |
| Signature check failed | 签名校验失败 | 补公钥或临时关校验 |
| Cannot satisfy dependencies | 依赖无法满足 | 对应内核版本不匹配 |
| Package size mismatch | 索引与实际文件不一致 | 重新 opkg update |
| Cannot find package | 源里没有这个包 | 换源或手动安装 ipk |
其中最经典的是依赖不满足,尤其是带 kmod 前缀的内核模块。出现这类问题先别急着用强制参数,具体分析过程放在《依赖冲突的处理》一篇专门讲,这里先给一个判断方向:用户态软件(比如某个文本编辑器)依赖差一点也许能强行装上运行,内核模块则不同,内核版本对不上几乎必然无法加载,只能找版本完全匹配的包。
再补充一个容易被忽视的细节:opkg 的索引文件存在内存的 /tmp/usr/lib/opkg 目录下,路由器重启后会清空,所以每次开机后第一次装软件都需要重新执行 opkg update。这不是 bug 而是刻意设计,为的是给闪存省空间。理解了这一点,你就能解释为什么刚重启的路由器急着装包会提示找不到包。同理,如果你发现 opkg list 输出为空,八成也是索引还没拉取的原因,跑一次 update 就好。固件内置软件包的安装信息则记录在 /usr/lib/opkg/status 文件里,这个是持久化的,开机即可查询。

延伸阅读
- 《依赖冲突的处理》:专讲 Cannot satisfy dependencies 之类报错的诊断与安全处理。
- 《LuCI 应用与常用插件》:装好 opkg 之后该装哪些插件、怎么选,看这一篇。
- 《SSH 密钥登录》:命令行操作路由器的前提,顺带把密码登录换成更安全的密钥方式。
