Skip to content

OpenWrt 最佳实践

工业网关配置规范

网络分区设计

工业场景下,IT 网络与 OT 网络必须严格隔离:

┌──────────────────────────────────────────────────┐
│                  OpenWrt 网关                     │
│                                                  │
│  eth0 (WAN) ──── 企业 IT 网络 / 4G/5G 上行       │
│  eth1 (LAN1) ─── OT 设备网络 (192.168.10.0/24)  │
│  eth2 (LAN2) ─── 管理网络 (192.168.20.0/24)     │
│  wlan0 ────────── 禁用或仅管理用途               │
└──────────────────────────────────────────────────┘
bash
# 配置 OT 隔离网络
uci batch <<'EOF'
set network.ot=interface
set network.ot.ifname='eth1'
set network.ot.proto='static'
set network.ot.ipaddr='192.168.10.1'
set network.ot.netmask='255.255.255.0'

set network.mgmt=interface
set network.mgmt.ifname='eth2'
set network.mgmt.proto='static'
set network.mgmt.ipaddr='192.168.20.1'
set network.mgmt.netmask='255.255.255.0'
commit network
EOF

# 防火墙:OT 区域只允许特定端口出站
uci batch <<'EOF'
add firewall zone
set firewall.@zone[-1].name='ot'
set firewall.@zone[-1].network='ot'
set firewall.@zone[-1].input='DROP'
set firewall.@zone[-1].output='ACCEPT'
set firewall.@zone[-1].forward='DROP'

add firewall rule
set firewall.@rule[-1].name='Allow-OT-Modbus'
set firewall.@rule[-1].src='ot'
set firewall.@rule[-1].dest_port='502'
set firewall.@rule[-1].proto='tcp'
set firewall.@rule[-1].target='ACCEPT'
commit firewall
EOF

串口配置(RS485/RS232)

bash
# 查看串口设备
ls /dev/ttyS* /dev/ttyUSB* /dev/ttyACM*

# 安装串口工具
opkg install kmod-usb-serial kmod-usb-serial-ch341 kmod-usb-serial-ftdi
opkg install minicom

# 配置串口参数(Modbus RTU 典型配置)
stty -F /dev/ttyS1 9600 cs8 -cstopb -parenb raw

# 持久化串口配置(通过 udev 规则)
cat > /etc/udev/rules.d/99-serial.rules <<'EOF'
SUBSYSTEM=="tty", ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6001", SYMLINK+="ttyModbus"
EOF

看门狗配置

工业设备必须启用硬件看门狗,防止系统死锁:

bash
# 安装看门狗守护进程
opkg install watchdog

# 配置
cat > /etc/watchdog.conf <<'EOF'
watchdog-device = /dev/watchdog
watchdog-timeout = 60
interval = 10
realtime = yes
priority = 1
EOF

/etc/init.d/watchdog enable
/etc/init.d/watchdog start

安全加固

SSH 安全配置

bash
# 禁用密码登录,仅允许密钥认证
uci set dropbear.@dropbear[0].PasswordAuth='off'
uci set dropbear.@dropbear[0].RootPasswordAuth='off'
uci set dropbear.@dropbear[0].Port='2222'  # 修改默认端口
uci commit dropbear

# 添加 SSH 公钥
mkdir -p /root/.ssh
cat >> /root/.ssh/authorized_keys <<'EOF'
ssh-ed25519 AAAA... your-key-comment
EOF
chmod 600 /root/.ssh/authorized_keys

/etc/init.d/dropbear restart

防火墙最小权限原则

bash
# 默认拒绝所有入站,只开放必要端口
uci set firewall.@defaults[0].input='DROP'
uci set firewall.@defaults[0].forward='DROP'
uci set firewall.@defaults[0].output='ACCEPT'

# 只允许管理网络访问 SSH 和 Web
uci add firewall rule
uci set firewall.@rule[-1].name='Allow-SSH-Mgmt'
uci set firewall.@rule[-1].src='mgmt'
uci set firewall.@rule[-1].dest_port='2222'
uci set firewall.@rule[-1].proto='tcp'
uci set firewall.@rule[-1].target='ACCEPT'

uci commit firewall
/etc/init.d/firewall restart

禁用不必要服务

bash
# 禁用 telnet(如果存在)
/etc/init.d/telnet disable 2>/dev/null

# 禁用 UPnP
/etc/init.d/miniupnpd disable 2>/dev/null

# 关闭 LuCI(生产环境可选)
/etc/init.d/uhttpd disable

OTA 升级方案

使用 sysupgrade

bash
# 下载新固件并验证
wget -O /tmp/firmware.bin https://your-server/firmware/openwrt-v2.bin
sha256sum /tmp/firmware.bin  # 对比官方校验值

# 保留配置升级(-c 参数)
sysupgrade -c /tmp/firmware.bin

# 不保留配置(全新安装)
sysupgrade -n /tmp/firmware.bin

# 指定保留的配置文件
cat /etc/sysupgrade.conf
# 添加自定义保留路径
echo "/etc/myapp.conf" >> /etc/sysupgrade.conf

双分区 A/B 升级(高可靠性方案)

对于关键工业设备,推荐实现 A/B 分区升级:

bash
#!/bin/sh
# /usr/bin/ota-upgrade.sh

FIRMWARE_URL="$1"
CURRENT_PART=$(cat /proc/cmdline | grep -o 'root=/dev/[^ ]*' | cut -d= -f2)

if [ "$CURRENT_PART" = "/dev/sda2" ]; then
    TARGET_PART="/dev/sda3"
else
    TARGET_PART="/dev/sda2"
fi

echo "当前分区: $CURRENT_PART,升级目标: $TARGET_PART"

# 下载固件到目标分区
wget -O - "$FIRMWARE_URL" | dd of="$TARGET_PART" bs=4M

# 验证写入
WRITTEN_HASH=$(dd if="$TARGET_PART" bs=4M | sha256sum | cut -d' ' -f1)
EXPECTED_HASH=$(wget -qO- "${FIRMWARE_URL}.sha256")

if [ "$WRITTEN_HASH" = "$EXPECTED_HASH" ]; then
    echo "固件验证通过,设置启动分区..."
    # 修改 grub/uboot 启动项
    grub-set-default "$TARGET_PART"
    reboot
else
    echo "固件验证失败,取消升级"
    exit 1
fi

性能优化

网络转发性能

bash
# 启用硬件 NAT 卸载(支持的平台)
echo 1 > /sys/kernel/debug/ecnt/hw_nat_enable

# 调整网络缓冲区
sysctl -w net.core.rmem_max=16777216
sysctl -w net.core.wmem_max=16777216
sysctl -w net.ipv4.tcp_rmem='4096 87380 16777216'
sysctl -w net.ipv4.tcp_wmem='4096 65536 16777216'

# 持久化
cat >> /etc/sysctl.conf <<'EOF'
net.core.rmem_max=16777216
net.core.wmem_max=16777216
net.ipv4.tcp_rmem=4096 87380 16777216
net.ipv4.tcp_wmem=4096 65536 16777216
EOF

串口轮询优化

bash
# 对于高频 Modbus 轮询,调整串口延迟
setserial /dev/ttyS1 low_latency

# 使用 DMA 传输(内核支持时)
# 在设备树中配置 dma-names = "tx", "rx"

日志与监控

集中日志配置

bash
# 配置 syslog 转发到远程服务器
uci set system.@system[0].log_ip='192.168.1.100'
uci set system.@system[0].log_port='514'
uci set system.@system[0].log_proto='udp'
uci set system.@system[0].log_size='256'
uci commit system
/etc/init.d/log restart

自定义监控脚本

bash
#!/bin/sh
# /usr/bin/health-monitor.sh
# 通过 cron 每分钟执行

MQTT_HOST="192.168.1.100"
DEVICE_ID=$(uci get system.@system[0].hostname)

# 采集系统指标
CPU_LOAD=$(cat /proc/loadavg | awk '{print $1}')
MEM_FREE=$(grep MemFree /proc/meminfo | awk '{print $2}')
UPTIME=$(cat /proc/uptime | awk '{print $1}')

# 检查关键进程
MODBUS_STATUS=$(pgrep -x modbus-collector > /dev/null && echo 1 || echo 0)
MQTT_STATUS=$(pgrep -x mosquitto > /dev/null && echo 1 || echo 0)

# 发布到 MQTT
mosquitto_pub -h "$MQTT_HOST" -t "gateway/$DEVICE_ID/health" \
  -m "{\"cpu\":$CPU_LOAD,\"mem_free\":$MEM_FREE,\"uptime\":$UPTIME,\
\"modbus\":$MODBUS_STATUS,\"mqtt\":$MQTT_STATUS}"
bash
# 添加到 cron
echo "* * * * * /usr/bin/health-monitor.sh" >> /etc/crontabs/root
/etc/init.d/cron restart

配置备份与恢复

bash
# 备份所有配置
sysupgrade -b /tmp/backup-$(date +%Y%m%d).tar.gz

# 上传到远程服务器
scp /tmp/backup-*.tar.gz admin@backup-server:/backups/

# 恢复配置
sysupgrade -r /tmp/backup-20240101.tar.gz

# 自动备份脚本(每天凌晨 2 点)
cat >> /etc/crontabs/root <<'EOF'
0 2 * * * sysupgrade -b /tmp/config-backup.tar.gz && \
  scp /tmp/config-backup.tar.gz admin@192.168.1.100:/backups/$(hostname)-$(date +\%Y\%m\%d).tar.gz
EOF

褚成志的IoT笔记