Tutorial ~15 min read

Linux Mihomo Setup: TUN Mode, systemd Service, and Desktop Routing (2026)

This guide is for readers who want a native Linux stack—desktop or a small server—where Mihomo (the open-source engine commonly known as Clash.Meta) runs headlessly, survives reboots under systemd, and uses TUN mode so browsers, terminals, and desktop apps follow the same routing policy without juggling per-app SOCKS settings. You will place binaries and config.yaml in predictable paths, enable automatic interface routing, grant only the Linux capabilities the process truly needs, then layer a minimal split-routing rule set that keeps domestic traffic direct while everything else uses your proxy groups.

Clash Editorial Team Linux · Mihomo · TUN · systemd · Desktop routing

Why Mihomo with TUN on Linux instead of only HTTP/SOCKS?

A traditional local HTTP or SOCKS listener is easy to understand: you point a browser at 127.0.0.1 and most tab traffic obeys the proxy. The pain arrives with everything else—package managers, git, IDEs, containers, games, and odd Electron apps that ignore environment variables. TUN mode installs a virtual network interface and lets the core participate in the host routing table so eligible flows are steered through Clash-class policy consistently. On Linux this is especially attractive because you can pair that behavior with systemd for boot persistence and clean logs via journalctl, which is exactly what homelab operators and developers expect from other infrastructure daemons.

If your subscription arrives in mixed formats, convert it with a workflow you control—our Subconverter complete guide explains safer patterns than pasting secrets into random web converters. After you have a sane Clash YAML profile, Mihomo can load it directly; the remaining work is filesystem layout, TUN knobs, and a service unit that survives real-world reboots.

Headless Mihomo versus graphical Meta clients

You can run the same policy engine inside a GUI client (for example Clash Verge Rev on Linux) or as a headless binary controlled only by YAML and the REST API. This article focuses on the headless path because it maps cleanly to servers and to advanced desktops where you want i3/Sway-friendly automation. If you prefer buttons and tray icons, browse our official download page for maintained Linux builds and treat this tutorial as the conceptual backbone—TUN, rule mode, and DNS behave the same once the core is running.

Prerequisites: kernel, packages, and honest privilege boundaries

Mihomo’s TUN stack expects a working /dev/net/tun, a reasonably modern kernel, and tools such as ip from iproute2 for route management when auto-route is enabled. Most desktop distributions ship these defaults; minimal cloud images sometimes omit iproute2 until you install the “recommended” network bundle. You also need permission to create TUN devices—either run as root (simple but coarse) or assign capabilities to the binary and run under a dedicated system user (cleaner).

SELinux and AppArmor profiles can block route changes even when the binary looks privileged enough. If the service starts yet traffic never enters the tunnel, check audit logs before you blame YAML: a denied net_admin operation looks like a silent routing miss. Similarly, NetworkManager and systemd-networkd both manage interfaces; Mihomo generally cooperates when auto-detect-interface can see your default egress, but exotic VPN stacks may fight over the same routes—disable overlapping tools temporarily when diagnosing.

  • Kernel: TUN support enabled (typical on x86_64 and aarch64 desktop kernels).
  • Tools: ip route, resolvectl or your resolver CLI for DNS checks.
  • Privileges: CAP_NET_ADMIN for TUN; CAP_NET_BIND_SERVICE if you bind low ports.
  • Firewall: nftables/iptables rules that do not drop marked packets you expect to redirect.

1Directory layout and binary install

Pick a stable home for configuration—common choices are /etc/mihomo for system-wide installs or ~/.config/mihomo for single-user setups. This walkthrough uses /etc/mihomo with a systemd service, which mirrors how many distributions package auxiliary daemons. Download the Mihomo release asset that matches your architecture (for example linux-amd64 or linux-arm64), verify checksums from the upstream release page, extract the binary to /usr/local/bin/mihomo, and ensure it is executable.

Checksum discipline: treat the Mihomo binary like any security-sensitive tool—verify the published digest after download, especially on unattended servers.

Create the configuration directory and seed an empty config.yaml only after you know your subscription loads; a common pattern is to keep /etc/mihomo/config.yaml as the single source of truth and symlink user tools to it if needed. If you run multiple profiles, prefer separate directories under /etc/mihomo/profiles/ and a top-level file that imports the active one—just avoid duplicating secrets across paths where backups might leak.

2Minimal config.yaml before touching TUN

Start with a conservative baseline: mode: rule, a mixed-port or distinct port/socks-port, and an external-controller bound to 127.0.0.1 so local dashboards can talk to the API without exposing it LAN-wide. Define at least one proxy or provider section and a proxy-groups entry your rules can reference. Until routing works, keep log-level: info so journalctl shows meaningful handshake errors instead of silent failure.

# Fragment — adapt names and ports to your profile
mode: rule
log-level: info
mixed-port: 7890
external-controller: 127.0.0.1:9090

proxies: []
proxy-groups: []
rules:
  - MATCH,DIRECT

Replace the placeholder lists with your real nodes and groups imported from subscription conversion. If you already run another Clash-class client, resist the urge to copy megabytes of experimental rules on day one—validate connectivity first, then grow complexity. For DNS alignment with rule mode and FakeIP, read our Meta core DNS leak prevention guide before you enable aggressive dns features.

3Enable TUN mode: stack, auto-route, and interface detection

Add a top-level tun map. Set enable: true. Turn on auto-route: true so Mihomo can install the routes it needs for selected traffic, and enable auto-detect-interface: true on typical desktops so the core tracks your primary NIC when Wi-Fi changes. The stack field chooses the dataplane implementation: system is often the first choice on mainline kernels, while gvisor can help in constrained or unusual environments at the cost of CPU—benchmark if you move heavy workloads.

tun:
  enable: true
  stack: system
  auto-route: true
  auto-detect-interface: true
  strict-route: false

strict-route tightens routing semantics to reduce leak-like edge cases; flipping it on prematurely can break split tunnels that rely on LAN routes, so change it only after baseline browsing works. If you need DNS hijack behavior aligned with TUN, explore dns-hijack options in tandem with the DNS article above—misaligned DNS is the fastest way to think “TUN is broken” when the real issue is name resolution.

Developers who split traffic between IDEs, npm, and GitHub will recognize why TUN matters: see the practical routing patterns in Clash routing tips for AI coding and npm—the same ideas apply once Linux sends those flows through Mihomo instead of per-tool proxies.

4systemd unit: After=network-online.target and capabilities

A reliable service orders itself after networking is actually usable, restarts on failure without wedging the machine, and drops privileges when possible. A typical system unit places the binary under /usr/local/bin/mihomo, passes -d /etc/mihomo (or --config if you prefer a single file path), and relies on CapabilityBoundingSet plus AmbientCapabilities to grant CAP_NET_ADMIN and optionally CAP_NET_BIND_SERVICE. Avoid running as root unless your distribution’s packaging standards require it; a dedicated mihomo user with constrained file permissions is easier to audit.

[Unit]
Description=Mihomo Clash.Meta daemon
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
User=mihomo
Group=mihomo
ExecStart=/usr/local/bin/mihomo -d /etc/mihomo
Restart=on-failure
RestartSec=3
AmbientCapabilities=CAP_NET_ADMIN CAP_NET_BIND_SERVICE
CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_BIND_SERVICE
NoNewPrivileges=yes

[Install]
WantedBy=multi-user.target

Hardening blocks vary by distribution—some admins add ProtectSystem=strict with writable state paths; others keep the unit minimal to reduce friction. After installing the unit file under /etc/systemd/system/mihomo.service, run systemctl daemon-reload, then systemctl enable --now mihomo. Follow output with journalctl -u mihomo -b and confirm you see listener lines without repeated crash loops.

Capability alternative: some admins prefer setcap cap_net_admin,cap_net_bind_service+ep /usr/local/bin/mihomo and drop ambient caps from the unit—choose one model and document it for your fleet.

Desktop reality: one policy for Chromium, Firefox, and terminals

With TUN enabled and routes installed, most desktop applications inherit the same policy as long as they use the system network stack normally. Chromium-based browsers generally need no extension-level proxy toggles; Firefox may still have its own proxy UI—set it to system defaults so you do not create a double-proxy paradox. Terminal tools such as curl, wget, and language package managers typically “just work,” which is the productivity win you are buying compared with exporting HTTP_PROXY in every shell profile.

Some containers and sandboxes use separate network namespaces; they will not magically inherit host TUN unless you design for that. Flatpak and Snap apps may also bypass expectations—treat them as separate verification targets. For Wayland versus X11, the routing story is identical; focus on namespaces and sandboxing instead of display servers.

Starter split routing: GEOIP, LAN, and MATCH

A maintainable first profile keeps domestic CDNs and private networks on DIRECT and sends the remainder to your primary proxy group. Community rule providers can accelerate setup, but read the trade-offs in our ruleset comparisons before you stack remote files you do not understand. At minimum, insert RFC1918-style IP-CIDR bypasses and a GEOIP,CN,DIRECT line ahead of your catch-all if that matches your region—ordering matters because Clash evaluates rules top to bottom.

Rule hygiene: every extra remote provider is another moving part that can fail at update time. Start lean, measure latency, then expand.

Verification checklist: routes, egress, and DNS

Verification should be boring and repeatable. Check that the TUN interface appears with ip link, inspect ip rule and ip route for entries Mihomo manages, and compare public IP seen by curl against expectations. DNS checks deserve their own pass: if domains resolve through unexpected resolvers, rule mode will look “random.” Cross-reference symptoms with the DNS guide rather than toggling TUN alone.

  1. systemctl status mihomo shows active (running) without rapid restarts.
  2. journalctl -u mihomo -n 100 contains no TLS or permission errors at steady state.
  3. curl -I https://example.com succeeds through the tunnel timeline you expect.
  4. Browser and terminal agree on egress IP for the same test URL.
  5. Disabling the service returns the machine to baseline routing without manual cleanup.

Troubleshooting: permissions, route fights, and DNS loops

“Start” succeeds but traffic ignores Mihomo: re-check capabilities, SELinux denials, and whether another VPN already owns default routes. DNS works in browser but not in CLI: systemd-resolved stubs versus Clash DNS—align according to the DNS article. High CPU with TUN: try alternate stacks, reduce logging, or simplify oversized provider lists. Works until reboot: you forgot enable on the unit or your init order starts Mihomo before DNS is ready—tighten After= dependencies.

Upstream transparency: where the binary lives versus where you download clients

Mihomo is open source; release artifacts and issue trackers live on the project’s GitHub repository, which is the right place to read changelogs, verify checksums, and follow security notices. For day-to-day graphical client installs on Linux, Windows, and macOS, continue to use our official Clash download page as the primary channel for packaged applications—keep upstream binaries for headless cores and auditing separate from end-user installer expectations. Pair downloads with the configuration documentation for shared vocabulary across GUI and YAML workflows.

Summary

A solid Linux setup chains four ideas: a verified Mihomo binary, a readable config.yaml, TUN with automatic routing for unified desktop behavior, and systemd so the service returns after every kernel update and reboot. Compared with ad hoc environment variables in every shell profile, this stack feels closer to how other network daemons are operated—predictable logs, clear ownership, and one place to adjust policy when your subscription or rule files change.

When the headless core is stable, adding richer rules or a GUI on top becomes experimentation instead of firefighting—

Download Clash for free and experience the difference

Clash on Linux Meta core

Prefer a tray icon? Grab official desktop builds from our download hub. Prefer automation? Pair this YAML-first workflow with the same Meta vocabulary across GUI and headless installs.

Official desktop builds

Linux packages alongside Windows and macOS

Same Meta core story

Profiles, groups, and TUN map to Mihomo YAML

Docs + blog depth

DNS, Subconverter, and split-routing guides

Configuration reference

Shared language across headless and GUI paths

Previous & Next

Related Reading

Linux + Mihomo + TUN

Automate Mihomo with systemd, then pick a graphical Meta client from our download page when you want a UI on the same machine.

Download Free Client