配置文件结构:UCI 命令行
在 OpenWrt 的世界里,一切配置最终都落在 /etc/config 目录下的文本文件里。这套体系叫 UCI(Unified Configuration Interface,统一配置接口)。掌握 UCI,意味着你可以脱开网页界面,用命令行精确、批量、可脚本化地管理路由器。本篇把 UCI 的文件格式、命令体系和实战用法讲到位。
UCI 的设计哲学
OpenWrt 之前的路由器固件,配置分散在各个服务自己的配置文件里,格式五花八门。UCI 把它们统一成一种简单格式,所有服务在启动时把 UCI 配置翻译成自己的原生配置。这样做的好处是显而易见的:一套语法、一套工具、一套脚本就能管理整个系统。
一个典型的 UCI 配置文件长这样:
config system
option hostname 'OpenWrt'
option timezone 'CST-8'
config timeserver 'ntp'
list server '0.openwrt.pool.ntp.org'
list server '1.openwrt.pool.ntp.org'
option enabled '1'
语法只有四种元素:config 声明一个段落(section),option 是单值选项,list 是多值列表,段落可以有名字(如 ntp)也可以匿名。所有值用单引号包裹,等号两边不强制空格。这种极简设计是有意为之——让人工读写和程序解析都很轻松。
| 常见配置文件 | 管理内容 |
|---|---|
| /etc/config/network | 网卡、接口、VLAN |
| /etc/config/wireless | 无线 SSID、加密 |
| /etc/config/dhcp | DHCP 分配范围 |
| /etc/config/firewall | 区域、规则、端口转发 |
| /etc/config/system | 主机名、时区、NTP |
命令体系
UCI 的命令行工具只有几个子命令,但组合起来能力很强。
| 命令 | 作用 | 示例 |
|---|---|---|
| uci show | 查看配置(可指定段落) | uci show network |
| uci get | 取单个选项的值 | uci get network.lan.ipaddr |
| uci set | 修改或新增选项 | uci set network.lan.ipaddr=新地址 |
| uci add | 追加匿名段落 | uci add firewall rule |
| uci add_list | 追加列表元素 | uci add_list dhcp.lan.dhcp_option |
| uci delete | 删除选项或段落 | uci delete network.wan6 |
| uci changes | 查看待提交的改动 | uci changes |
| uci commit | 提交改动写入文件 | uci commit network |
理解 UCI 最重要的一个概念是暂存区。uci set 修改的内容先放在内存里,用 uci changes 能看到这些待生效的改动,只有执行 uci commit 之后才真正写入 /etc/config 文件。这给了你一个检查和反悔的机会:改错了且没提交,重启就恢复了;已经提交但没重启服务,配置文件变了但运行中的程序还用旧配置。
修改完之后要让服务重新读取配置,规范做法是调用服务的 init 脚本:
uci set network.lan.ipaddr='192.168.10.1'
uci commit network
/etc/init.d/network restart
也可以用 reload_config 通知所有 procd 管理的服务按需重载。注意改 IP 之后你的 SSH 连接会断,需要用新地址重连,这是新手必经的一个小坑,熟练使用 SSH 客户端 的会话切换就能从容应对。
实战:改一个 LAN 地址
把理论串起来走一遍完整流程。任务是把局域网网段从 192.168.1.x 改成 192.168.10.x。相关配置涉及三处:网卡接口的 IP、DHCP 的分配范围、防火墙规则里的网段引用。按顺序执行:
# 修改 LAN 接口 IP
uci set network.lan.ipaddr='192.168.10.1'
uci set network.lan.netmask='255.255.255.0'
uci commit network
# 同步 DHCP 配置(如使用了非默认池)
uci set dhcp.lan.start='100'
uci set dhcp.lan.limit='150'
uci commit dhcp
# 重启网络与 DHCP 服务
/etc/init.d/network restart
/etc/init.d/dnsmasq restart
执行前先想清楚:改 IP 会立刻断开当前连接,客户端设备也要等 DHCP 租约到期或手动重连才能拿到新地址。生产环境更稳妥的做法是先确认好新网段没有冲突,把上面命令写成一个脚本一次跑完,避免改一半卡在中途。
此外还要检查新网段内没有其它设备占用 .1 这个网关地址,DHCP 分配池也不要和手动设置的静态地址重叠,否则会出现两台设备抢一个 IP 的经典故障,表现是某台设备时通时断,新手很难察觉。
多命令场景还推荐 uci batch 批量执行:
uci batch <<EOF
set network.lan.ipaddr='192.168.10.1'
set network.lan.netmask='255.255.255.0'
commit network
EOF
批量写法既适合人手粘贴,也适合放进自动化脚本,是配置管理的基础组件。关于脚本化运维的更多思路,自动化运维实践 有系统讲解。

取值与匿名段落
uci get 的输出有时候会让人困惑,尤其是返回一行很长内容的情况,那是因为取的是 list 列表选项,所有元素连在一起显示。想逐条取值,可以在键名后用数组下标,比如 uci get network.@timeserver[0].server 之类。这类细节不需要死记,用到时 uci show 看一眼完整结构,照着写就行。
匿名段落(没有名字的 config 段落)的引用方式统一是 @类型名[序号],例如 firewall.@rule[0] 表示第一条规则。新增匿名段最典型的场景是加防火墙规则,流程通常是 uci add firewall rule 添加一个空段落,再用 uci set firewall.@rule[-1].name=xxx 逐项填充,[-1] 代表刚添加的最后一条。这种写法在批量脚本里很常见,读懂它对你后续照着官方文档抄配置会有帮助。
直接改文件行不行
完全可以,UCI 文件本身就是纯文本,vim 之类的编辑器改完保存,再重启对应服务,效果与命令行完全相同。官方文档也说了:手动改要自己承担语法风险,一个标点错误会让整个文件无法解析,而不只是出错的那一段。
两种方式各有适用场合。手动编辑适合大段结构重写、从别处整段移植配置;命令行适合精确改动单点选项、可复制的操作步骤、自动化脚本。日常推荐以命令行为主,出问题容易回溯。任何方式改动之后,都可以用 uci show 段落名 快速验证解析是否正常,如果这条命令报错,说明文件语法已经出问题了。
一个很有用的排障技巧:当某个服务行为异常又找不到原因时,先把当前配置导出留档(uci show > /tmp/backup.txt),再与默认配置逐项对比,往往能发现被遗忘的残留配置。另外,uci show 支持按段落过滤,比如 uci show firewall 只看防火墙部分,配合重定向存文件,和别的设备做配置比对时非常方便。
与 LuCI 的关系
LuCI 界面表单的每一次保存,背后都是一组 uci set 和 uci commit 操作。理解这一点有两个直接好处。第一,网页界面上找不到的高级选项,命令行里都能直接设。第二,写文档或求助时,用 uci show 输出的配置片段比截图更精确,别人一眼就能看懂。
反过来也一样,命令行改过的配置,LuCI 界面会如实显示,两边是同一份数据的两个视图。想系统理解界面与配置的对应关系,可以翻翻 LuCI 应用与常用插件 那部分的说明。

延伸阅读
- 《opkg 包管理与软件源》:环境搭建之后,opkg 与 UCI 是玩转 OpenWrt 的两件基本工具。
- 《防火墙进阶与端口转发》:大量 firewall 段落的实战示例,UCLI 语法的最佳练兵场。
- 《常见故障排查清单》:配置改错导致的服务异常,在速查手册里找快速定位方法。
