Plan the network first: the main router provides internet access; the bypass router handles traffic routing

When running mihomo directly on a bypass router, start by figuring out the traffic path—not by importing a subscription. Change the gateway on just one test device first, then verify forwarding, DNS, and rules before changing DHCP. This guide uses a single-interface bypass router on the same subnet: the main router keeps its WAN connection, DHCP service, and internet uplink; OpenWrt connects to its LAN, and mihomo handles traffic from selected devices.

DeviceIPv4 addressDefault gateway and role
Main router192.168.10.1/24Connects upstream and continues to provide DHCP
OpenWrt bypass router192.168.10.2/24Default gateway: 192.168.10.1
Test device192.168.10.100/24Gateway and DNS: 192.168.10.2

These addresses are examples; replace them with your own subnet before following the steps. Keep the bypass router's address outside the main router's DHCP pool, or create a static DHCP lease. In OpenWrt, go to Network → Interfaces → LAN → Edit and set a static IPv4 address, subnet mask, and IPv4 gateway. Do not set the bypass router's own gateway to its own address.

  • Run only one DHCP server on a broadcast domain. On the bypass router, open LAN → DHCP Server → General Setup and select Ignore interface, while keeping dnsmasq's DNS service enabled.
  • Do not point the main router's default route back to the bypass router, or traffic can loop between the two routers.
  • During testing, keep a direct way to access the main router's admin interface so you can recover if the service stops and you need to change device settings.

Install mihomo: check the CPU architecture, working directory, and permissions

mihomo is the kernel name used after Clash Meta. A direct kernel installation does not include a GUI client or automatically configure the OpenWrt firewall. First, connect over SSH, inspect the system, and make sure you download the Linux executable for the correct architecture:

ubus call system board
uname -m
df -h /overlay /tmp
date
ip -4 route show

x86_64 usually means amd64, and aarch64 usually means arm64. For MIPS devices, you also need to check endianness, instruction set, and floating-point ABI—“64-bit router” alone is not enough to choose a binary. If you see Exec format error, check the architecture. For Illegal instruction, check the CPU instruction-set requirements rather than repeatedly editing the YAML.

Place the binary and configuration

Upload the extracted kernel to /tmp/mihomo on the router over SCP or SFTP, then run the commands below. /tmp is usually in memory and is cleared on reboot; store the kernel and configuration on persistent storage for long-term use.

mkdir -p /etc/mihomo
cp /tmp/mihomo /usr/bin/mihomo
chmod 0755 /usr/bin/mihomo
chmod 0700 /etc/mihomo
/usr/bin/mihomo -v

Save the actual configuration as /etc/mihomo/config.yaml and run chmod 0600 /etc/mihomo/config.yaml. Subscription URLs, proxy credentials, and controller secrets are sensitive. If the configuration enables rule sets or geodata, make sure those resources can be downloaded or are available in the working directory. Keep an eye on free space, especially on devices with limited flash storage.

TUN also requires kernel support. The commands below are for the common opkg environment in OpenWrt 24.10. For other versions, first check the firmware's package manager and repositories. Kernel modules must match the running firmware kernel; do not force-install packages built for another version.

opkg update
opkg install kmod-tun ip-full
test -c /dev/net/tun && echo "TUN device ready"

Run /usr/bin/mihomo -t -d /etc/mihomo to check the configuration first. A successful test only confirms that the syntax is valid and some resources can be initialized; it does not mean transparent forwarding works.

TUN or redir: choose one traffic-interception method based on your protocol needs

TUN receives IP traffic through a virtual network device and is suitable when both TCP and UDP need to be handled. redir relies on firewall rules to redirect TCP connections to a listening port in the kernel. Its traffic path can be easier to inspect, but redir-port alone does not handle UDP. Choose one method to start with; do not enable multiple plugins, TUN, and hand-written transparent proxy rules at the same time.

ItemTUNredir
Traffic handledTCP and UDP; actual support also depends on the proxy nodePrimarily TCP; UDP requires a separate approach such as TPROXY
Requirements/dev/net/tun, routing permissions, and forwarding enabledA TCP listening port and firewall redirect rules
Main troubleshooting areasPolicy routing, egress interface detection, and the TUN firewall zoneRule matches, reserved-address exclusions, and duplicate interception
Ports used in this guideUse mixed-port: 7890 to test an explicit proxy connectionredir-port: 7892

Minimal TUN configuration for a connectivity test

The basic configuration below tests direct forwarding. It has no proxy nodes and ends with the DIRECT rule, so a successful test does not mean proxying through a node works. Use it to check the TUN and DNS paths, then merge in your actual proxies, proxy-providers, proxy-groups, and routing rules. Do not overwrite an unbacked-up configuration with it.

mixed-port: 7890
allow-lan: false
mode: rule
log-level: info
ipv6: false

tun:
  enable: true
  device: mihomo
  stack: mixed
  auto-route: true
  auto-detect-interface: true
  strict-route: false
  dns-hijack:
    - any:53

dns:
  enable: true
  listen: 127.0.0.1:1053
  ipv6: false
  enhanced-mode: redir-host
  nameserver:
    - 223.5.5.5
    - 119.29.29.29

rules:
  - IP-CIDR,192.168.10.0/24,DIRECT,no-resolve
  - MATCH,DIRECT

allow-lan: false restricts explicit proxy listeners; it does not prevent TUN from handling forwarded traffic. auto-route adds the routes needed for traffic interception, but does not configure every OpenWrt firewall zone for you. auto-detect-interface also relies on a working default route. If you use multiple WANs, a VPN uplink, or other policy routes, set interface-name explicitly for the actual egress interface instead of assuming it is eth0.

What redir does not handle

For redir, disable tun.enable, set redir-port: 7892, and add firewall rules in the prerouting path to redirect only TCP traffic from the selected LAN devices. OpenWrt 22.03 and later commonly use firewall4 and nftables; do not assume iptables commands from older guides will add working rules to the same firewall.

  • Limit the rules to the ingress interface and test source address 192.168.10.100. Exclude the router's management address, the LAN, and any reserved address ranges you need to keep out of the proxy.
  • Do not send connections opened by the kernel to proxy nodes back through the transparent proxy entry point. If you also intercept traffic from the router itself, set up separate egress bypass and loop prevention.
  • HTTP/3 uses UDP/443. With TCP redir only, a browser's HTTP/2 and HTTP/3 traffic may use different routes; that does not mean port 7892 is broken.
  • Do not replace the entire table inet fw4. After making the rules persistent, test /etc/init.d/firewall reload and confirm that they remain in place after the reload.

DNS routing: send device queries to the bypass router, then resolve upstream through local services

A good starting path is: the device queries 192.168.10.2:53, OpenWrt dnsmasq forwards to 127.0.0.1:1053, and mihomo queries explicitly configured upstream resolvers. This keeps dnsmasq handling local network names and avoids two services competing for port 53 on the same address.

For a simple setup without custom split DNS, you can use the UCI settings below. Back up /etc/config/dhcp first. The commands remove the existing generic upstream server list from the first dnsmasq section. If you have corporate domains or other local forwarding rules, merge the settings manually rather than running them as-is.

cp /etc/config/dhcp /root/dhcp.before-mihomo
uci set dhcp.@dnsmasq[0].noresolv='1'
uci -q delete dhcp.@dnsmasq[0].server
uci add_list dhcp.@dnsmasq[0].server='127.0.0.1#1053'
uci commit dhcp
/etc/init.d/dnsmasq restart

nslookup example.com 127.0.0.1

noresolv='1' prevents dnsmasq from also reading its automatically generated upstream server list. Do not set 192.168.10.2 as mihomo's upstream resolver, or dnsmasq and mihomo will send DNS queries back and forth in a loop. If your proxy nodes use domain names, make sure those names can still be resolved before the proxy connection is up.

For an initial setup, redir-host makes it easier to inspect DNS results. Before switching to fake-ip, make sure forwarding through the bypass router is stable, then configure fake-ip-filter to suit local domain names and device compatibility. Browser Secure DNS, Android Private DNS, and in-app DoH can bypass regular port 53 queries; dns-hijack does not decrypt those connections automatically.

OpenWrt forwarding and same-subnet return traffic: creating a TUN interface is not enough

Check the actual zones and forwarding relationships under Network → Firewall. A common approach is to create a dedicated zone for the TUN device mihomo, allow LAN traffic into that zone, and allow direct traffic emerging from TUN to reach the actual egress zone. On a single-interface bypass router, egress is often still on LAN. Do not copy a dual-interface guide and assume the egress zone must be WAN.

  • Allow devices to reach the bypass router on UDP and TCP port 53. Do not expose the DNS service unintentionally on untrusted interfaces.
  • Check whether net.ipv4.ip_forward is set to 1. Devices still will not get online if the kernel has routes but forwarding is disabled.
  • While troubleshooting, temporarily disable software and hardware flow offloading so existing connections do not take a fast path that skews rule counters and packet captures.
  • Do not “fix” forwarding by disabling the firewall globally. Allow only the zones and directions you actually need, and check the order of existing rules.

There is another easy-to-miss issue on a shared subnet: after the bypass router sends direct traffic to the main router, the main router may send replies straight to the device, creating an asymmetric path. If your design requires traffic to pass through the bypass router in both directions, apply narrowly scoped source NAT to selected forwarded traffic so the upstream router sees 192.168.10.2 as the source. Do not indiscriminately enable masquerading for all traffic in the entire LAN zone. A separate subnet for proxied devices is another, often clearer, option.

Forwarded traffic entering and leaving the same interface can also trigger ICMP Redirects, telling devices to use the main router instead. Check the relevant settings for this topology, especially on the actual LAN device:

sysctl net.ipv4.ip_forward
sysctl net.ipv4.conf.all.send_redirects
sysctl net.ipv4.conf.default.send_redirects
sysctl net.ipv4.conf.br-lan.send_redirects

ip -4 route show
ip -4 rule show
ip -4 route show table all

If the device is indeed named br-lan, set the three send_redirects entries above to 0, test the result, then make it persistent. Adjust the settings to match your actual device if the interface name contains a dot or uses a different bridge layout. Do not change every sysctl setting at once, or it will be difficult to tell which change affected the traffic path.

Start at boot with procd, not systemd

OpenWrt generally uses procd to manage services; desktop Linux commands such as systemctl enable mihomo do not apply. Stop any other proxy-management plugins first, and make sure no other process is using the same ports or managing the same TUN routes. Then create /etc/init.d/mihomo:

#!/bin/sh /etc/rc.common

START=99
STOP=10
USE_PROCD=1

start_service() {
    /usr/bin/mihomo -t -d /etc/mihomo || return 1

    procd_open_instance
    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_set_param limits nofile="65535 65535"
    procd_close_instance
}

This script checks the configuration before handing the process to procd. The example respawn parameters limit repeated crashes and restarts in a short period. The service runs as root by default so it can create TUN devices and change routes. Running it as a less privileged user requires a separate capability setup; adding a username alone is not enough.

chmod 0755 /etc/init.d/mihomo
/etc/init.d/mihomo start
logread -e mihomo
ip link show mihomo

# Enable autostart only after confirming the service and forwarding work
/etc/init.d/mihomo enable

After editing the YAML, run mihomo -t -d /etc/mihomo first, then run /etc/init.d/mihomo restart if the test passes. A complete recovery at boot also requires persistent firewall rules, a working DNS service, and access to any resources mihomo needs to download. START=99 alone does not guarantee an internet connection is ready.

Verify and roll back: check ports, DNS, forwarding, and proxy nodes in order

During acceptance testing, change the gateway on only the test device. First verify the explicit proxy from the bypass router, then test transparent traffic from the device. Only after that should you roll out the gateway and DNS settings through the main router's DHCP service. This separates “the kernel can access the internet” from “device traffic is being intercepted.”

  1. Check that mihomo is running. Review logread -e mihomo for occupied ports, failed rule downloads, or TUN creation errors. If ss is installed, run ss -lntup to check the actual listeners, including ports 7890 and 1053.
  2. Test the explicit proxy. If curl is available on the router, run curl -I -x http://127.0.0.1:7890 https://example.com. This bypasses transparent forwarding from the test device. If it fails, check mihomo, upstream DNS, and the egress route first.
  3. Test DNS from the device. On a Linux test device, run nslookup example.com 192.168.10.2, then use ip -4 route show default to confirm the gateway. Successful name resolution does not prove that TCP traffic is passing through TUN.
  4. Check that transparent rules match. Disable any explicit in-app proxy on the device and start a new connection. Check mihomo's logs for the source address, matched rule, and outbound. Once the proxy-node configuration is merged, make sure the actual proxy group and node are selected rather than always matching DIRECT.
  5. Test recovery. Test a service restart, firewall reload, and device reboot in turn. Check that DNS comes back, TUN is recreated, and the device still uses the intended gateway.

Common symptoms and what to check first

SymptomCheck first
Router is reachable, but devices are notDevice gateway, IPv4 forwarding, firewall zones, and same-subnet return path
IP connections work, but domain names failPorts 53 and 1053, dnsmasq upstream, and DNS loops
Some apps bypass the proxyIPv6 default route, UDP, and app-specific proxy or DNS settings
Small requests work, but downloads often stallPath MTU, upstream encapsulation, and retransmissions; do not blindly increase the TUN MTU
Stops working after a rebootprocd enabled state, persistent configuration location, firewall rule recovery, and startup logs

To roll back, first restore the test device's gateway and DNS to the main router at 192.168.10.1. Then stop mihomo and remove custom transparent proxy rules and forwarding settings. If you configured dnsmasq to forward only to port 1053, restore its upstream servers too. Otherwise, the bypass router will still receive DNS queries after mihomo stops, but nothing will be available to resolve them.

/etc/init.d/mihomo stop
/etc/init.d/mihomo disable

# Restore only if this backup is from before this deployment
cp /root/dhcp.before-mihomo /etc/config/dhcp
/etc/init.d/dnsmasq restart

Only roll this out to the whole network after testing. The main router publishes the gateway with DHCP option 3 and DNS with option 6; assign those addresses only to devices that need to use the bypass router. Keeping a record of the topology, configuration backups, and a rollback path makes long-term maintenance easier than applying a complete ruleset all at once. For field descriptions, see the Configuration Reference; for importing a client configuration, see Quick Start.