Mihomo on an OpenWrt Side Router: Deployment and Transparent Proxying
Run mihomo on an OpenWrt router or side router without a GUI client. This guide covers network layouts, TProxy vs. redir, and gateway setup for routing traffic across your home.
1. Decide Which Traffic the Side Router Will Handle
mihomo is a proxy core, not an automatic setup tool for all of OpenWrt’s networking. A subscription provides nodes and rules, and the core selects an outbound route. Whether device traffic reaches the core still depends on the default gateway, routing table, firewall, and DNS path. Running a YAML file on the router alone does not put LAN devices behind a transparent proxy.
This guide uses a simple IPv4 example: the main router is 192.168.10.1/24 and handles the internet connection and DHCP; the side router is 192.168.10.2/24 with its default gateway pointing to the main router; and the test computer is 192.168.10.100/24. These addresses are examples only. Replace them with your network’s actual addresses and check for conflicts with the DHCP pool before deployment.
| Connection Method | Traffic Entry Point | Best For |
|---|---|---|
| Explicit proxy | Apps connect manually to port 7890 on the side router | Testing nodes, subscriptions, and rules first |
| Single-NIC side router | Set the device’s default gateway to 192.168.10.2 | Bringing a few devices online gradually |
| Dual-NIC downstream router | Devices connect to a separate downstream subnet | A clearly defined forwarding boundary |
| Traffic steering by the main router | The main router forwards traffic by source address or policy | Centralized management of connected devices |
2. Checks Before Deploying on OpenWrt
Check the System Architecture and Firewall Backend
Over SSH, note the OpenWrt version, CPU architecture, and available storage. OpenWrt 22.03 and later use firewall4 and nftables by default, but upgrades, custom firmware, and third-party packages can change the actual setup. Don’t paste old iptables rules into an nftables system, or run two transparent proxy packages that capture the same traffic.
ubus call system board
uname -m
df -h /overlay
free -m
command -v fw4
command -v nft
ip route show
ip -6 route show
The output of uname -m can help identify the architecture, but you still need a mihomo build suited to the device’s CPU features. Some older devices don’t support newer instruction sets. If mihomo exits immediately or reports an illegal instruction, check the binary build first instead of repeatedly changing the subscription.
Keep the Core, Configuration, and Service Management Separate
Manage the executable, working directory, and service script separately. For example, place the core at /usr/bin/mihomo, the configuration at /etc/mihomo/config.yaml, and let OpenWrt’s procd manage the service. These paths are a deployment convention; they don’t mean the files are preinstalled.
/usr/bin/mihomo -v
/usr/bin/mihomo -t -d /etc/mihomo -f /etc/mihomo/config.yaml
The second command checks whether the configuration can be loaded; it is not a full connectivity test. Configurations using rule sets, GeoIP, or GeoSite data also need the relevant resources. Check that external resources can be downloaded, the directory is writable, and startup doesn’t depend on a proxy connection that isn’t available yet. The service script should handle startup order, restarts after failure, and log output so the process doesn’t exit when the SSH session ends.
3. Test the Subscription and Rules with an Explicit Proxy
Use this deployment order: “core running → explicit proxy working → DNS working → transparent traffic capture.” This helps distinguish an unavailable node from a routing error. The snippet below is only a connectivity baseline: it has no proxy nodes, and its final rule sends all traffic directly. It doesn’t replace a subscription or tell you whether a proxy exit is working.
mixed-port: 7890
allow-lan: true
bind-address: 192.168.10.2
mode: rule
log-level: info
ipv6: false
rules:
- MATCH,DIRECT
When merging this snippet into your configuration, keep only one copy of each top-level field. Once LAN listening is enabled, configure the OpenWrt firewall to allow access to port 7890 from trusted LAN devices only. Don’t expose it to WAN or set up public port forwarding. The listen address must belong to the side router.
- On the test computer, set the HTTP proxy to
192.168.10.2:7890and confirm that requests reach the core. - Next, load a valid Clash-format subscription, confirm that the proxy group includes an available node, and select that node.
- Check the connection log for the matched rule and outbound route. In rule mode, the result depends on rule order—not on whether the proxy group is named “Auto.”
- Turn off the computer’s explicit proxy before testing transparent proxying, so the two traffic paths don’t overlap and skew the results.
On a test computer with curl installed, run curl -I --proxy http://192.168.10.2:7890 https://example.com. This checks the HTTP proxy request path. To confirm traffic is going through a node, also check the matched rule, outbound log, and a trusted egress lookup.
4. TProxy, redir, and TUN: What Each One Does
| Method | What It Handles | Required System Setup |
|---|---|---|
redir-port | Accept redirected TCP connections | NAT redirection, address exclusions, and loop prevention |
tproxy-port | Accept transparently proxied TCP and UDP traffic | TPROXY rules, packet marks, and policy routing |
tun | Accept IP traffic through a virtual network interface | TUN support, route capture, and firewall forwarding |
redir primarily handles TCP
Setting redir-port: 7892 opens a listening port; the firewall must also redirect matching TCP traffic to it. This entry point can’t transparently capture UDP in the same way. If webpages load but games, voice calls, or QUIC fail, check the actual UDP path first instead of simply increasing the timeout.
TProxy Requires Packet Marks and Policy Routing
tproxy-port: 7893 can accept TCP and UDP traffic transparently, but the required kernel modules, firewall rules, and routing table must all be in place. The system uses fwmark and ip rule to route marked packets to the local receive path. Choose mark values and routing table numbers that don’t conflict with existing VPNs, multi-WAN setups, or other packages; don’t assume any particular number is unused on every device.
TUN Takes More Than Flipping a Switch
mihomo’s TUN mode can create routes using fields such as auto-route, but you still need to verify OpenWrt’s forwarding policy, interface detection, and IPv6 routing. Recent mihomo versions also offer Linux support for features such as auto-redirect; check the documentation for the version you have installed. Don’t enable automatic redirection from one guide alongside manually configured TProxy rules from another.
5. Gateways, Return Traffic, and Firewall Forwarding
On a single-NIC side router, set the test computer’s default gateway to 192.168.10.2, while the side router’s own default route should still point to 192.168.10.1. Don’t point the main router and side router’s default routes at each other. If the main router continues to provide DHCP, change the computer manually first; once tested, use DHCP option 3 to advertise the gateway and option 6 to advertise DNS.
- IP forwarding: Run
sysctl net.ipv4.ip_forwardto check IPv4 forwarding. For normal forwarding, the value should be1. - Firewall zones: In LuCI, go to “Network” → “Firewall” → “General Settings” and check which zone each interface belongs to and how forwarding is configured. Labels may vary by version, so verify the actual zones and interface assignments.
- Return traffic on the same subnet: The main router may send replies directly to the computer, creating an asymmetric path. This can make connection tracking, filtering rules, and statistics on the side router behave differently than expected.
- ICMP Redirect: When traffic enters and leaves through the same interface, the system may tell a device to use a more direct gateway. Check whether the side router sends redirects and whether the device accepts them.
Some single-NIC setups use controlled source NAT to make return traffic for direct connections pass back through the side router. The trade-off is that the upstream router may see all traffic as coming from the side router, affecting per-device statistics and policies. Don’t treat “masquerade on every zone” as a universal fix. Dual-NIC setups, separate downstream subnets, and different firewall policies each need their own design.
6. DNS: Understand the Roles of Ports 53 and 1053
OpenWrt commonly uses dnsmasq on port 53 for DHCP and LAN name resolution. If mihomo also binds to port 53 on the same address, the services will conflict. A simpler setup to troubleshoot is for devices to query port 53 on the side router, dnsmasq to forward requests to mihomo on local port 1053, and mihomo to query upstream DNS.
dns:
enable: true
listen: 127.0.0.1:1053
ipv6: false
enhanced-mode: fake-ip
fake-ip-range: 198.18.0.1/16
nameserver:
- https://1.1.1.1/dns-query
This is only an example DNS section. The upstream address must be reachable from your network, and its connection path must work with your proxy policy. In LuCI, go to “Network” → “DHCP/DNS” → “General Settings” and configure DNS forwarding with 127.0.0.1#1053 using syntax supported by your version. Also check where the resolv file gets its contents to prevent dnsmasq from forwarding requests back to itself.
fake-ip returns an address used for connection mapping, not the destination website’s real address. The mapping only works if mihomo also receives connections from the device to that address. If DNS goes through the side router but the gateway still points to the main router, you may be able to resolve names while every webpage times out.
- Keep LAN hostnames on dnsmasq where possible. If compatibility issues arise, configure fake-ip exclusions or domain resolution policies for the affected domains.
- Redirecting port 53 only covers matching traditional DNS traffic. Built-in browser DoH, encrypted DNS in apps, and other tunnels need to be assessed separately.
- Setting
dns.ipv6: falsealone doesn’t disable IPv6 on devices or capture IPv6 traffic. Devices may still connect directly using the IPv6 default route advertised by the main router.
Complete IPv4 testing first, then plan IPv6 router advertisements (RA), DNS announcements, default routes, and proxy paths separately. For dual-stack traffic capture, verify both AAAA lookups and actual IPv6 connections; checking the IPv4 exit alone isn’t enough.
7. Verify Each Layer and Troubleshoot
Change one thing at a time and record the results before and after each change. The checks below help distinguish traffic that never reaches the side router from traffic that reaches the core but matches the wrong rule, or fails because the node itself is unavailable.
- Basic connectivity: The test computer can reach the main router and the side router’s management address. The side router has the correct default route and system time.
- Explicit proxy: Use port 7890 to access a test site, then check the connection log, selected proxy group, and any outbound errors.
- DNS: Run
nslookup example.com 192.168.10.2and confirm the query follows the intended resolution path. If fake-ip is enabled, check the mapped address. - Transparent traffic capture: Turn off the app’s proxy and start a new connection. Confirm that mihomo still sees it and that it matches the expected rule.
- UDP and IPv6: Test apps that need UDP and destinations that use IPv6 separately. A successful TCP test doesn’t prove either of these paths works.
- Recovery after reboot: Restart the side router and check that the service starts, DNS works, firewall rules are restored, and node hostnames resolve.
| Symptom | Check First |
|---|---|
| Explicit proxy works, but there are no transparent proxy logs | Device gateway, forwarding path, rule counters, and TUN routes |
| Domain resolves, but connections keep timing out | Whether fake-ip traffic reaches the core, proxy loops, and node reachability |
| Web browsing works, but some real-time apps fail | UDP entry point, node UDP support, MTU, and firewall |
| Existing connections still use the old outbound route after rule changes | Close the test connection and start a new one to avoid reusing an existing session |
| No DNS resolution anywhere after reboot | dnsmasq upstream, mihomo startup order, and dependencies for downloading resources |
To capture packets, run tcpdump -ni br-lan host 192.168.10.100 on a device with tcpdump installed to observe traffic from the test computer. Replace br-lan with the actual LAN interface. Before sharing logs, remove sensitive information such as subscription URLs, node credentials, and domains you’ve visited.
8. Configuration Maintenance and Rollback
Update subscriptions, upgrade the core, and change firewall rules separately. Keep device-specific DNS, listen addresses, entry ports, and routing policies in a locally managed layer so remote subscription updates don’t overwrite side-router settings. If you use overrides or configuration merging, check the final generated YAML—not just the original subscription.
- Before upgrading, save the current core version, effective configuration, service script, and firewall rules. Test the configuration before scheduling a service restart.
- Record the original gateway and DNS values before changing them in the main router’s DHCP settings. Restore both when rolling back so devices don’t keep relying on a DNS service that has been stopped.
- Expose the control interface only to the management addresses that need it, and set access credentials. Treat subscription files as sensitive configuration and keep them out of public repositories.
- Plan a bypass for outages in advance. If devices still point to a powered-off side router, the main router won’t automatically take over its gateway address.
A successful side-router deployment depends on aligning the traffic entry, DNS resolution, and outbound paths. First verify explicit proxying on one device, then choose a single transparent traffic capture method, and only then expand the DHCP rollout. For rule modes, subscription imports, and client steps, see the Clash setup guide; for field details, consult the full documentation.