Installing Clash on Linux: Desktop Client and Command-Line systemd Service Deployment
Running Clash on Linux breaks down into two completely different routes: desktop environments favor a visual setup with a GUI client installed directly, while server environments have no graphical interface and need the core binary paired with systemd to run as a persistent service. This article walks through the install steps, directory layout, and permission notes for both routes.
Choosing between the two routes
Before doing anything, clarify one thing: "installing Clash" on Linux is not a single operation—you first need to determine which type of environment you're dealing with. Desktop Linux (Ubuntu Desktop, Fedora Workstation, various Linux Mint spins) has a window manager and system tray, making it a good fit for a graphical client where switching nodes and checking traffic is all click-based. Server Linux (cloud hosts, NAS boxes, home gateways) usually only offers an SSH connection with no desktop environment, so you're limited to a command-line-only core binary paired with a process manager to keep the proxy running in the background.
The software forms used on these two routes are entirely different: the desktop route uses a graphical client like Clash Verge Rev, built on the Tauri framework, with the mihomo core bundled inside and a visual interface for subscription management, rule editing, and traffic charts. The command-line route runs the mihomo core executable directly—no interface at all, everything driven by config files and terminal commands—then hands process lifecycle management to systemd so it comes back up automatically after a reboot.
Tip: Not sure which environment you're in? Run echo $XDG_CURRENT_DESKTOP—any output means a desktop environment is present. Machines you access via SSH from a cloud console are almost always command-line-only.
Desktop environments: installing Clash Verge Rev's deb package
Clash Verge Rev's official release provides a .deb installer for Debian/Ubuntu-based distros, currently the lowest-friction way to install on desktop Linux—no manual dependency wrangling, just double-click or install via dpkg. Here's the full process.
Step 1: Download the package for your architecture
Most Linux desktops run x86_64 (amd64), while a minority of ARM devices (certain domestic laptops, Raspberry Pi desktop kits) need the aarch64 build. Check your architecture with:
uname -m
# Output x86_64 → choose the amd64 package
# Output aarch64 → choose the arm64 package
Step 2: Install with dpkg and resolve dependencies
Once the deb package is in a local directory, run the install command. The deb package won't pull dependencies automatically—if it flags missing ones, fix them right after with apt:
sudo dpkg -i clash-verge-rev_*.deb
# If a dependency error appears, run this to auto-fix
sudo apt --fix-broken install
Once installed, the app shows up in your application menu, and a user-level background helper process gets registered to handle system proxy settings and virtual network adapter permission requests. On first launch, a graphical password prompt usually appears—this is because enabling TUN mode requires creating a virtual network interface, which needs root privileges. That's expected behavior, not an installation error.
Step 3: Configure autostart
Clash Verge Rev's settings panel has a "Launch on startup" toggle. Once enabled, the app is launched automatically at login through the desktop environment's autostart mechanism (following the .desktop file convention under ~/.config/autostart/). If the toggle doesn't seem to work, manually check whether the corresponding desktop file was generated in that directory:
ls ~/.config/autostart/ | grep -i clash
If it's missing, you can copy a desktop file from the app's install directory into that path, or simply turn the autostart toggle off and back on in the settings panel—this usually re-triggers the registration process.
Installation on other distributions
Non-Debian distros each have their own approach:
RPM-based distros (Fedora, openSUSE): the official release also provides an .rpm package, installable via sudo rpm -i or sudo dnf install pointed at the local file.
Arch-based distros: a community-maintained AUR package is available, installable with an AUR helper like yay or paru, with dependencies resolved automatically.
Other distros or portable-install scenarios: a generic AppImage build is also available—download it, grant execute permission, and run it directly with nothing written to system directories, which suits temporary testing or restricted environments.
Server environments: mihomo core + systemd deployment
Servers have no desktop environment, so there's no need—or ability—to install a graphical client. Deploying the mihomo core (the continuation of the Clash Meta project) directly is the sensible choice. The core is a single executable with very low resource usage, and pairing it with systemd lets the proxy service recover automatically after a reboot with no manual intervention.
Step 1: Plan the config directory layout
Plan the directory structure before deploying, keeping config files separate from the program binary so future core upgrades don't accidentally wipe your config:
Placing the core executable in a system-level executable directory like /usr/local/bin and keeping config files separately in /etc/mihomo is standard practice for Linux software deployment—it makes systemd management cleaner and speeds up manual troubleshooting later.
Step 2: Download the core and grant execute permission
mkdir -p /etc/mihomo
cd /usr/local/bin
# Assuming you've downloaded and extracted the core archive for your architecture into a mihomo file
chmod +x mihomo
mihomo -v # Verify it runs correctly and prints a version number
Check server architecture the same way with uname -m. Most cloud hosts are x86_64, while some budget overseas providers or ARM cloud instances (certain lightweight application servers) are aarch64—double-check before downloading, since a mismatched executable will simply error out and exit on launch.
Step 3: Prepare the config file
Place the YAML config converted from your subscription into /etc/mihomo/config.yaml and confirm the key fields are correct—especially external-controller. In a server environment, if this address is enabled and bound to 0.0.0.0, you're effectively exposing the core's control interface to the public internet, so you must set an access secret or bind it to a local address only:
external-controller: 127.0.0.1:9090
secret: "set a sufficiently complex secret"
Step 4: Write a systemd service unit
Create the service file /etc/systemd/system/mihomo.service with the following contents:
A few fields deserve explanation: -d /etc/mihomo tells the core to read config files from that directory; Restart=on-failure means the process restarts automatically if it exits abnormally, preventing a single network blip from permanently killing the proxy service; LimitNOFILE raises the file descriptor limit, since a proxy service holds many concurrent connections at once and the default system limit tends to trigger connection failures under load.
The enable command sets up the symlink for autostart on boot, so after a server reboot mihomo comes up along with the system without any manual commands. Use status to confirm the current run state—check specifically that the active (running) line looks correct.
Permission notes and verifying it works
Permission issues are the most common pitfall when deploying a proxy on Linux, so let's go through them clearly.
Permission requirements for TUN mode
If the config enables tun.enable: true, the core needs to create a virtual network interface and modify the routing table, which requires CAP_NET_ADMIN privileges on Linux. Running the systemd service as root is the simplest solution (as with User=root in the service unit above), but if you'd rather not run the proxy process persistently as root for security reasons, you can grant the capability to the executable individually with setcap and run it as a normal user instead:
After granting the capability, change User=root in the service unit to a dedicated regular user created for the proxy service, further tightening the permission scope—this is the more recommended approach for server security practices.
Read/write permissions on the config directory
If you run the service as a regular user, remember to grant that user read access to the config directory—otherwise the core will exit immediately at startup because it can't read the config file:
sudo chown -R clash-user:clash-user /etc/mihomo
Verifying the proxy is working
After starting the service, first confirm the port is listening properly:
sudo ss -tlnp | grep mihomo
Then send a request through the proxy from the command line to check whether the exit IP has changed:
If the returned IP matches the node's exit address rather than the server's own address, the proxy chain is working. In desktop environments with Clash Verge Rev, you can simply check the connection status and latency test results in the client—no need to run a manual curl check.
Note: Running mihomo on a server is usually meant to give LAN devices a shared proxy exit point, not to make the server itself route through a proxy. When configuring bind-address, be explicit about which LAN IP ranges are allowed to connect, to avoid the security risk of leaving the port open to the public internet without restriction.
Ongoing maintenance tips
Once both routes are deployed, the day-to-day maintenance focus differs slightly between them.
Desktop client side: Clash Verge Rev has a built-in subscription auto-update feature—set an update interval in the settings so you don't need to re-import subscription links manually every time; if you're juggling multiple subscription sources, rename each config profile to something recognizable at a glance to avoid accidentally switching to an expired subscription.
Command-line service side: after updating the config file, you don't need to restart the whole service—mihomo supports hot-reloading via its RESTful API, or you can simply run systemctl restart mihomo to apply changes. It's worth backing up the config directory regularly, especially if you have many custom rules, since one accidental overwrite can wipe out all your rules at once.
Also, regardless of which route you take, it's worth updating the GeoIP and GeoSite databases periodically—stale databases can cause routing rules to misfire, leading to domains that should go through the proxy bypassing it, or addresses that should connect directly getting routed through the proxy instead. See the tech note on database updates for detailed update methods and troubleshooting steps.