1. Deployment Model: Main Router or Bypass Gateway
Before running a proxy core on a router, you need to answer one question first: which device does the core actually run on. The two models have clearly different use cases, and picking the wrong one is the number one reason beginners get stuck.
Main router (inline install)
The core runs right on the gateway itself, so all LAN traffic passes through it naturally with zero client-side config. The trade-off is tight coupling: a core crash, a bad rule, or memory exhaustion takes the whole household offline. NAT and encryption/decryption also stack on the same chip, which is the heaviest possible load — low-end MIPS boxes generally can't keep up once bandwidth exceeds 100Mbps.
Bypass gateway (single-arm gateway)
Set up a separate device — an old TV box, a Raspberry Pi, or a small x86 box all work — flash OpenWrt onto it, plug it into the same LAN as your main router, and give it a static IP on that subnet. Any device you want proxied just points its default gateway and DNS at this bypass box; everything else stays untouched. If the bypass gateway crashes, switching the gateway back to the main router restores internet in under ten seconds — the risk is fully contained.
This guide focuses on the bypass gateway model. Core installation and configuration are identical either way — the only difference is where traffic enters — so readers going with an inline main-router setup can skip the "Pointing the Gateway" section in Part 4.
The real value of a bypass gateway isn't performance — it's the ability to roll back. Any misconfiguration comes with a ten-second exit. That's the safety net you want in place before putting a proxy core anywhere near your production network.
2. Choosing and Installing the Core
mihomo is the community-maintained continuation of the original Clash core after it was archived (formerly Clash.Meta). It ships as a single-file binary with no extra dependencies and runs directly on OpenWrt, making it the go-to core for router deployments today. Its release builds are gzip-compressed raw binaries split by CPU architecture, so step one is figuring out exactly which architecture your device uses.
SSH into the router and run uname -m, then match the output against this table to pick the right download:
| uname -m output | Typical devices | Keyword in release filename |
|---|---|---|
| aarch64 | Raspberry Pi 4/5, NanoPi R4S, most ARM boxes | linux-arm64 |
| armv7l | Raspberry Pi 2/3 (32-bit OS), older dev boards | linux-armv7 |
| mipsel | MT7621-based routers (K2P, Xiaomi 3 variants) | linux-mipsle-softfloat |
| x86_64 | x86 router boxes, VMs | linux-amd64-compatible |
Two easy mistakes to avoid: first, x86 router boxes need the compatible-suffixed build — OpenWrt's x86 target compiles for an older instruction set, and a plain amd64 build will throw Illegal instruction on some CPUs; second, MIPS devices like MT7621 are little-endian and mostly lack a hardware FPU, so you need the mipsle-softfloat build specifically.
Here's the full install sequence for an arm64 device:
opkg update
opkg install curl ca-bundle kmod-tun
curl -L -o /tmp/mihomo.gz https://github.com/MetaCubeX/mihomo/releases/download/v1.19.5/mihomo-linux-arm64-v1.19.5.gz
gunzip /tmp/mihomo.gz
mv /tmp/mihomo /usr/bin/mihomo
chmod +x /usr/bin/mihomo
mihomo -v
If the last line, mihomo -v, prints a version number, you picked the right architecture. If it throws Illegal instruction or Exec format error, go back to the table above and try a different build. The version number in the command is just an example — check the mihomo releases page for the current stable version and exact filename before downloading. kmod-tun gets installed here too; it's needed in Part 4.
/tmp on OpenWrt is a RAM disk that clears on reboot, so it's only good for staging files. The core binary and configs need to live on flash storage — /usr/bin and /etc/mihomo. If your device has less than 32MB of flash, set up extroot or use external storage first, or you won't even have room for the GeoIP database.
3. Setting Up the Config: Fetching Your Subscription and Key Fields
We'll use /etc/mihomo as the config directory, and start the core with the -d /etc/mihomo flag — config.yaml, the GeoIP database, and cache files will all land there. Create the directory first, then pull down your subscription:
mkdir -p /etc/mihomo
curl -L -o /etc/mihomo/config.yaml "your subscription URL"
Most proxy providers' subscription links return a ready-to-use YAML config when requested by a Clash-family client — just save it as config.yaml. If what you get back is a base64-encoded node list instead, that means the server is returning a generic subscription format, and you'll need to send a Clash User-Agent with the request, or convert it on your computer first and scp it over to the router. Running a subscription-conversion tool on the router itself isn't recommended — it's just extra surface area to maintain.
Once you have the subscription file, edit these key fields for the bypass-gateway role and leave everything else as-is:
mixed-port: 7890 # combined HTTP and SOCKS entry point
allow-lan: true # allow LAN devices to connect — required for a bypass gateway
bind-address: "*"
log-level: warning
external-controller: 0.0.0.0:9090 # external control API
external-ui: ui # dashboard static files directory
secret: "replace with your own password"
dns:
enable: true
listen: 0.0.0.0:1053
enhanced-mode: fake-ip
fake-ip-range: 198.18.0.1/16
nameserver:
- 223.5.5.5
- 119.29.29.29
fallback:
- https://1.1.1.1/dns-query
- https://dns.google/dns-query
tun:
enable: true
stack: system
auto-route: true
auto-detect-interface: true
dns-hijack:
- any:53
Three fields determine whether the bypass gateway actually works: without allow-lan enabled, LAN devices simply can't reach port 7890; external-controller needs to bind to 0.0.0.0 so you can reach the dashboard from a browser on your computer; and the tun block is the core of traffic takeover, covered next. After editing, verify the syntax with the core's built-in check:
mihomo -t -d /etc/mihomo
If it prints configuration file test is successful, you're good. If it errors out, the message will include a line number — go fix that line.
If external-controller is exposed on the LAN, always set a secret, and never map it to the public internet. Port 9090 has full control — switching nodes, viewing connections, editing config — so leaving it open is basically handing your entire network exit to anyone on the same subnet.
4. Taking Over Traffic: TUN Mode and Gateway Pointing
TUN is the right takeover method here because it moves all the routing plumbing inside the core itself: once enabled, mihomo creates a virtual network interface called utun, auto-route writes the routing rules automatically, and all outbound and forwarded TCP/UDP traffic gets pulled into the core — no need to hand-write an iptables REDIRECT rule, and no special-casing for UDP. Set stack to system for the best compatibility; try gvisor if you're chasing throughput and want to benchmark.
TUN requires kernel-level support, which is exactly what the kmod-tun package installed in Part 2 provides. Confirm the device node exists:
ls /dev/net/tun
If /dev/net/tun shows up, you're set. If it says the file doesn't exist, kmod-tun either isn't installed or hasn't loaded — reinstall it and reboot.
Pointing client gateways
The bypass gateway isn't directly connected to any client device, so traffic needs to be "pointed" toward it. Here are three approaches, ranked by recommendation:
- Push it via the main router's DHCP: in the main router's DHCP settings, change the gateway (option 3) and DNS (option 6) to the bypass gateway's IP. Every device on the network switches over seamlessly, and new devices pick it up automatically.
- Set it manually per device: only change the gateway and DNS on the devices you want proxied, leaving everything else connected directly to the main router — this granularity is unique to the bypass model and is great for testing on one device first.
- Let the bypass gateway run its own DHCP: turn off DHCP on the main router and let the bypass gateway take over entirely. This gives you the most control, but if the bypass gateway goes down, nothing on the network gets an IP — not recommended for beginners.
Two system-level checks: OpenWrt has IP forwarding on by default — confirm with sysctl net.ipv4.ip_forward, which should return 1. On the firewall side, go to Network → Firewall → Zones and add the utun device to the lan zone's device list — otherwise forwarded traffic gets dropped at the netfilter level, which shows up as clients being able to reach the bypass gateway but unable to load any webpage.
5. Autostart on Boot: Letting procd Supervise It
OpenWrt's service manager is procd, and a single init script gets you both boot-time autostart and crash recovery. Create /etc/init.d/mihomo with the following contents:
#!/bin/sh /etc/rc.common
# mihomo core supervision script
START=99
STOP=10
USE_PROCD=1
start_service() {
procd_open_instance mihomo
procd_set_param command /usr/bin/mihomo -d /etc/mihomo
procd_set_param respawn 3600 5 5
procd_set_param stdout 1
procd_set_param stderr 1
procd_close_instance
}
The three numbers on the respawn line are, in order: delay, interval, and max retries — meaning the process gets restarted 5 seconds after exiting, but if it crashes more than 5 times within an hour, procd gives up. stdout and stderr are redirected to syslog, so logread will show you the core's logs afterward. Make it executable and enable it:
chmod +x /etc/init.d/mihomo
/etc/init.d/mihomo enable
service mihomo start
enable creates a symlink starting with S99 under /etc/rc.d, so the core starts automatically on every reboot. You can also automate subscription refreshes: add a weekly crontab job that re-downloads config.yaml in the early morning and then runs service mihomo restart, keeping the node list fresh without manual work.
6. Verification and Troubleshooting Checklist
Getting everything deployed doesn't mean the traffic split is actually working. Go through these checks in order — each one has a clear pass/fail signal:
Process is running
pgrep mihomoreturns output, and/etc/init.d/mihomo statusshows running. On first launch, the core auto-downloads the GeoIP database into /etc/mihomo, so make sure that directory is writable with enough free space.Logs are clean
logread -e mihomoshows no repeating errors. If the same error line keeps showing up, it's usually a config or network issue — trace it from the error message.Dashboard is reachable
Open http://bypass-gateway-IP:9090/ui in a browser, enter the secret, and you should see live connections. The external-ui directory needs the built dashboard assets — from metacubexd or zashboard — extracted into it beforehand.
DNS is being intercepted
Run
nslookup www.google.com bypass-gateway-IPfrom a client. In fake-ip mode, it should return an address in the 198.18.x.x range, confirming the query is going through the core rather than leaking around it.Traffic exit is correct
Open any IP-lookup site on a client device — it should show the proxy node's exit address. Then visit a site that should stay on direct connection and confirm it's fast and not routed through the proxy — that confirms the split is actually working.
Common issues and fixes:
- Illegal instruction / Exec format error: wrong architecture build — go back to the table in Part 2 and grab the correct one.
- All nodes time out but the dashboard loads fine: the router's system clock is off by too much, breaking TLS validation — confirm NTP sync has completed. The bypass gateway also needs to be able to resolve the subscription domain on its own.
- Clients can reach the bypass gateway but have no internet access at all: utun hasn't been added to the firewall's lan zone, or the client's gateway pointing hasn't taken effect — go back through Part 4 step by step.
- Sites that should be fast are oddly slow: DNS splitting isn't working — check whether the dns block is enabled and whether fake-ip-filter covers the domains that should bypass the proxy. If needed, point client DNS at the bypass gateway too, so queries don't skip the core and go straight upstream.
At this point, you've got a self-healing, rollback-friendly bypass gateway that takes over traffic on demand. From here, maintenance boils down to two things: keeping an eye on mihomo release updates, and backing up the /etc/mihomo directory periodically — it holds all your configs and databases, so copying that whole folder over is all you need when migrating to a new device.