博客已经尘封许久。
这次折腾觉得挺有价值的,即便在AI加持下,还是踩了不少坑。
以下是GPT老师生成。
本文是一次 GL.iNet GL-MT5000(Brume 3)国内版 的实机折腾记录。
最终结果:普通上网、OpenClash、WireGuard、DDNS-GO 均正常使用。本文只针对下述硬件/固件环境验证通过。GL.iNet 后续固件、不同地区版本或不同硬件修订版,文件位置、软件包和行为都可能发生变化,请不要无脑照抄涉及闪存和软件源的操作。
1. 目标
在 不刷原生 OpenWrt、不换掉 GL.iNet 原厂固件 的前提下,让国内版 MT5000 实现:
- OpenClash
- GL.iNet 原厂 WireGuard Server / Client
- DDNS-GO(独立 Web 界面,使用 DNSPod 等自定义 DDNS)
- 保留 GL.iNet 原厂 Web 管理界面
- 额外启用 LuCI
最终结构可以理解为:
GL.iNet 原厂 Web
├── WAN / LAN / DHCP / 系统管理
├── 原厂 WireGuard
└── 其他 GL.iNet 功能
LuCI :8080
└── OpenClash
DDNS-GO :9876
└── DNSPod / 腾讯云等 DDNS
2. 本次实机环境
设备:
GL.iNet GL-MT5000
产品系列:Brume 3
国内版
实机固件环境:
GL.iNet firmware : 4.8.6
OpenWrt : 21.02-SNAPSHOT
Target : mediatek/mt7987
Architecture : aarch64_cortex-a53
Kernel : 5.4.281
Firewall : fw3
iptables : 1.8.7 legacy
fw4 : 不存在
可通过 SSH 检查:
cat /etc/glversion
cat /etc/openwrt_release
uname -a
iptables -V
本机原厂软件源为:
https://fw.gl-inet.cn/releases/v21.02-SNAPSHOT/mt7987a/kmod-5.4.281/aarch64_cortex-a53/kmod
https://fw.gl-inet.cn/releases/v21.02-SNAPSHOT/mt7987a/packages/aarch64_cortex-a53/glinet
https://fw.gl-inet.cn/releases/v21.02-SNAPSHOT/mt7987a/packages/aarch64_cortex-a53/packages
检查:
cat /etc/opkg/distfeeds.conf
3. 先说几个最重要的坑
整个过程真正容易出问题的地方,不是 OpenClash 本身,而是 GL.iNet 固件并不是标准的“原生 OpenWrt 环境”。
3.1 不要直接 opkg install luci
这台机器有 GL.iNet 自己的 LuCI 初始化流程。
我第一次直接:
opkg install luci
虽然软件包装上去了,但 LuCI 最后出现:
Bad Gateway
The process did not produce any response
正确方式是使用原厂脚本:
sh /usr/bin/init_luci.sh web
3.2 不要随便换 OpenWrt 软件源
强烈建议保留 GL.iNet 自己的 mt7987a 软件源。
不要:
换成普通 OpenWrt feed
换 iStoreOS feed
opkg upgrade
--force-depends 强装 kmod
尤其是 kernel module。
即使都叫:
kernel 5.4.281
也不代表 kernel ABI/hash 一定兼容。
3.3 国内版 WireGuard 实际上已经在固件里
本机原厂已经包含:
wireguard-tools
kmod-wireguard
gl-sdk4-wg-client
gl-sdk4-wg-server
gl-sdk4-ui-wgclient
gl-sdk4-ui-wgserver
gl-sdk4-ui-vpndashboard
所以 不需要为了 WireGuard 再安装 luci-proto-wireguard。
真正的问题主要是:
国内版 / 简体中文界面把 VPN 菜单隐藏了
这个后面详细说明。
4. 国内版 CN 改为 US
高风险步骤。先备份。
下面的 offset 只是在我的 GL-MT5000 / 4.8.6 上验证。
不同硬件或固件请先确认,不要直接写入闪存。
本机国家代码位于:
设备:/dev/mmcblk0p2
offset:0x4088
十进制:16520
检查:
hexdump -C -s 0x4080 -n 32 /dev/mmcblk0p2
国内版原值:
43 4e = CN
4.1 先备份相关区域
至少把这一小段原始内容备份出来:
dd if=/dev/mmcblk0p2 \
of=/root/mt5000_region_4080_backup.bin \
bs=1 skip=16512 count=32
确认:
ls -l /root/mt5000_region_4080_backup.bin
hexdump -C /root/mt5000_region_4080_backup.bin
建议立即把备份文件复制到电脑保存。
需要回滚这一段时:
dd if=/root/mt5000_region_4080_backup.bin \
of=/dev/mmcblk0p2 \
bs=1 seek=16512 conv=notrunc
sync
4.2 写入 US
确认设备和 offset 无误后:
printf 'US' | dd \
of=/dev/mmcblk0p2 \
bs=1 seek=16520 conv=notrunc
sync
检查:
hexdump -C -s 0x4080 -n 32 /dev/mmcblk0p2
正常应看到:
55 53 = US
运行时国家代码也可以检查:
cat /proc/gl-hw-info/country_code
本机最终为:
US
我的机器在后续执行恢复出厂后,raw region flag 仍保持 US,但不要假设所有固件都一定如此。
5. 正式切换主路由前:临时 LAN-LAN 联网
这一段很重要。
为了先在 MT5000 上安装 LuCI、OpenClash、Mihomo 和 DDNS-GO,同时暂时不拆原来的主路由,可以让 MT5000 作为同网段设备挂在旧路由后面。
假设原主路由:
192.168.1.1
临时拓扑:
Internet
│
旧主路由 192.168.1.1
│
├── PC
│
└── MT5000 LAN
192.168.1.249
MT5000 LAN 必须保持:
协议:静态地址
IP:192.168.1.249
掩码:255.255.255.0
网关:192.168.1.1
不要把 LAN 改成 DHCP 客户端。
5.1 临时给 MT5000 配网关和 DNS
SSH:
uci set network.lan.gateway='192.168.1.1'
uci -q delete network.lan.dns
uci add_list network.lan.dns='192.168.1.1'
uci add_list network.lan.dns='223.5.5.5'
因为当前 DHCP 应继续由旧主路由提供,所以关闭 MT5000 的 LAN DHCP:
uci set dhcp.lan.ignore='1'
uci commit network
uci commit dhcp
/etc/init.d/network restart
检查:
ip route
正常应有:
default via 192.168.1.1 dev br-lan
测试:
ping -c 3 223.5.5.5
nslookup github.com
如果旧主路由本身使用 OpenClash Fake-IP,nslookup 返回 198.18.x.x 并不一定是异常。
6. 启用 LuCI
首先检查:
ls -l /usr/bin/init_luci.sh
然后执行:
sh /usr/bin/init_luci.sh web
这个脚本可能没有任何输出,只要退出正常即可。
检查:
netstat -lntp 2>/dev/null | grep -E ':8080|:8443'
正常情况下:
8080 → LuCI HTTP
8443 → LuCI HTTPS
例如临时 IP 为 192.168.1.249 时:
http://192.168.1.249:8080/cgi-bin/luci/
GL.iNet 原厂 Web 仍然使用:
80 / 443
也就是:
http://192.168.1.249/
两套界面可以同时存在。
7. OpenClash
本机环境是:
fw3
iptables legacy
所以不是 fw4/nftables 路线。
7.1 先确认底层能力
本机实测原厂环境已经具备:
ip_set
nf_socket_ipv4
nf_socket_ipv6
nf_tproxy_ipv4
nf_tproxy_ipv6
xt_TPROXY
xt_socket
tun
检查:
lsmod | grep -Ei 'tproxy|socket|ip_set|tun'
TPROXY:
iptables -j TPROXY -h
socket:
iptables -m socket -h
TUN:
ls -l /dev/net/tun
7.2 本机已验证的相关软件包
在执行 GL.iNet LuCI 初始化后,本机可以正常看到:
ca-bundle
curl
dnsmasq-full
ip-full
ipset
iptables
iptables-mod-extra
iptables-mod-tproxy
kmod-inet-diag
kmod-tun
kmod-ipt-nat
luci
luci-base
luci-compat
unzip
尤其是:
dnsmasq-full 2.85-16
已经由 GL.iNet 环境正常注册。
可以检查:
opkg status dnsmasq-full
不要看到依赖列表就无脑重装所有 kmod。
7.3 安装缺少的用户态依赖
本机当时缺:
bash
ruby
ruby-yaml
先模拟:
opkg --noaction install bash ruby ruby-yaml
确认不会更换 kernel/kmod 等关键组件后再执行:
opkg install bash ruby ruby-yaml
验证:
bash --version | head -1
ruby --version
ruby -e 'require "yaml"; puts "yaml ok"'
我当时安装后的版本为:
Bash 5.1.16
Ruby 3.0.4
7.4 安装 OpenClash LuCI 插件
我实机成功使用的是:
OpenClash 0.47.156
下载:
curl -L --retry 2 \
https://github.com/vernesong/OpenClash/releases/download/v0.47.156/luci-app-openclash_0.47.156_all.ipk \
-o /tmp/openclash.ipk
先模拟:
opkg --noaction install /tmp/openclash.ipk
确认不会异常替换 kernel、kmod、dnsmasq、iptables 等关键组件后:
opkg install /tmp/openclash.ipk
验证:
opkg status luci-app-openclash | grep -E '^(Package|Version|Status):'
ls -l /etc/init.d/openclash
如果 LuCI 的:
服务
菜单里暂时没看到 OpenClash,先:
rm -rf /tmp/luci-indexcache /tmp/luci-modulecache
/etc/init.d/uhttpd restart
然后退出 LuCI 重新登录。
8. 安装 Mihomo / Meta Core
进入:
LuCI
→ 服务
→ OpenClash
→ 插件设置
→ 版本更新
安装:
Meta Core / Mihomo Core
MT5000 架构是:
arm64 / aarch64
安装完成后检查:
ls -lah /etc/openclash/core/
应有:
clash_meta
验证:
/etc/openclash/core/clash_meta -v
必须看到类似:
linux arm64
我当时安装成功的核心显示:
Mihomo Meta
linux arm64
with_gvisor
8.1 一个迁移旧 OpenClash 配置的提醒
如果旧路由是 x86_64,而 MT5000 是 ARM64:
不建议直接把旧 OpenClash 的完整 tar.gz 备份整体覆盖恢复。
因为完整备份里有可能包含:
x86_64 core
从而覆盖 MT5000 的:
ARM64 clash_meta
更稳妥的做法是只迁移:
YAML / 订阅 / 规则配置
核心在 MT5000 上重新下载。
9. WireGuard:原厂功能其实已经存在
本机原厂固件已经有:
wireguard-tools
kmod-wireguard
gl-sdk4-wg-client
gl-sdk4-wg-server
gl-sdk4-ui-wgclient
gl-sdk4-ui-wgserver
gl-sdk4-ui-vpndashboard
检查:
opkg list-installed | grep -E 'wireguard|gl-sdk4.*wg|vpndashboard'
因此没有必要另外通过 LuCI 安装 WireGuard。
10. 为什么原厂 Web 看不到 WireGuard?
实机排查后发现,真正原因非常简单:
GL.iNet 在简体中文界面主动隐藏了 VPN 菜单。
这些文件:
/usr/share/oui/menu.d/vpndashboard.json
/usr/share/oui/menu.d/wgclient.json
/usr/share/oui/menu.d/wgserver.json
里面都有:
"lang_hide": ["zh-cn"]
GL.iNet 前端会根据当前语言过滤菜单。
11. 最推荐的方法:直接使用繁体中文或英文界面
如果不介意界面语言:
这里其实完全没必要改系统文件。
直接把 GL.iNet 原厂 Web 的语言切换成:
繁體中文
或者:
English
原厂的:
VPN 仪表盘
WireGuard 客户端
WireGuard 服务器
就会显示出来。
这是我更推荐给普通用户的方法:
不改 UI 文件
不影响升级
不需要维护补丁
12. 可选:让简体中文也显示 WireGuard
如果一定要使用简体中文,则可以删除三个 menu JSON 顶层的:
"lang_hide": ["zh-cn"]
12.1 先备份
mkdir -p /root/wg-ui-unlock-backup
cp -af /usr/share/oui/menu.d/vpndashboard.json \
/root/wg-ui-unlock-backup/
cp -af /usr/share/oui/menu.d/wgclient.json \
/root/wg-ui-unlock-backup/
cp -af /usr/share/oui/menu.d/wgserver.json \
/root/wg-ui-unlock-backup/
12.2 用 jq 修改
不要粗暴 sed,用 JSON 工具处理:
for f in \
/usr/share/oui/menu.d/vpndashboard.json \
/usr/share/oui/menu.d/wgclient.json \
/usr/share/oui/menu.d/wgserver.json
do
tmp="${f}.tmp.$$"
jq 'del(.lang_hide)' "$f" > "$tmp" &&
jq empty "$tmp" &&
mv "$tmp" "$f"
done
sync
验证:
jq '.lang_hide // "NO_LANG_HIDE"' \
/usr/share/oui/menu.d/vpndashboard.json
jq '.lang_hide // "NO_LANG_HIDE"' \
/usr/share/oui/menu.d/wgclient.json
jq '.lang_hide // "NO_LANG_HIDE"' \
/usr/share/oui/menu.d/wgserver.json
都应该返回:
NO_LANG_HIDE
退出原厂 Web,强制刷新并重新登录即可。
12.3 回滚
cp -af /root/wg-ui-unlock-backup/vpndashboard.json \
/usr/share/oui/menu.d/vpndashboard.json
cp -af /root/wg-ui-unlock-backup/wgclient.json \
/usr/share/oui/menu.d/wgclient.json
cp -af /root/wg-ui-unlock-backup/wgserver.json \
/usr/share/oui/menu.d/wgserver.json
sync
13. WireGuard 配置
WireGuard 本身建议直接通过 GL.iNet 原厂 Web 完成。
例如:
虚拟专用网络
→ WireGuard 服务器
我的旧网络使用:
Server IPv4:192.168.2.1/24
UDP Port:51820
Peer、密钥、AllowedIPs、全局/分流等参数根据自己的需求配置即可。
如果主要用途只是:
手机在外网访问家里的 192.168.1.0/24
那么客户端可以只让:
192.168.1.0/24
192.168.2.0/24
走 WireGuard,而不是 0.0.0.0/0 全局回家。
14. DDNS:不用原厂 DDNS,直接安装 DDNS-GO
GL.iNet 自带 DDNS 主要使用自己的 DDNS 服务。
如果希望:
自己的域名
+
DNSPod / 腾讯云
我最后选择:
独立版 ddns-go
而不是 luci-app-ddns-go。
原因:
当前系统 OpenWrt 21.02 / LuCI 21
独立二进制依赖最少
有自己的 Web UI
不需要折腾 LuCI 插件兼容性
15. 安装 DDNS-GO
通过 GitHub API 获取最新 Linux ARM64 版本:
curl -L --retry 2 \
https://api.github.com/repos/jeessy2/ddns-go/releases/latest \
-o /tmp/ddns-go-release.json
提取下载地址:
URL="$(jsonfilter \
-i /tmp/ddns-go-release.json \
-e '@.assets[*].browser_download_url' \
| grep 'linux_arm64.tar.gz$' \
| head -1)"
检查:
echo "$URL"
下载:
curl -L --retry 2 "$URL" \
-o /tmp/ddns-go.tar.gz
解压:
rm -rf /tmp/ddns-go
mkdir -p /tmp/ddns-go
tar -xzf /tmp/ddns-go.tar.gz \
-C /tmp/ddns-go
安装:
cp /tmp/ddns-go/ddns-go /usr/bin/ddns-go
chmod 0755 /usr/bin/ddns-go
mkdir -p /etc/ddns-go
验证:
/usr/bin/ddns-go -v
16. 把 DDNS-GO 注册成 OpenWrt 服务
创建:
cat >/etc/init.d/ddns-go <<'EOF'
#!/bin/sh /etc/rc.common
USE_PROCD=1
START=95
STOP=10
start_service() {
procd_open_instance
procd_set_param command /usr/bin/ddns-go -l 0.0.0.0:9876 -c /etc/ddns-go/config.yaml
procd_set_param respawn
procd_set_param stdout 1
procd_set_param stderr 1
procd_close_instance
}
EOF
权限:
chmod +x /etc/init.d/ddns-go
启用:
/etc/init.d/ddns-go enable
/etc/init.d/ddns-go start
检查:
ps | grep '[d]dns-go'
netstat -lntp 2>/dev/null | grep ':9876'
Web:
http://路由器IP:9876
然后在 Web 里自行配置:
DNSPod / 腾讯云
SecretId / SecretKey / Token
域名
IPv4 获取方式
不要在 WAN 防火墙上开放 9876 管理端口。
17. 从临时 LAN-LAN 切换成正式主路由
软件全部准备好后,再换主路由。
临时阶段:
MT5000 LAN:
192.168.1.249
Static
Gateway = 192.168.1.1
DHCP Server = OFF
正式切换时:
- 先断开旧主路由,避免两个
192.168.1.1冲突。 - 把 MT5000 LAN 改成正式地址。
- 清除临时 LAN Gateway / DNS。
- 开启 DHCP Server。
- 根据自己的宽带方式配置 WAN。
- 再测试 OpenClash / WireGuard / DDNS-GO。
例如最终 LAN:
协议:静态地址
IP:192.168.1.1
掩码:255.255.255.0
IPv4 网关:留空
手工 LAN DNS:可留空
DHCP Server:开启
开启 DHCP Server:
uci set dhcp.lan.ignore='0'
uci commit dhcp
/etc/init.d/dnsmasq restart
再次强调:
LAN 仍然是“静态地址”
不是 DHCP Client。
18. 最终验证
我这次最终确认:
普通上网 OK
OpenClash OK
WireGuard OK
DDNS-GO OK
可以分别检查:
LuCI
http://192.168.1.1:8080/
GL.iNet 原厂 Web
http://192.168.1.1/
OpenClash
/etc/openclash/core/clash_meta -v
并实际测试代理。
WireGuard
手机关闭 Wi-Fi,使用 4G/5G 从公网连接 DDNS 域名:
your-domain.example:51820
再测试:
192.168.1.1
家庭 LAN 设备
DDNS-GO
http://192.168.1.1:9876/
并检查 DNSPod 中的 A 记录是否已经更新为当前公网 IPv4。
19. 总结:这个国内版真正需要突破的是什么?
折腾完以后,整个问题其实可以归纳为几个点。
1. 国内版区域限制
CN → US
可以解除部分地区限制。
但这一步涉及闪存,一定要先备份,并且只应在确认设备/固件版本一致后操作。
2. LuCI 不是普通 OpenWrt 的安装方式
真正关键命令:
sh /usr/bin/init_luci.sh web
不要直接:
opkg install luci
3. OpenClash 可以正常工作
MT5000 4.8.6 的底层:
fw3
iptables legacy
TPROXY
socket
TUN
ipset
dnsmasq-full
实际上都具备。
正确处理用户态依赖后,OpenClash + ARM64 Mihomo 可以正常运行。
4. WireGuard 根本不是“被删掉了”
原厂:
kernel
wireguard-tools
GL SDK
GL Web UI
都还在。
简体中文界面看不到 WireGuard,核心原因只是:
"lang_hide": ["zh-cn"]
所以最省事的解决办法是:
直接使用繁体中文 / English
如果一定要简体中文,再删除相应菜单 JSON 的 lang_hide。
5. DDNS 没必要纠结 GL.iNet 原厂供应商
需要 DNSPod 时,直接:
ddns-go standalone
就可以了。
它自己有 9876 Web 界面,因此没有必要再为了一个 LuCI 菜单去折腾版本兼容。
20. 我个人推荐的最简路线
如果重新做一次,我会按这个顺序:
① 确认 MT5000 / 4.8.6 环境
↓
② 备份并处理 CN → US
↓
③ 临时 LAN-LAN 联网
↓
④ /usr/bin/init_luci.sh web
↓
⑤ 安装 OpenClash 用户态依赖
↓
⑥ 安装 OpenClash LuCI 插件
↓
⑦ 安装 ARM64 Mihomo Core
↓
⑧ GL.iNet Web 切繁体中文,直接使用原厂 WireGuard
↓
⑨ 安装 standalone ddns-go
↓
⑩ 断开旧主路由
↓
⑪ MT5000 LAN 改为正式主路由地址、开启 DHCP
↓
⑫ 配置 WAN
↓
⑬ 测试普通上网
↓
⑭ 测试 OpenClash
↓
⑮ 测试 WireGuard + DDNS
其中:
WireGuard 简体中文菜单解锁
属于完全可选项。
21. 风险提醒
本文包含:
raw flash 写入
opkg 软件包安装
网络接口修改
第三方代理组件
建议:
- 操作前保留原厂固件;
- 修改 flash 前先备份;
- 每一步做完就验证;
- 不要一次性执行大量不理解的命令;
- 不要使用
opkg upgrade; - 不要强装 kernel module;
- 不要混用 OpenWrt/iStoreOS 软件源;
- 修改 LAN 前先明确“DHCP Client”和“DHCP Server”的区别;
- 配置公网 WireGuard / DDNS 时,不要把管理端口暴露到 WAN。
最终状态
本次在:
GL.iNet GL-MT5000 国内版
Firmware 4.8.6
OpenWrt 21.02-SNAPSHOT
Kernel 5.4.281
aarch64_cortex-a53
上已经实机验证:
GL.iNet 原厂 Web 正常
LuCI 正常
OpenClash 正常
Mihomo ARM64 Core 正常
WireGuard Server 正常
WireGuard 外网连接 正常
DDNS-GO + DNSPod 正常
普通路由上网 正常
这套方案的核心思路不是把 MT5000 改造成“纯 OpenWrt”,而是:
尽量保留 GL.iNet 原厂固件和原厂网络/VPN能力,只额外补上 LuCI、OpenClash 和独立 DDNS-GO。
这样既能使用 GL.iNet 原厂 Web 和 WireGuard,又能获得 OpenClash 和自定义 DDNS。
文章评论