金亚洲技术笔记

凡是过往,皆为序章。

OrangePi Zero2安装OpenWRT做旁路由

Posted on   » linux • 2869 words • 6 minute read

买了很多开发板,除了Raspberry Pi 5每天都在用,其他板子:Raspberry Pi Zero W、Raspberry Pi Pico、OrangePi Zero2、ESP32、ESP8266、microbit、合宙Air101都在吃灰。Raspberry Pi Zero W不支持64位,可玩性低,也就OrangePi Zero2还凑合,打算装个OpenWRT做旁路由实现:解锁网*云音乐+广告过滤。

准备工作

  1. 准备一个可以连接互联网的路由器作为主路由,IP:192.168.2.1
  2. ~~Orange Pi官网下载OpenWRT镜像:Orange Pi Zero2,~~Orange Pi官方使用的镜像名为openwrt-aarch64-opizero2-23.12-linux6.1.62-ext4.img,经测试官方更新包地址已失效,无法更新系统。所以到OpenWRT官网下载,然后用rufus烧录;
  3. 主路由WAN口通过交换机,连接互联网;
  4. Orange Pi作为旁路由网口连接主路由LAN口;

Orange Pi官网镜像配置

此步可以跳过,因为官网镜像无法更新系统,可玩性低。

  1. OpenWRT会占用主路由IP,打开http://192.168.2.1登录 OpenWrt → 网络 → 接口 → LAN → 编辑 → 常规设置,修改旁路由的IP地址和网关,把IP改为192.168.2.3,把网关改为主路由IP地址,以接入互联网。

image-20251010154925101

  1. DHCP 服务器 → 常规设置关闭旁路由IPV4和IPV6的DHCP。

image-20251010155559339

image-20251010160231556

  1. 高级设置中修改DNS服务器。

image-20251010155424352

测试配置效果,网关设置成功,可以访问互联网:

image-20251010165209641

查看固件版本:

root@OpenWrt:~# cat /etc/openwrt_release
DISTRIB_ID='OpenWrt'
DISTRIB_RELEASE='SNAPSHOT'
DISTRIB_REVISION='r0+24458-1f701cc1dd'
DISTRIB_TARGET='sunxi/cortexa53'
DISTRIB_ARCH='aarch64_cortex-a53'
DISTRIB_DESCRIPTION='OpenWrt SNAPSHOT r0+24458-1f701cc1dd'
DISTRIB_TAINTS='no-all'

OpenWRT官网镜像配置

OpenWrt Firmware Selector下载镜像前,点击自定义预安装软件包和/或首次启动脚本做以下配置:

预安装的软件包

base-files busybox ca-bundle dropbear e2fsprogs firewall4 fstools kmod-nft-offload libc libgcc libopenssl openssl-util libustream-openssl logd mkf2fs mtd netifd nftables odhcp6c odhcpd-ipv6only partx-utils ppp ppp-mod-pppoe procd procd-seccomp procd-ujail uboot-envtools uci uclient-fetch urandom-seed urngd coreutils-nohup bash dnsmasq-full curl ca-certificates ipset ip-full libcap libcap-bin ruby ruby-yaml kmod-tun kmod-inet-diag unzip kmod-nft-tproxy luci-compat luci luci-base openssh-sftp-server fdisk losetup resize2fs kmod-fs-ext4 mount-utils parted kmod-nft-socket luci-i18n-base-zh-cn libatomic1 libev libsodium libpcre2 libudns kmod-netlink-diag libstdcpp6 boost boost-system boost-program_options coreutils-base64 libuci-lua resolveip aria2 luci-app-aria2 luci-i18n-aria2-zh-cn luci-app-samba4 opkg mosquitto-client git make build-essential

首次启动时运行的脚本(uci-defaults)

以下脚本只支持有线接入,不支持PPPOE拨号和WLAN无线接入。

root_password改为OpenWRT系统root密码;

lan_ip_address改为旁路由应设置的IP地址;

network.lan.gateway改为主路由的IP地址;

network.lan.dns改为公网DNS解析地址

root_password="123456"
lan_ip_address="192.168.2.2"

# log potential errors
exec >/tmp/setup.log 2>&1

if [ -n "$root_password" ]; then
  (echo "$root_password"; sleep 1; echo "$root_password") | passwd > /dev/null
fi

# Configure LAN
# More options: https://openwrt.org/docs/guide-user/base-system/basic-networking
if [ -n "$lan_ip_address" ]; then
  uci set network.lan.ipaddr="$lan_ip_address"
  uci set network.lan.gateway="192.168.2.1"
  uci set dhcp.lan.ignore="1"
  uci set network.lan.dns="114.114.114.114 199.29.29.29 223.5.5.5"
  uci commit network
fi

cat << "EOF" > /etc/uci-defaults/70-rootpt-resize
if [ ! -e /etc/rootpt-resize ] \
&& type parted > /dev/null \
&& lock -n /var/lock/root-resize
then
ROOT_BLK="$(readlink -f /sys/dev/block/"$(awk -e \
'$9=="/dev/root"{print $3}' /proc/self/mountinfo)")"
ROOT_DISK="/dev/$(basename "${ROOT_BLK%/*}")"
ROOT_PART="${ROOT_BLK##*[^0-9]}"
parted -f -s "${ROOT_DISK}" \
resizepart "${ROOT_PART}" 100%
mount_root done
touch /etc/rootpt-resize
reboot
fi
exit 1
EOF
cat << "EOF" > /etc/uci-defaults/80-rootfs-resize
if [ ! -e /etc/rootfs-resize ] \
&& [ -e /etc/rootpt-resize ] \
&& type losetup > /dev/null \
&& type resize2fs > /dev/null \
&& lock -n /var/lock/root-resize
then
ROOT_BLK="$(readlink -f /sys/dev/block/"$(awk -e \
'$9=="/dev/root"{print $3}' /proc/self/mountinfo)")"
ROOT_DEV="/dev/${ROOT_BLK##*/}"
LOOP_DEV="$(awk -e '$5=="/overlay"{print $9}' \
/proc/self/mountinfo)"
if [ -z "${LOOP_DEV}" ]
then
LOOP_DEV="$(losetup -f)"
losetup "${LOOP_DEV}" "${ROOT_DEV}"
fi
resize2fs -f "${LOOP_DEV}"
mount_root done
touch /etc/rootfs-resize
reboot
fi
exit 1
EOF
cat << "EOF" >> /etc/sysupgrade.conf
/etc/uci-defaults/70-rootpt-resize
/etc/uci-defaults/80-rootfs-resize
EOF

sh /etc/uci-defaults/70-rootpt-resize

echo "All done!"

点击请求构建,半分钟左右构建成功。

image-20251011095932934

烧录镜像后,关闭旁路由IPV4和IPV6的DHCP。。


更换国内源

cp /etc/opkg/distfeeds.conf /etc/opkg/distfeeds.conf.backup

vim /etc/opkg/distfeeds.conf

src/gz openwrt_core https://mirrors.tuna.tsinghua.edu.cn/openwrt/releases/24.10.3/targets/x86/64/packages
src/gz openwrt_base https://mirrors.tuna.tsinghua.edu.cn/openwrt/releases/24.10.3/packages/x86_64/base
src/gz openwrt_luci https://mirrors.tuna.tsinghua.edu.cn/openwrt/releases/24.10.3/packages/x86_64/luci
src/gz openwrt_packages https://mirrors.tuna.tsinghua.edu.cn/openwrt/releases/24.10.3/packages/x86_64/packages
src/gz openwrt_routing https://mirrors.tuna.tsinghua.edu.cn/openwrt/releases/24.10.3/packages/x86_64/routing
src/gz openwrt_telephony https://mirrors.tuna.tsinghua.edu.cn/openwrt/releases/24.10.3/packages/x86_64/telephony

opkg update

# 验证更换是否成功
opkg install luci

旁路由作为MQTT Client

LuCI 为OpenWRT增加菜单:/usr/lib/lua/luci/controller/mqttclient.lua

module("luci.controller.mqttclient", package.seeall)

function index()
    entry({"admin", "services", "mqttclient"}, cbi("mqttclient"), _("MQTT Client"), 90).dependent = true
end

MQTT Client页面:/usr/lib/lua/luci/model/cbi/mqttclient.lua

local m, s, o
local sys = require "luci.sys"

-- 日志函数(记录到同一个日志文件)
local function log(message)
    local f = io.open("/var/log/mqttclient.log", "a")
    if f then
        f:write(string.format("[%s] %s\n", os.date("%Y-%m-%d %H:%M:%S"), message))
        f:close()
    end
end

m = Map("mqttclient", translate("MQTT Client"),
    translate("Configure MQTT client settings and control connection."))

-- === Broker Settings ===
s = m:section(TypedSection, "mqttclient", translate("Broker Settings"))
s.anonymous = true

o = s:option(Value, "broker_host", translate("Broker Host"))
o.placeholder = "127.0.0.1"
o.default = "127.0.0.1"
o.rmempty = false

o = s:option(Value, "broker_port", translate("Broker Port"))
o.placeholder = "1883"
o.default = "1883"
o.datatype = "port"
o.rmempty = false

o = s:option(Value, "username", translate("Username"))
o.rmempty = true

o = s:option(Value, "password", translate("Password"))
o.password = true
o.rmempty = true

o = s:option(Value, "client_id", translate("Client ID"))
o.placeholder = "openwrt-client"
o.default = "openwrt-client"
o.rmempty = false

-- === Connection Control ===
s = m:section(TypedSection, "mqttclient", translate("Connection Control"))
s.anonymous = true

o = s:option(Button, "_connect", translate("Connect"))
o.inputstyle = "apply"
function o.write(self, section)
    log("User pressed Connect button from web interface")
    -- 调用 init 脚本并把输出追加到日志
    sys.call("/etc/init.d/mqttclient connect >> /var/log/mqttclient.log 2>&1")
end

o = s:option(Button, "_disconnect", translate("Disconnect"))
o.inputstyle = "reset"
function o.write(self, section)
    log("User pressed Disconnect button from web interface")
    sys.call("/etc/init.d/mqttclient disconnect >> /var/log/mqttclient.log 2>&1")
end

-- === Publish Message ===
s = m:section(TypedSection, "mqttclient", translate("Publish Message"))
s.anonymous = true

o = s:option(Value, "pub_topic", translate("Topic"))
o.placeholder = "test/topic"
o.rmempty = false

o = s:option(Value, "pub_message", translate("Message"))
o.placeholder = "Hello, MQTT!"
o.rmempty = false

o = s:option(Button, "_publish", translate("Publish"))
o.inputstyle = "action"
function o.write(self, section)
    local topic = m.uci:get("mqttclient", section, "pub_topic") or ""
    local message = m.uci:get("mqttclient", section, "pub_message") or ""
    log("User pressed Publish button. Topic: " .. topic .. ", Message: " .. message)
    -- 调用 init 脚本发布消息,同时输出到日志
    sys.call(string.format(
        "/etc/init.d/mqttclient publish '%s' '%s' >> /var/log/mqttclient.log 2>&1",
        topic:gsub("'", "'\\''"),
        message:gsub("'", "'\\''")
    ))
end

return m

UCI配置文件:/etc/config/mqttclient

config mqttclient
        option broker_host '10.0.0.1'
        option broker_port '1883'
        option username 'mqtt-username'
        option password 'mqtt-password'
        option client_id 'openwrt-client'
        option pub_topic 'data/test'
        option pub_message 'Hello, MQTT.'

后端服务脚本:/etc/init.d/mqttclient

#!/bin/sh /etc/rc.common

START=99
STOP=10
LOG_FILE="/var/log/mqttclient.log"

EXTRA_COMMANDS="connect disconnect publish config"
EXTRA_HELP="        connect      Connect to MQTT broker
        disconnect   Disconnect from MQTT broker
        publish      Publish a message to a topic
        config       Show current MQTT client configuration"

USE_PROCD=1

log() {
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" >> "$LOG_FILE"
}

command_exists() {
    command -v "$1" >/dev/null 2>&1
}

uci_get() {
    uci get "mqttclient.@mqttclient[0].$1" 2>/dev/null
}

start_service() {
    if ! command_exists /usr/bin/mosquitto_sub; then
        log "Error: mosquitto_sub not found. Please install mosquitto-client."
        return 1
    fi

    local host=$(uci_get broker_host)
    local port=$(uci_get broker_port)
    local user=$(uci_get username)
    local pass=$(uci_get password)
    local client_id=$(uci_get client_id)

    log "Starting MQTT client: host=$host, port=$port, client_id=$client_id"

    procd_open_instance
    procd_set_param command /usr/bin/mosquitto_sub
    procd_append_param command -h "$host"
    procd_append_param command -p "$port"
    [ -n "$user" ] && procd_append_param command -u "$user"
    [ -n "$pass" ] && procd_append_param command -P "$pass"
    procd_append_param command -i "$client_id"
    procd_append_param command -t "#"
    procd_set_param respawn
    procd_set_param stdout "$LOG_FILE"
    procd_set_param stderr "$LOG_FILE"
    procd_close_instance
}

stop_service() {
    log "Stopping MQTT client"
    killall mosquitto_sub 2>/dev/null
}

connect() {
    log "Connect button pressed"
    start
}

disconnect() {
    log "Disconnect button pressed"
    stop
}

publish() {
    local topic="$1"
    local message="$2"

    if ! command_exists /usr/bin/mosquitto_pub; then
        log "Error: mosquitto_pub not found. Please install mosquitto-client."
        return 1
    fi

    local host=$(uci_get broker_host)
    local port=$(uci_get broker_port)
    local user=$(uci_get username)
    local pass=$(uci_get password)
    local client_id=$(uci_get client_id)

    log "Publishing to topic: $topic"

    if /usr/bin/mosquitto_pub -h "$host" -p "$port" \
       ${user:+-u "$user"} ${pass:+-P "$pass"} \
       -i "$client_id" -t "$topic" -m "$message" >> "$LOG_FILE" 2>&1; then
        log "Successfully published to $topic"
    else
        log "Failed to publish to $topic"
    fi
}

config() {
    log "=== Dumping MQTT client configuration ==="
    log "broker_host=$(uci_get broker_host)"
    log "broker_port=$(uci_get broker_port)"
    log "username=$(uci_get username)"
    log "password=******"
    log "client_id=$(uci_get client_id)"
    log "pub_topic=$(uci_get pub_topic)"
    log "pub_message=$(uci_get pub_message)"
    log "=========================================="
}

boot() {
    start
}

# 添加执行权限
chmod +x /etc/init.d/mqttclient

# 启动服务
/etc/init.d/mqttclient enable
/etc/init.d/mqttclient restart

# 调试配置读取
/etc/init.d/mqttclient config
# 测试发布消息
/etc/init.d/mqttclient publish "data/test1" "Hello from OpenWrt"
# 查看测试日志
tail -f /var/log/mqttclient.log


测试通过:

image-20251016100713549

稍微改改代码,定时上传心跳,监控设备是否离线。

安装.Net8环境

# 使用Arm64 Alpine
wget https://builds.dotnet.microsoft.com/dotnet/aspnetcore/Runtime/8.0.20/aspnetcore-runtime-8.0.20-linux-musl-arm64.tar.gz\

./dotnet --info
Host:
  Version:      8.0.20
  Architecture: arm64
  Commit:       574100b692
  RID:          linux-musl-arm64

开发测试环境备用。


解锁网*云音乐

本来想安装UnblockNeteaseMusic,后来发现了更好用的YesPlayMusic客户端,所以不再折腾。


安装拦截广告应用AdGuardhome

系统 → SoftWare,在过滤器中输入adguardhome,点击Install安装。


cd /usr/bin/
https://github.com/AdguardTeam/AdGuardHome/releases/download/v0.107.67/AdGuardHome_linux_arm64.tar.gz
tar -zxvf AdGuardHome_linux_arm64.tar.gz

touch /etc/AdGuardHome.yaml
cd /usr/bin/AdGuardHome && ./AdGuardHome

image-20251016091616940


进入WEB管理页:http://192.168.2.2:3000

image-20251016091846367


设置上游DNS

设置 -> DNS设置,上游 DNS 服务器,请求方式改为并行请求

doh.360.cn/dns-query

dns.alidns.com/dns-query

应用后配置文件保存在/usr/bin/AdGuardHome/AdGuardHome.yaml

停止进程./AdGuardHome,删除/etc/AdGuardHome.yaml


安装OpenWRT AdGuardhome管理

下载luci-app-adguardhome

cd /opt/
wget https://github.com/rufengsuixing/luci-app-adguardhome/releases/download/1.8-9/luci-app-adguardhome_1.8-9_all.ipk
opkg install luci-app-adguardhome_1.8-9_all.ipk

配置OpenWRT AdGuardhome参数

重启设备,之后进入服务 -> AdGuard Home

启用:选中

网页管理端口:81

重定向:作为dnsmasq的上游服务器

配置文件路径:/usr/bin/AdGuardHome/AdGuardHome.yaml

保存并应用之后进入网络 -> DHCP/DNS,发现DNS已经转发到AdGuardhome。


image-20251016095411618


在主路由上设置DNS为旁路由IP地址。

image-20251017105045648


随机访问几个网站,已经存在拦截数据。

image-20251017105213770

ps:测试中发现重启旁路由后,AdGuardhome并不会自动拉起进程,需要手动到AdGuardHome菜单应用一下才可以启动进程。


参考文章:

为Orange Pi Zero 2编译最新openwrt - 知乎

【个人笔记】【openwrt篇】AdGuardHome安装及配置_adguardhome设置教程-CSDN博客

×