Why desktop Linux needs an explicit always-on plan
On Windows and macOS, users are used to installers that register background services and tray icons that respawn after logout. Linux desktops are more fragmented: a Flatpak might sandbox the config path, an AppImage might live entirely in your home directory, and a distribution package might expect /etc while your GUI wrote to ~/.config. The symptom is always the same—you reboot, log back in, and traffic stops flowing because nothing relaunched the mihomo core that powers Clash Meta.
The fix is not heroic shell scripting at login. It is to treat the proxy core like any other network daemon: give it a stable working directory, a single source of truth for config.yaml, and a systemd unit (user-scoped or system-scoped) with sane restart rules. Your graphical client then becomes an editor and status panel, while systemd guarantees the process is present before you open the browser. If you are migrating from an older stack, skim our Clash Meta upgrade guide first so naming and rule syntax line up with current expectations.
How the pieces fit together
Clash Meta is the family of cores descended from the original Clash design, with modern protocols and richer routing. mihomo is the actively maintained core you will run on Linux today. A desktop client (for example Clash Verge Rev, Mihomo Party, or another Qt-based shell) typically embeds or shells out to that core, manages subscriptions, and exposes TUN or system-proxy toggles.
You can run in two coherent modes:
- GUI-led: the application owns the lifecycle of the core. This is fine until the app does not start on boot, crashes quietly, or updates and moves binaries.
- systemd-led: systemd starts mihomo directly; the GUI attaches to an API port or supervises the same binary. This is the pattern that survives reboots and unattended desktops.
Most readers will blend both: keep the GUI for editing, but let systemd start the daemon. The critical detail is to point both layers at the same directory so you never edit one file while the running process reads another. For routing theory once the daemon is up, the YAML routing walkthrough explains groups, rule order, and DNS modes in depth.
Preparing Debian or Ubuntu desktop
Install baseline tooling you will need for troubleshooting and for downloading official bundles:
sudo apt update
sudo apt install -y curl ca-certificates iptables dnsutils
If you plan to use TUN mode (transparent forwarding for the whole system), ensure kernel modules and permissions are available. Many desktop kernels already ship tun; verify with lsmod | grep tun after first use. Some distributions also expect ip and iptables or nftables compatibility layers—install whatever meta-package your release documents for “network tools.”
Create a dedicated configuration directory instead of scattering files. A common choice is ~/.config/mihomo for personal machines or /etc/mihomo if multiple users must share one profile. Pick one and stay consistent; the systemd unit examples below assume ~/.config/mihomo with config.yaml at the root of that folder.
Installing a maintained Mihomo-class desktop client
Grab a client that tracks recent mihomo releases and publishes Linux artifacts you can audit—typically .deb, .AppImage, or tarball builds. Install according to upstream instructions; avoid random repackaged binaries without checksums. After installation, open the client once, import your subscription or paste a starter profile, and confirm the core starts and listens on the expected mixed port (often 7890 for HTTP/SOCKS unless you changed it).
Before you wire systemd, note which path the GUI writes for config.yaml. Some clients mirror profiles under their own application ID inside ~/.config. That is acceptable only if your unit uses the identical path. If the GUI copies YAML into a cache directory on every launch, point systemd at the cache or change the GUI setting so the “working directory” is explicit.
Where possible, disable the GUI option that “kills the core on exit” while you transition to systemd supervision—otherwise you will fight duplicate processes. Many clients offer an external-controller port; keep it bound to 127.0.0.1 and protect it with a secret token in YAML.
systemd user service (recommended for single-user laptops)
A user unit runs in your session context, respects your home directory permissions, and avoids sprinkling root-owned files across /etc. Enable lingering so the service can start at boot without an interactive login:
sudo loginctl enable-linger $USER
Create the unit file ~/.config/systemd/user/mihomo.service:
[Unit]
Description=Mihomo (Clash Meta) daemon
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
WorkingDirectory=%h/.config/mihomo
ExecStart=%h/.local/bin/mihomo -d %h/.config/mihomo
Restart=on-failure
RestartSec=3
LimitNOFILE=1048576
[Install]
WantedBy=default.target
Adjust ExecStart to the real binary location—some users symlink the extracted binary into ~/.local/bin/mihomo. Reload units, enable, and start:
systemctl --user daemon-reload
systemctl --user enable --now mihomo.service
systemctl --user status mihomo.service
If the client also tries to spawn mihomo, choose one supervisor. The cleanest approach is to let systemd own the process and configure the GUI to “connect to existing core” if such a mode exists; otherwise stop the GUI’s auto-start toggle after verifying the unit works.
systemd system service (shared machines and fixed paths)
For workstations managed like small servers—where the proxy must exist before any desktop session—use a system unit under /etc/systemd/system/mihomo.service:
[Unit]
Description=Mihomo (Clash Meta) system daemon
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=mihomo
Group=mihomo
WorkingDirectory=/etc/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=true
[Install]
WantedBy=multi-user.target
Create a dedicated mihomo user, place configuration under /etc/mihomo with appropriate ownership, and tighten file permissions on config.yaml because it may contain API tokens. Hardening details vary by distribution; the important part is that the service user can read the profile and create the TUN interface if you enable that mode.
Reload and enable globally:
sudo systemctl daemon-reload
sudo systemctl enable --now mihomo.service
sudo systemctl status mihomo.service
TUN mode, capabilities, and security trade-offs
TUN is convenient because applications do not need explicit proxy awareness, but it requires capability to manipulate network interfaces. The sample system unit adds CAP_NET_ADMIN; user services may inherit enough privileges on some desktops and fail on others. If activation fails, read the journal: journalctl --user -u mihomo.service or the system-wide equivalent.
When TUN is not worth the complexity, fall back to system proxy mode and let the desktop environment apply http_proxy variables. That path cooperates better with sandboxed Flatpaks, though it is less universal than a tunnel interface. Pick the mode that matches how your applications are packaged; there is no single winner for every Linux desktop.
Verification checklist after reboot
- Confirm the unit is active:
systemctl --user is-active mihomo.serviceor the system variant. - Hit a health-check URL through the mixed port:
curl -x http://127.0.0.1:7890 https://www.cloudflare.com/cdn-cgi/trace(adjust port to match your YAML). - Open your GUI and ensure it shows the same node list and logs as before; if it appears disconnected, align API ports and secrets.
- Watch DNS behavior: misconfigured
dnssections cause “everything times out” even when TCP proxying works; revisit the YAML guide linked above if lookups loop.
Operational habits that keep the setup boring
Snapshot config.yaml before major edits. Keep subscription URLs out of shell history when possible. Schedule updates for the desktop client and the mihomo binary together—version skew is a common source of obscure protocol errors. When traveling, test suspend/resume: if Wi-Fi reconnection races the proxy, add a small RestartSec backoff or hook network-online.target dependencies more explicitly.
Document your ports in a plaintext note: mixed port, SOCKS, external-controller, and any redir ports for TUN. Future you—or a roommate debugging the box—will appreciate not having to grep YAML at midnight.
If you dual-boot or share the machine, consider separate profiles per user rather than one global /etc/mihomo tree. Personal units under systemd --user isolate credentials naturally, while system-wide installs are better when the proxy is a shared office resource with a known maintenance owner.
Troubleshooting quick reference
| Symptom | Likely cause | What to try |
|---|---|---|
| Service starts then exits immediately | Invalid YAML path; missing binary; permission denied on profile | Run status with -l; validate file ownership; test ExecStart manually in a shell |
| GUI shows connected but browser is direct | System proxy not applied; different ports; bypass rules | Align proxy env vars; confirm bypass list; verify rule order in YAML |
| TUN fails to create interface | Missing capability; conflict with NetworkManager; seccomp profile | Check journal; add capabilities; disable conflicting legacy tools temporarily to test |
| Works until reboot | User unit without linger; GUI-only autostart; duplicate supervisors racing | Enable linger; disable GUI auto-launch; ensure single systemd owner |
| High CPU after sleep | Stale file descriptors; DNS loops; excessive rule-set polling | Restart service; inspect DNS section; increase provider intervals sensibly |
Closing: make reliability the default feature
Linux rewards explicit design. A polished Mihomo desktop client gets you productive on day one, but systemd is what makes the same Clash Meta stack feel as dependable as any commercial VPN client after every kernel update and unexpected reboot. Keep one config directory, one supervisor, and a short verification routine, and the proxy stops being something you “turn on” and becomes part of the machine baseline.
Compared with piecing together random scripts from forums, this layout stays readable six months later and plays nicely with standard tools like journalctl. When you are ready to pick an up-to-date build without hunting mirrors, use our download page to choose a maintained client for your platform. → Download Clash for free and experience the difference.