Image: Zhuoer Mountain, Qilian County
- Background
My bypass router is the Xiaomi AX3000T, which has been flashed with OpenWrt firmware and runs OpenClash (based on the mihomo kernel). This solution has been used for over half a year and the overall experience is decent, but there is a fatal issue: the AX3000T only has 233MB of memory
When OpenClash is running, the mihomo process itself consumes tens of MB of memory, and coupled with the overhead of the OpenWrt system itself, the remaining available memory is often only a dozen MB. Once the number of subscribed nodes is larger and the rules are more complex, OOM Killer will be triggered, mihomo will be killed, and the entire agent will be directly disconnected. The most annoying thing is that the network will not automatically recover, so you have to manually restart the OpenClash service in the background. Sometimes I don’t even know if it’s disconnected in the middle of the night, and only realize the next morning that I can’t access the internet. Decided to remove mihomo from the router.
2. Scheme selection
There happens to be an idle Raspberry Pi 4B (8GB memory version) at hand, with memory crushing directly. Solution: Use Docker to run mihomo on Raspberry Pi, and the router will no longer take on proxy tasks.
III. Backup AX3000T Configuration
The first step of migration is to backup all the configurations on the router:
# 备份OpenWrt基础配置
scp -r root@你的路由器IP:/etc/config/ ./openwrt-config/
# 备份OpenClash的mihomo主配置
scp root@你的路由器IP:/etc/openclash/config/config_real.yaml ./mihomo-config/
# 备份规则集文件
scp -r root@你的路由器IP:/etc/openclash/rule_provider/ ./mihomo-config/rule_provider/
# 备份自定义规则
scp root@你的路由器IP:/etc/openclash/custom_rules/ ./mihomo-config/custom_rules/
- Configuration Migration
The config.real.yaml exported from OpenClash cannot be used directly and some adjustments need to be made:
- Delete the experimental field unique to OpenClash (which was added by OpenClash itself and Mihomo does not recognize it)
- Change ports such as mixed port and port to avoid conflicts with other services on Raspberry Pi
- Set allow lan: true (because other devices need to connect through a local area network)
- Change the external controller to 0.0.0.0:9090 for remote management convenience
Put the organized configuration and rule_devider files into a directory on the Raspberry Pi, such as/home/pi/mihomo/
Fifth, pitfalls record: ImmortalWrt Docker solution
The initial solution I came up with was to run ImmortalWrt (a branch of OpenWrt) on Raspberry Pi using Docker, and then run OpenClash inside ImmortalWrt. This is the most convenient configuration and migration, which is the same as the experience on the router.
It sounds beautiful, but in reality it’s a disaster.
After starting the ImmortalWrt container, its br lan bridge will directly seize the Raspberry Pi’s eth0 network card! Even more deadly is that ImmortalWrt’s default IP address is 192.168.x.1 (your router IP), while my Raspberry Pi IP is your Raspberry Pi IP, and the two IPs conflict in the same network segment.
Result: The Raspberry Pi lost contact directly, causing the entire LAN routing table to become chaotic. Not only could the Raspberry Pi not access it, but the networks of other devices were also disconnected. Finally, the only option is to physically power off and restart the Raspberry Pi, then enter recovery mode to delete the Docker container.
Blood and tears lesson: Never use Docker to run ImmortalWrt as a proxy on Raspberry Pi! Br lan bridging can grab network cards, and IP conflicts can cause the entire network to crash!
Sixth, the correct solution is to directly run mihomo Docker
After abandoning the ImmortalWrt solution, return to the simplest way – run mihomo directly with Docker:
docker run -d --name mihomo --network host --cap-add NET_ADMIN -v /home/pi/mihomo/config.yaml:/root/.config/mihomo/config.yaml -v /home/pi/mihomo/rule_provider:/root/.config/mihomo/rule_provider --restart unless-stopped metacubex/mihomo:latest
With this command, start mihomo directly and run it on port 9090 of the Raspberry Pi. For other devices that require proxy, simply point the main router and DNS to the IP address of the Raspberry Pi.
7. Effect Comparison
| Comparison items | AX3000T+OpenClash | Raspberry Pi 4B+Docker mihom |
|---|---|---|
| Available memory | ~233MB (often insufficient) | 8GB (completely surplus) |
| OOM risk | Frequently triggered, resulting in network disconnection | |
| Configuration management | OpenWrt backend | Directly edit YAML+Docker restart |
| Firmware update risk | Flashing may cause bricking | Completely independent of router |
| Network interruption risk | OOM killing process leads to network disconnection | Almost never | Extra hardware cost | None | Need a Raspberry Pi |
| None | Approximately 5W (Raspberry Pi 4B standby) | |
| Maintenance complexity | Medium | Low (Docker container management is very convenient) |
8. Summary
How to determine if it is OOM? SSH to the router to run dmesg | grep – i oom, if you see a large amount of; Out of memory: Killed process” The log, that’s it. The AX3000T only has 233MB of memory, and the clash-meta process running OpenClash often consumes 100MB+. Coupled with the system itself, the memory is basically insufficient.
The core lesson is one sentence: Do not use ImmortalWrt’s Docker container to run proxies, just use mihomo’s Docker image. ImmortalWrt’s br lan bridging will seize the host’s network card, causing IP conflicts and directly crashing the entire network.
The combination of Raspberry Pi 4B+Docker+mihomo solves the fundamental problem of insufficient router memory and is much more convenient to manage than OpenClash. The configuration file is just a YAML file, which takes effect as soon as the Docker restart is completed, without the need to click around in the complex web interface of OpenWrt.
If your router often crashes due to insufficient memory, we strongly recommend trying this solution!
Reference materials:
Docker Official installation script
Released on August 23, 2026.
