1. Why Pair Clash Meta with systemd on Ubuntu
Most people discover Clash through glossy desktop clients on Windows or macOS, where a tray icon hides complexity. On Ubuntu, it is tempting to run the core binary inside a terminal tab, watch colored logs scroll forever, and call it a day. That approach works until you close the laptop lid, detach from SSH, or reboot after a kernel update—then your tunnel disappears and every application that depended on a local HTTP or SOCKS port suddenly behaves as if the internet “half works.” Moving the same Clash Meta workload under systemd fixes those lifecycle problems in one place: the service manager already understands dependency ordering, restart semantics, journal logging, and security hardening primitives that are tedious to reinvent in shell scripts.
Another reason administrators reach for systemd is observability. When something fails at two in the morning, you want systemctl status to tell you whether the binary exited, whether systemd already attempted a restart, and whether the last error message landed in the journal. Compared with nohup-style background jobs, that operational clarity is not glamorous, but it is the difference between a five-minute fix and an hour of guessing which terminal window still owns port 7890. For a lightweight server that only exists to forward developer traffic, boring reliability beats clever one-liners.
Finally, treating mihomo as a first-class daemon makes it easier to separate concerns. Your YAML profile, rule providers, and GEOIP databases live in a dedicated directory with explicit ownership, while desktop applications simply point at a stable local endpoint. That separation mirrors how you would deploy any other network service on Linux—and it keeps your mental model consistent when you later add firewall rules, split DNS, or optional TUN mode for full-device capture.
2. Prerequisites and Naming Notes (mihomo vs Clash Meta)
This article assumes a recent Ubuntu LTS or non-LTS release on amd64 or another architecture supported by upstream builds. You need sudo access, outbound HTTPS to fetch packages and subscription endpoints, and enough disk space for configuration files plus occasional rule-provider caches. If you plan to manage the daemon over SSH, confirm that your remote session uses key-based authentication and that you are comfortable editing files under /etc with sudoedit or an editor that respects root-owned permissions.
Terminology deserves a short pause. The ecosystem still says “Clash Meta” in conversation, but the actively maintained core is commonly distributed under the name mihomo. Think of mihomo as the engine: it reads config.yaml, applies modern rule features, and exposes mixed-port listeners. GUI clients on other platforms wrap that same engine with buttons and charts; on Ubuntu you are often interacting with the binary directly, which is why clarity around the executable name matters when you write systemd units. If you skim release assets quickly, look for packages that match your CPU architecture and prefer signed or checksum-verified downloads when your threat model demands it.
Before you install anything, decide whether this machine is primarily a personal workstation or an always-on gateway. Workstations may prefer a user-scoped configuration under ~/.config with a user systemd unit, while gateways usually centralize files under /etc/mihomo with a system unit. The steps below emphasize the system-wide layout because it maps cleanly to boot auto-start for shared use, but you can translate the same ideas to a user service if you dislike root-owned configs.
3. Install from a Debian Package on Ubuntu
The most straightforward deb install story on Ubuntu is to download a .deb built for your architecture from the upstream release page, then let APT resolve dependencies. A typical workflow looks like this: move the file into a temporary directory, run sudo apt install ./mihomo_*.deb (note the ./ prefix, which tells APT to treat the path as a local package), and verify that the binary landed on your PATH. If the release ships only a compressed tarball instead of a .deb, extract the binary to /usr/local/bin, mark it executable, and skip ahead—the systemd section still applies; only the packaging step changes.
After installation, confirm the executable name with which mihomo or command -v mihomo. Some community packages install a compatibility symlink so that scripts expecting clash-meta still resolve. Consistency matters because your unit file’s ExecStart line must reference the real path that dpkg recorded. If you maintain multiple versions side by side for experiments, avoid shadowing the system binary in confusing ways; instead, use explicit paths such as /opt/mihomo/bin/mihomo and update the unit accordingly.
When you curate installers for everyday use, prefer maintained bundles that track the broader ecosystem. The download hub on this site centralizes desktop-oriented clients for other platforms; on Ubuntu you may still pair a manually installed mihomo core with a separate UI later, but the habit of pulling binaries from a transparent, versioned channel remains valuable. If you need to read release notes or verify checksums, the upstream open-source repository is linked in a dedicated note at the end of this article so it does not compete with the installer call-to-action.
4. Configuration Directory, config.yaml, and Permissions
mihomo expects a directory that contains config.yaml (and often additional assets such as GEOIP databases or rule-provider caches). For a system deployment, create something like /etc/mihomo, place your main profile at /etc/mihomo/config.yaml, and tighten permissions so that ordinary users cannot silently rewrite outbound rules. A pragmatic pattern is root:root ownership with 0640 on the YAML file if only root should edit it, or a dedicated mihomo system user if you want the daemon to drop privileges after start.
If you already maintain a subscription URL, import it into config.yaml using the same mental model as other Clash guides: define proxies, anchor policy groups, and order rules so that domestic destinations can still hit DIRECT when appropriate. Newcomers who need a refresher on URL imports can follow the dedicated subscription import tutorial before returning here to wire the service. Remember that systemd will not magically fix a malformed profile; validate your YAML with a manual foreground run first: sudo mihomo -d /etc/mihomo, watch for parser errors, then interrupt with Ctrl+C once connectivity checks succeed.
Logging deserves a conscious choice. Many operators symlink or point logs to /var/log/mihomo, but systemd already captures stdout and stderr into the journal when you use the simple service type. Pick one primary destination to avoid duplicate rotation policies. If you enable verbose debugging for a short investigation, remember to dial verbosity back afterward so your journal does not grow noisy enough to obscure real incidents.
5. Author a systemd Unit for mihomo
Create a unit file at /etc/systemd/system/mihomo.service. The example below assumes the binary lives at /usr/bin/mihomo and the configuration directory is /etc/mihomo. Adjust paths to match dpkg -L output on your machine. The -d flag tells mihomo which directory to treat as its home for config.yaml and runtime files.
# /etc/systemd/system/mihomo.service [Unit] Description=mihomo (Clash Meta) proxy daemon After=network-online.target Wants=network-online.target [Service] Type=simple ExecStart=/usr/bin/mihomo -d /etc/mihomo Restart=on-failure RestartSec=5 LimitNOFILE=1048576 [Install] WantedBy=multi-user.target
The After=network-online.target stanza reduces races where the daemon starts before DNS or routing is fully settled—especially on Wi-Fi laptops that negotiate DHCP in the background. It does not magically solve every corporate captive portal scenario, but it removes a common foot-gun on home networks. LimitNOFILE bumps the open-file ceiling, which helps under heavy connection churn; tune or drop it if your environment enforces stricter ulimit policies.
Hardening blocks such as ProtectSystem, ProtectHome, or CapabilityBoundingSet are available for advanced users, but they interact with where you store databases and whether you enable TUN. Start with a minimal unit, prove stability, then iterate. Nothing undermines trust in automation faster than a service that refuses to start because systemd blocked a legitimate write to a cache directory you forgot to whitelist.
6. Enable on Boot, Verify Status, and Read Logs
Reload systemd so it notices the new unit: sudo systemctl daemon-reload. Start the service once manually with sudo systemctl start mihomo, then inspect sudo systemctl status mihomo --no-pager. You should see an active (running) line and the main PID. If the status instead shows a failed state, copy the error text immediately; it often points to a bad path, a YAML typo, or a permission mismatch on the configuration directory.
Enable boot integration with sudo systemctl enable mihomo, which creates the expected symlink under /etc/systemd/system/multi-user.target.wants. Reboot once as a sanity check, then confirm the service came back: systemctl is-active mihomo should print active. For logs, prefer journalctl -u mihomo -e for a pager-friendly stream, or journalctl -u mihomo --since "10 minutes ago" when you are correlating incidents with other system events.
Quick connectivity checks from the same host include curling through the mixed port if you exposed one in your profile, or verifying that a browser pointed at the local HTTP proxy can load an international test page. If only some applications work, the issue may be split between application-level proxy settings and your Clash rules—our routing and rules reference explains how rule order interacts with policy groups so you do not chase ghosts in systemd when the real mismatch lives in YAML.
7. Crash Recovery, Restart Policies, and Ordering
The example unit uses Restart=on-failure, which is appropriate when you want systemd to resurrect the daemon after a non-zero exit code but not necessarily after a clean stop request. Operators who expect frequent OOM kills or flaky dynamic libraries may switch to Restart=always with a sane StartLimitIntervalSec guard to avoid tight crash loops thrashing the CPU. Combine restart policies with health awareness at the proxy layer: if your upstream subscription goes stale, the process might stay alive while applications fail differently—monitor external endpoints, not only the PID field in systemctl.
Ordering ties into real-world networking stacks. If you run local DNS stacks such as systemd-resolved, Unbound, or dnsmasq, ensure your Clash DNS section does not fight them for the same listening address. A common pattern is to let mihomo bind its DNS inbound on a high loopback port and forward queries explicitly, rather than assuming ownership of port 53 unless you truly intend to be the resolver for the entire OS. Document whichever pattern you choose; six months later, future you will not remember why port 53 seemed “free” on Tuesday.
For multi-user machines, communicate maintenance windows when you reload units. A brief systemctl reload is not always available for every daemon flag; sometimes a full restart is necessary, which drops in-flight connections. If that disruption is unacceptable, schedule changes during idle periods or keep a parallel staging profile that you validate offline before swapping filenames.
8. Desktop Integration: HTTP Proxy and Terminal Workflows
Running the core under systemd solves background longevity, but your Linux desktop proxy experience still depends on how individual apps route traffic. GNOME and KDE offer graphical proxy panels; browsers often respect environment variables such as http_proxy and https_proxy when launched from a shell that exports them. Terminal multiplexers and IDEs sometimes inherit a login shell profile, sometimes not—if curl works in one window and fails in another, compare env | grep -i proxy between the two sessions before you blame Clash.
Container engines and language-specific tools frequently ignore global desktop settings entirely. Docker, for example, may require a daemon-level HTTP proxy configuration, while Rust or Node tooling might need vendor-specific environment variables. The Clash side should present a stable local listener; the application side must be taught to use it. Treat that split as a feature: your YAML governs how traffic exits the machine once it reaches mihomo, while each toolchain’s documentation governs how it discovers a proxy on localhost.
On shared workstations, consider creating a concise README in your system documentation folder that lists the mixed port, SOCKS port, and any authenticated controller endpoint. Even if you are the only user today, that note prevents accidental exposure of a management API when you later tweak firewall rules or expose services on LAN for testing.
9. Optional: TUN Mode and Linux Capabilities
HTTP and SOCKS listeners cover many developer workflows, yet some users eventually enable TUN mode to capture broader traffic without per-app proxy settings. On Linux, that path often implies elevated capabilities such as CAP_NET_ADMIN so the process can manipulate virtual interfaces. systemd can grant ambient capabilities via unit directives, but doing so raises your security review burden: any vulnerability in the core becomes more sensitive when the process can affect routing tables at a low level.
If you decide to pursue TUN, read the upstream documentation for the exact keys your profile version expects, then validate with short foreground runs before you bake assumptions into a headless unit. For conceptual background on when TUN matters versus application proxies, the TUN mode overview on this site frames the trade-offs in client-agnostic language that still applies to Ubuntu hosts.
When experimenting, keep a rollback plan: a known-good YAML without TUN stanzas, a disabled unit override directory, and a reminder that misconfigured routing can lock you out of SSH if you push everything through a broken exit. Always maintain a secondary path to the machine—out-of-band console, physical access, or a firewall rule that preserves management connectivity—before you radically change default routes.
10. Troubleshooting Common Ubuntu Pitfalls
“systemctl says active but nothing connects.” Check whether your listeners bind to 127.0.0.1 only, whether another process seized the same port, and whether your applications actually target that port. Use ss -lntp as a quick inventory. Also revisit DNS settings inside your profile: fake-ip modes interact with local resolvers in ways that can look like “the tunnel is down” when the tunnel is fine but name resolution is not.
“The service starts, then exits immediately.” Inspect journalctl -u mihomo -b for stack traces or YAML parse errors. foreground-run the binary with the same -d path to reproduce interactively. Watch for SELinux or AppArmor only if your distribution enforces profiles; stock Ubuntu Server and Desktop setups differ.
“Everything worked until reboot.” Confirm you actually ran systemctl enable, verify the unit file is still present, and ensure no conflicting legacy startup script launches a second copy that fights over ports. A quick systemctl list-units | grep -i mihomo helps detect duplicates.
Security reminders. Avoid exposing the external-controller socket to untrusted networks without authentication. Prefer loopback binds and SSH port forwarding for remote administration. Firewall untrusted interfaces if the machine roams across coffee-shop Wi-Fi. Technical tooling is neutral; deployment choices are not.
11. Closing Thoughts
Installing Clash Meta on Ubuntu is only half the story; the durable part is how you operate it. A clean deb-based deployment, a well-owned configuration directory, and a thoughtful systemd unit turn the mihomo core into infrastructure you can reason about: start ordering after the network is live, restart intelligently after failures, and return automatically on boot without babysitting terminals. Compared with ad hoc background jobs, that structure is calmer to troubleshoot when DNS, rules, or upstream endpoints misbehave—and calmer troubleshooting is what keeps a Linux desktop proxy in the “invisible helper” category instead of the “fragile script I fear to touch” category.
When you are ready to align installers across the devices you actually carry day to day, consolidating on a transparent download surface beats chasing random mirrors that may lag behind security fixes. The open-source engine remains auditable on GitHub for readers who want source-level assurance—see the note below—while day-to-day packages should still flow through the same curated entry points you trust for the rest of your toolchain.
Upstream source code and release artifacts for the mihomo core are maintained in the MetaCubeX/mihomo repository on GitHub. That link is provided for transparency and changelogs; for everyday client bundles and cross-platform picks, continue to use this site’s download flow rather than treating GitHub as the primary installer channel.
If you want maintained builds and a single place to compare ecosystem options before you commit YAML to disk, browse the official download hub after you finish hardening your Ubuntu service. Compared with juggling stray archives, that approach keeps versions legible across machines and makes it easier to recreate the same logical setup when you inevitably migrate to a new laptop. → Download Clash for free and experience the difference
Related Reading · topic cluster
Hand-picked deep-dives on the same topic — practical Clash routing guides in the same category.
Install Clash Meta on Debian 12: Binary Install, Systemd, and Mixed-Port First Setup (2026)
Debian 12 Bookworm: install mihomo (Clash Meta) from an audited upstream binary, place config under /etc/mihomo, set mixed-port and subscriptions, enable system…
Read moreInstall Clash Meta on Arch Linux: systemd Auto-Start and First Setup (2026)
Arch or Manjaro: install mihomo with yay/paru (AUR) or a manual binary, use systemd (system or user) for boot, set mixed-port, import subscriptions, and keep pa…
Read moreInstall Clash Meta on Fedora: systemd Boot Setup and Mixed Port First Steps (2026)
Fedora Workstation or RHEL-like desktop: install mihomo without Ubuntu deb habits, place config under /etc/mihomo, wire systemd for boot and crash recovery, set…
Read more