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 MethodTraffic Entry PointBest For
Explicit proxyApps connect manually to port 7890 on the side routerTesting nodes, subscriptions, and rules first
Single-NIC side routerSet the device’s default gateway to 192.168.10.2Bringing a few devices online gradually
Dual-NIC downstream routerDevices connect to a separate downstream subnetA clearly defined forwarding boundary
Traffic steering by the main routerThe main router forwards traffic by source address or policyCentralized 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.

  1. On the test computer, set the HTTP proxy to 192.168.10.2:7890 and confirm that requests reach the core.
  2. Next, load a valid Clash-format subscription, confirm that the proxy group includes an available node, and select that node.
  3. 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.”
  4. 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

MethodWhat It HandlesRequired System Setup
redir-portAccept redirected TCP connectionsNAT redirection, address exclusions, and loop prevention
tproxy-portAccept transparently proxied TCP and UDP trafficTPROXY rules, packet marks, and policy routing
tunAccept IP traffic through a virtual network interfaceTUN 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.

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.

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.

  1. 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.
  2. Explicit proxy: Use port 7890 to access a test site, then check the connection log, selected proxy group, and any outbound errors.
  3. DNS: Run nslookup example.com 192.168.10.2 and confirm the query follows the intended resolution path. If fake-ip is enabled, check the mapped address.
  4. 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.
  5. 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.
  6. Recovery after reboot: Restart the side router and check that the service starts, DNS works, firewall rules are restored, and node hostnames resolve.
SymptomCheck First
Explicit proxy works, but there are no transparent proxy logsDevice gateway, forwarding path, rule counters, and TUN routes
Domain resolves, but connections keep timing outWhether fake-ip traffic reaches the core, proxy loops, and node reachability
Web browsing works, but some real-time apps failUDP entry point, node UDP support, MTU, and firewall
Existing connections still use the old outbound route after rule changesClose the test connection and start a new one to avoid reusing an existing session
No DNS resolution anywhere after rebootdnsmasq 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.

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.