Why Desktop Linux Users Still Reach for Clash

Linux coverage in proxy tutorials often stops at “export http_proxy and hope for the best.” That might be enough for a one-off curl, but it does not give you rule-based splitting, resilient subscription updates, or the same mental model you already learned on Windows and macOS. On Ubuntu and other Debian-flavored desktops, Clash Linux setups are usually implemented with the mihomo core (the modern continuation of the Clash Meta line) plus either a GUI front end or a headless service managed by systemd. This article focuses on the second pattern because it matches what people search for when they type “Ubuntu + systemd + autostart”: a repeatable install, explicit file layout, and a supervised process that comes back after reboots.

You do not need to be a kernel developer. You do need basic shell literacy, patience with YAML, and the willingness to read logs when something refuses to bind a port. If you are also maintaining subscriptions for a household or a small office box under your desk, pair this walkthrough with our subscription management guide so your remote URLs stay fresh without turning into a paste-bin liability.

What This Guide Assumes (and What It Deliberately Skips)

The steps below target a generic Ubuntu 22.04 or 24.04 environment with systemd as PID 1. They work equally well on many Ubuntu derivatives, but package names and default firewall tools can differ. We will:

  • Install a single statically linked or distro-compatible mihomo binary into a predictable location.
  • Keep configuration, GeoIP databases, and cached rule bundles under one directory owned by a non-root user.
  • Import a subscription the same way most providers expect: a remote URL that expands into a list of outbounds, merged into a local config.yaml (either generated by a template or maintained by hand).
  • Create a systemd service with Restart=on-failure so transient errors do not leave you offline until someone runs a manual command.

We will not re-hash every possible TUN stack permutation on Linux; once you have the daemon stable, see the transparent-proxy discussion in our TUN mode guide for how virtual interfaces interact with DNS hijacking and strict-route-style behavior. We will, however, call out the permission and routing foot-guns that trip beginners when they jump straight to TUN without validating their base config.

Before You Touch the Binary

Collect these artifacts before you open a terminal:

  • A trustworthy subscription URL or hand-built YAML. Treat the URL like a bearer token. If it leaks into screenshots or shell history on a shared machine, rotate it with your provider.
  • Architectural awareness. Download the build that matches your machine (amd64 versus arm64). Apple Silicon-like ARM laptops and Raspberry Pi-class boards are increasingly common; grabbing the wrong archive is an avoidable five-minute detour.
  • A non-login system user (optional but recommended for servers). On a workstation, your everyday user is fine. On a headless relay, create clash with /usr/sbin/nologin and tighten directory permissions so only root and that user can read secrets.
  • Firewall intent. Ubuntu Desktop often ships with a friendly frontend to ufw. Clash’s inbound ports are localhost-facing in most configs (mixed-port on 127.0.0.1), so you rarely need to punch holes outward. If you deliberately expose the external controller or a SOCKS listener on 0.0.0.0, you must justify that threat model in writing—ideally before someone on the café Wi-Fi finds it.
If you are comparing how Clash concepts translate across operating systems, the feature overview on our features page explains the shared vocabulary (rules, strategy groups, DNS modes) without tying you to a specific GUI.

Install the Core on Ubuntu

Modern cores publish prebuilt binaries or compressed archives with checksums. You can compile from source, but most readers should not make that their first milestone. Instead, start from the maintained bundles linked on this site’s download page, which keeps the “where do I actually get the file?” question aligned with the same channel we use for other platforms—rather than sending you through a maze of abandoned GitHub forks.

A typical manual install looks like this (adjust version strings and names to match the archive you verified):

sudo install -m 0755 mihomo-linux-amd64 /usr/local/bin/mihomo
mihomo -v

If sudo is not available on your shell account, place the binary under ~/bin or ~/.local/bin and ensure that directory appears early in PATH for both your interactive shell and the systemd unit you will write later. Inconsistent PATH values between login shells and service environments are a classic reason a unit “works when I type it” but fails on boot.

Some corporate mirrors block direct GitHub releases. If downloads stall only on that network, fetch the archive elsewhere, verify its hash out of band, and copy it over with scp. The extra discipline pays off the first time you avoid running a renamed trojan masquerading as a “Clash Meta speed edition.”

Choose a Configuration Directory and Drop Initial Files

Conventionally, administrators use /etc/clash for system-wide installs and ~/.config/clash for per-user setups. Either works as long as the same account that runs mihomo owns the files. A pragmatic desktop layout might be:

mkdir -p ~/.config/clash
cd ~/.config/clash
# config.yaml, Country.mmdb, and rule providers will live here

Your config.yaml must, at minimum, define listeners (mixed-port or separate HTTP/SOCKS ports), an external-controller if you want dashboards, and either inline proxies or proxy-providers fed by remote subscriptions. If your vendor only gives you a single mega-file URL, you can still use proxy-providers with type: http and appropriate path keys so mihomo refreshes nodes on an interval—mirroring what a GUI would schedule for you automatically.

When migrating YAML from another machine, open it in a UTF-8-aware editor, strip machine-specific absolute paths, and compare deprecated keys against our mihomo migration notes. Nothing stalls a Linux onboarding faster than a silent schema mismatch that GUI editions used to paper over.

Subscription Import: Three Patterns You Will Actually See

Pattern A — GUI-assisted import: If you install a maintained Linux GUI (several mihomo front ends exist), you may never hand-edit providers. That is fine; systemd can still launch the underlying core the GUI expects. The critical part is knowing which directory ends up authoritative so you are not debugging the wrong file.

Pattern B — Remote provider entries: Ideal for servers. Your config.yaml references HTTP providers with a refresh interval and stores the expanded YAML under ~/.config/clash/providers/ or similar. Pair this pattern with the hygiene tips in the subscription article so you are not refreshing every sixty seconds like a denial-of-service cannon pointed at your vendor.

Pattern C — Manual fetch with version control: Advanced users sometimes check their static fragments into Git while keeping secrets outside the repo. That is powerful but error-prone: remember that git pull on a live box can momentarily break parsing if someone commits a half-edited file. Always run a foreground test after edits.

Prove It in the Foreground Before systemd Owns It

Run:

cd ~/.config/clash
mihomo -d .

Watch the log output. You want to see listeners bind, GeoIP or GeoSite data load, and providers refresh without TLS errors. Open a second terminal and exercise the proxy deliberately:

curl -I https://example.com
https_proxy=http://127.0.0.1:7890 curl -I https://example.com

Replace 7890 with whatever mixed-port you configured. If the first command succeeds but the second hangs, you might still be probing the wrong port or mixing HTTP versus SOCKS semantics. If both fail, your baseline connectivity—not Clash—is suspect.

Browser users on GNOME or KDE should switch the desktop proxy to “manual” with the same host and port, or use an extension that respects system settings. This is the Linux equivalent of the Windows “System Proxy” story we covered in our Windows tutorial: only software that honors those variables will traverse Clash unless you elevate to TUN.

When you are satisfied, stop the foreground process with Ctrl+C. systemd will take over next—but never skip the foreground rehearsal. Jumping straight to a detached unit turns every typo into a forensic exercise across journalctl timestamps.

Write a systemd Unit for Autostart and Restarts

We will define a user service, which keeps permissions aligned with desktop expectations and avoids running a network tunnel as root. Enable lingering so the user slice starts at boot even without an interactive login:

loginctl enable-linger $USER

Create ~/.config/systemd/user/clash.service:

[Unit]
Description=Mihomo Clash-compatible proxy core
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
WorkingDirectory=%h/.config/clash
ExecStart=/usr/local/bin/mihomo -d %h/.config/clash
Restart=on-failure
RestartSec=3
LimitNOFILE=1048576

[Install]
WantedBy=default.target

Notes worth reading twice:

  • After=network-online.target reduces race conditions on Wi-Fi or DHCP-heavy networks, though it is not a magical guarantee that every captive portal has opened.
  • Restart=on-failure implements the “keepalive” expectation without pretending crashes are healthy. Adjust to always only if you understand the risk of tight restart loops burning CPU while a bad config never gets fixed.
  • LimitNOFILE bumps file descriptors for busy rule lists and many concurrent streams; tweak if your security baseline forbids high limits.

Reload and enable:

systemctl --user daemon-reload
systemctl --user enable --now clash.service
systemctl --user status clash.service --no-pager

For a system-wide unit (headless router or shared gateway), place a file in /etc/systemd/system/clash.service, set User= and Group= to a dedicated account, point WorkingDirectory at /etc/clash, and chmod secrets accordingly. Always prefer capability tightening (AmbientCapabilities=, CapabilityBoundingSet=) over blanket root when you enable TUN-style features that require elevated networking hooks—exact capabilities vary by kernel and core build.

Observing Logs Without Losing Your Mind

User services log to the user journal. Start with:

journalctl --user -u clash.service -b -f

If you see repeated DNS resolution failures, provider HTTP 403 responses, or TLS MITM warnings, fix those upstream before blaming Ubuntu routing tables. Conversely, if startup succeeds yet clients still time out, return to the split between application-level proxy awareness and full-device TUN, because Linux desktop apps are notorious for ignoring environment variables unless launched from a shell you have carefully curated.

A Short Reality Check on TUN for Linux Beginners

TUN mode can unify traffic the way people expect “VPN software” to behave, but it also intersects with ip rule, policy routing, and occasionally nftables. If your immediate goal is “make the browser work on Ubuntu with minimal drama,” stay on mixed-port plus desktop proxy settings until the base rules behave. Once you turn on TUN, revisit DNS hijacking: a loop where Clash queries itself through a tunnel that is not yet up can masquerade as “the Internet broke” when in reality you trapped resolvers. The linked TUN guide unpacks those interactions in more depth than this Ubuntu checklist can afford.

Troubleshooting the Failure Modes We See Most Often

Permission Denied on Config or Provider Files

systemd runs with a clean environment and strict ownership expectations. If your subscription downloader wrote root-owned files into ~/.config/clash, the user service cannot read them. Fix with chown -R or regenerate providers under the correct account.

Address Already in Use

Another leftover mihomo instance, Docker port publishing, or an IDE’s embedded proxy may occupy 7890 or your controller port. Use ss -lntp to locate the process, then either stop the conflict or reassign ports consistently across your YAML and your desktop proxy settings.

Domestic Sites Fast, International Sites Hang

Symptom clusters like this often implicate DNS: Clash may be routing TCP fine while resolvers never return addresses your rules can act on. Revisit your dns section, ensure you are not mixing fake-ip semantics with applications that insist on real records, and temporarily test with a well-known resolver to isolate upstream filtering. For YAML specifics, the DNS chapters in our documentation hub describe how each mode is supposed to behave when the network is imperfect.

Mandatory Access Controls on Hardened Images

Ubuntu defaults are relatively relaxed, but derivatives or custom images may ship AppArmor profiles that block unfamiliar binaries from touching /dev/net/tun. Symptoms show up in audit logs rather than Clash’s own UI. If you operate under such constraints, engage whoever maintains the image before improvising broad disables.

Operational Security Habits That Cost Nothing

Bind the external controller to 127.0.0.1 unless you have an affirmative reason to expose it, and always set a non-empty secret if something else on the machine might speak the REST API. Rotate subscription URLs after you suspect clipboard leaks, and never leave world-readable permissions on directories that hold provider caches—systemd’s user slice should still follow sensible umask discipline.

Compared with cobbling together random shell scripts that spawn screen sessions, a well-tested Linux client wrapping the same mihomo releases you run headless usually delivers faster upgrades, clearer dashboards, and fewer “works until reboot” stories. Pick the approach that matches how hands-on you want to be, but keep the configuration directory as the single source of truth either way.

From Zero to Reliable Ubuntu Autostart

If you followed each checkpoint—verified binary, coherent config path, successful foreground run, and a systemd unit with sane restart semantics—you now have the Linux counterpart to the polished autostart story Windows users get from GUI installers. The platform asks more of you upfront, but the payoff is transparency: every behavior is visible in YAML and logs, and your machine repeats the same startup sequence after every kernel update instead of hiding state in undocumented tray icons.

Compared with ad hoc proxy scripts, a maintained Clash-class stack gives you consistent rule evaluation across laptops, desktops, and tiny always-on boxes, so you spend less time re-learning divergent tooling on each device. When you are ready to standardize installs without chasing stray archives, consolidate downloads through one trusted entry point and reuse the same documentation you already trust for other operating systems.

→ Download Clash for free and experience the difference once your Ubuntu service is stable and you want matching clients on the rest of your hardware.