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 验证,只要不再报超时就算成功。具体的镜像目录结构属于网络基础知识,想深入了解可以看 网络分层与域名解析。

opkg 安装软件的完整流程

动手:添加一个第三方软件源

有时候你想装的插件官方源里没有,就需要添加第三方源。规范流程分三步:放签名公钥、写源地址、更新并安装。以添加一个第三方源为例:

# 第一步:把源的 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 密钥登录》:命令行操作路由器的前提,顺带把密码登录换成更安全的密钥方式。