Install Clash on Linux: Desktop Clients, the mihomo CLI, and systemd Deployment
Covers desktop distributions and headless servers, including configuration paths, service startup, log inspection, and proxy environment variables.
Choose a deployment method and identify the CPU architecture
On Linux, “installing Clash” usually means choosing between two approaches. A desktop setup uses a graphical client to manage the core, subscriptions, system proxy, and policy groups. It suits distributions with a desktop environment, such as Ubuntu, Debian, Fedora, and Arch Linux. A command-line setup runs the mihomo core directly and uses systemd to supervise the process. This is better suited to servers, software routers, development machines, and headless devices.
Both approaches perform the same core tasks: read YAML configuration, listen on local proxy ports, select policies according to rules, and forward connections to the configured nodes. The main difference is how they are managed. A graphical client provides subscription updates, policy switching, and a log window; a command-line deployment requires you to maintain the configuration directory, service permissions, logs, and update process yourself.
For Linux command-line deployments, mihomo is generally the actively maintained choice. It originated from the Clash Meta branch and supports common Clash rules, policy groups, proxy providers, DNS, and TUN settings. When migrating an older configuration, do not rely on the file extension alone. Check whether its rule types, script fields, DNS options, and experimental features are supported by the current core.
Check the CPU architecture before downloading. The architecture in the package name must match the system; the distribution name alone is not enough. Run the following command to see the architecture reported by the kernel:
uname -m
getconf LONG_BIT
| Command output | Common package identifiers | Typical devices |
|---|---|---|
x86_64 |
amd64 or x86_64 |
Most Intel and AMD desktops and servers |
aarch64 |
arm64 or aarch64 |
64-bit ARM servers and development boards |
armv7l |
armv7 |
Some 32-bit ARM devices |
Install a graphical client on a desktop distribution
Desktop users should choose a client that is still maintained and explicitly provides a Linux build. Common distribution formats include AppImage, Debian packages, and RPM packages. When choosing a format, verify the architecture, desktop environment, and application release notes together. Graphical clients usually store user configuration in an application data directory under the home directory, rather than in the system-wide /etc directory.
Install with AppImage
AppImage is a single-file application format suited to desktop environments where you do not want to modify system package sources. After downloading the file for your architecture, make it executable and launch it from a terminal. The example below assumes the package is in the current user’s Downloads directory; use the actual filename from the download:
cd "$HOME/Downloads"
chmod +x Clash*.AppImage
./Clash*.AppImage
If it launches from a terminal but nothing happens when double-clicked in the file manager, read the startup error in the terminal. Some distributions require a working FUSE runtime; some AppImage files can also run after being extracted. Do not launch a desktop client with sudo unless you understand its source and permission implications. Otherwise, configuration may be written to root’s home directory, leaving the regular user with “missing configuration” errors or files they cannot edit.
DEB and RPM packages
Debian, Ubuntu, and their derivatives can install the corresponding DEB package. Using APT to install a local file also handles dependencies declared by the package:
sudo apt install ./client-filename.deb
Distributions in the RPM ecosystem, including Fedora and Rocky Linux, can install a local package with DNF:
sudo dnf install ./client-filename.rpm
After installation, launch the client from the application menu and import a subscription or local YAML file. The subscription URL should come from the service provider. In a client, “update subscription” usually means downloading the configuration again; it does not update the client or proxy core. Confirm these three update processes separately.
First checks on the desktop client
- On the configuration page, confirm that the subscription has been parsed into nodes and policy groups.
- Open the logs and verify that the listening ports were created successfully.
- Select the policy node you want to use so the policy group is not left on an unavailable option.
- Choose system proxy or TUN according to the traffic you need to route. Do not enable TUN without authorization.
- After closing the client, check whether the system proxy has been restored so the desktop environment does not retain a dead local port.
GNOME, KDE, and Xfce do not handle tray icons and system proxy settings in exactly the same way. A missing tray icon does not necessarily mean the core has stopped; check the process, listening ports, and logs together. In Wayland sessions, window and tray implementations may also be affected by desktop extensions and packaging choices.
Install the mihomo command-line core
A headless server does not need a desktop client. A practical directory layout has three parts: place the executable in /usr/local/bin, store configuration in /etc/mihomo, and send runtime logs to the systemd journal. This keeps upgrades from overwriting configuration and makes permission management consistent.
Create the configuration directory first. Then move the downloaded and extracted binary that matches the current architecture into its target location:
sudo install -d -m 0750 /etc/mihomo
sudo install -m 0755 mihomo /usr/local/bin/mihomo
/usr/local/bin/mihomo -v
If the version command prints normally, the binary can at least run on the current system. If you see Exec format error, check the CPU architecture first. If the file is reported missing even though the path exists, also verify that the archive was fully extracted, required dynamic linking support is available, and the file is not on a mount point that disallows execution.
Before creating the service, run one foreground startup test. Save the configuration as /etc/mihomo/config.yaml, then run:
sudo /usr/local/bin/mihomo -d /etc/mihomo
-d specifies the working directory. The core reads the main configuration from this directory and may store caches, rule data, or other runtime files there. Foreground startup makes YAML parsing errors, port conflicts, rule download failures, and DNS initialization problems easy to see. After confirming that it runs correctly, press Ctrl+C to stop it and switch to systemd.
Configuration directories, subscriptions, and a minimal startup configuration
A subscription usually returns a complete YAML file, but it may also return a server-transformed configuration. Before saving it, confirm that the response is actually configuration text rather than a login page, error message, or access-verification page. If you write HTML directly to config.yaml, the core will report a parsing error at startup.
The configuration below illustrates the basic relationship between local ports and the controller interface; it is not a complete subscription. Actual proxy nodes, policy groups, and rules should come from a valid configuration:
mixed-port: 7890
allow-lan: false
mode: rule
log-level: info
ipv6: false
external-controller: 127.0.0.1:9090
secret: "Set a password for local administration only"
dns:
enable: true
listen: 127.0.0.1:1053
ipv6: false
proxies: []
proxy-groups: []
rules:
- MATCH,DIRECT
mixed-port accepts both HTTP and SOCKS5 proxy connections, making it convenient to configure command-line tools consistently. allow-lan: false prevents devices on the local network from using the proxy. If LAN access is genuinely required, configure the listening address, firewall rules, and access boundaries together rather than simply enabling this switch.
external-controller is the control interface, not a regular proxy port. If you need to use a dashboard, restrict its listening scope and set secret. Exposing the controller on every network interface expands the management surface; on servers, listen on the loopback address first and access it through a controlled management channel.
After obtaining the configuration from a subscription, back up the existing file before replacing it atomically. Check file permissions before reloading the core:
sudo cp /etc/mihomo/config.yaml /etc/mihomo/config.yaml.bak
sudo chown root:mihomo /etc/mihomo/config.yaml
sudo chmod 0640 /etc/mihomo/config.yaml
If the service account needs to write caches or download rule sets in the configuration directory, the directory’s group must allow those operations as well. Overly restrictive permissions prevent providers from updating; inconsistent permissions often lead to the familiar difference between a successful manual launch and a failed systemd launch.
Run mihomo under systemd
systemd can start the core at boot and centrally handle restarts, status, and logs. Create a low-privilege system user first. The account does not need a login shell or a home directory:
sudo useradd --system --no-create-home --shell /usr/sbin/nologin mihomo
sudo chown -R mihomo:mihomo /etc/mihomo
Write the following service unit to /etc/systemd/system/mihomo.service. This basic version works for HTTP, SOCKS, and rule-based routing. If TUN is enabled in the configuration, additional network capabilities and device permissions are required.
[Unit]
Description=mihomo proxy service
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=5
LimitNOFILE=1048576
[Install]
WantedBy=multi-user.target
After saving the file, reload the systemd configuration, start the service, and enable it at boot:
sudo systemctl daemon-reload
sudo systemctl enable --now mihomo
systemctl status mihomo --no-pager
Use journalctl to inspect logs. For the first startup, review the full recent log; while troubleshooting continuously, follow new output instead:
journalctl -u mihomo -n 100 --no-pager
journalctl -u mihomo -f
After changing the YAML, run sudo systemctl restart mihomo. It is best to test a copy in the foreground first so a syntax error does not interrupt the service. If you only changed a policy selection from a subscription, also confirm whether the client or dashboard stores that choice in a cache rather than writing it back to the YAML.
systemd permissions for TUN mode
TUN creates a virtual network interface and changes routes, so it needs more network privileges than a regular local proxy. Add capability restrictions in the service unit’s [Service] section; this is easier to control than running the entire service as root indefinitely:
AmbientCapabilities=CAP_NET_ADMIN CAP_NET_RAW
CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_RAW
Also confirm that /dev/net/tun exists, the kernel module is available, and the service account can access the device. Containers and restricted virtual machines additionally need the host platform to permit the TUN device and network-management capabilities. Enabling TUN in the configuration does not mean the runtime environment already provides these conditions.
systemd security policies, SELinux, or AppArmor rules may further restrict network operations depending on the distribution. Treat permission denied in the logs alongside kernel audit records; repeatedly broadening directory permissions will not fix a missing network capability.
Proxy traffic from terminals, package managers, and remote sessions
Once mihomo is listening successfully, applications still need to send requests to that port. System proxy settings, environment variables, and TUN are three different paths. Environment variables are most common on command-line servers; desktop applications usually read the desktop environment’s system proxy; programs that ignore proxy settings may require TUN.
Set the current terminal temporarily
Assuming mixed-port is 7890, set the current shell as follows:
export http_proxy="http://127.0.0.1:7890"
export https_proxy="http://127.0.0.1:7890"
export all_proxy="socks5h://127.0.0.1:7890"
export no_proxy="127.0.0.1,localhost,::1"
export HTTP_PROXY="$http_proxy"
export HTTPS_PROXY="$https_proxy"
export ALL_PROXY="$all_proxy"
export NO_PROXY="$no_proxy"
In socks5h, the h means the proxy handles resolution of the destination hostname, which suits tools that support this notation. Not every program reads the same variables, so setting both uppercase and lowercase forms improves compatibility across command-line tools. These temporary variables disappear when the current shell exits.
If you put the variables in ~/.profile or a shell initialization file, they will take effect at every login. However, when the service is stopped, programs that read those variables will still try to connect to the local port. For long-running servers, a separate script that enables and clears the proxy on demand is usually better:
unset http_proxy https_proxy all_proxy no_proxy
unset HTTP_PROXY HTTPS_PROXY ALL_PROXY NO_PROXY
APT, DNF, and Git
APT and DNF can usually inherit proxy variables from the execution environment, but running them through sudo may cause security policies to strip those variables. For a persistent setup, use the package manager’s own proxy configuration and limit it to the necessary repositories. Git can set an HTTP proxy per user:
git config --global http.proxy http://127.0.0.1:7890
git config --global https.proxy http://127.0.0.1:7890
Run the following to clear the Git setting:
git config --global --unset http.proxy
git config --global --unset https.proxy
SSH does not automatically read HTTP proxy variables. When pulling a repository over SSH, the connection path is determined by SSH configuration and proxy commands; successful browser access does not prove that SSH will work.
Access boundaries on remote servers
When managing a remote server over SSH, 127.0.0.1:7890 refers to the remote server itself, not the administrator’s computer. If mihomo runs on your local computer, use SSH port forwarding to send the proxy port to the remote end; if mihomo is installed on the server, applications should connect to the server’s local listening port. Do not confuse loopback and LAN addresses.
Troubleshoot startup failures, port conflicts, and DNS
The service keeps restarting
Run systemctl status mihomo to check the exit code, then read the latest 100 log lines. YAML indentation errors, incorrect field types, unreadable configuration files, and unwritable working directories can all prevent startup. Because systemd’s automatic restart can make logs scroll quickly, stop the service first and run it in the foreground with the same account:
sudo systemctl stop mihomo
sudo -u mihomo /usr/local/bin/mihomo -d /etc/mihomo
This exposes permission differences such as “works when run manually as root, fails under the service account.” Start the service again after fixing the issue, and do not leave a temporary test instance running alongside the systemd instance.
The port is already in use
Use ss to inspect listening ports and their associated processes:
sudo ss -lntup | grep -E '7890|7891|9090|1053'
Common conflicts come from another Clash graphical client, an old mihomo process, or another local proxy. Stop duplicate instances or change the port, then update the environment variables, desktop system proxy, and controller URL accordingly. Changing only the YAML while leaving application-side proxy addresses unchanged can make the core appear healthy while every request fails.
The node exists but cannot connect
First identify the failing stage in the logs. DNS resolution failure, connection timeout, TLS handshake failure, and authentication failure indicate different problems. Confirm that the server clock is accurate, check whether the subscription has expired, and test the current policy-group selection. In rule mode, also check which rule and policy handled the request so that a routing problem is not mistaken for an unavailable node.
If only certain domains fail, check the DNS configuration, rule-set update status, and IPv6 path. Disabling IPv6 in the configuration affects core-related resolution and connection selection, but does not necessarily disable every IPv6 behavior in the operating system. Desktop browsers may also use their own secure DNS, so check the browser, system, and mihomo resolution paths separately.
The system proxy is enabled, but some programs connect directly
The system proxy is simply a set of proxy parameters supplied by the desktop environment. Browsers and most desktop applications read it, but games, containers, some command-line programs, and software with its own network stack may ignore it. First try the program’s own proxy option or environment variables; deploy TUN only when you genuinely need to capture more traffic.
Inside a Docker container, 127.0.0.1 refers to the container itself. To reach a host proxy, the container must use a reachable host address, and mihomo’s listening scope and firewall must allow that source. After enabling allow-lan, assess the listening interfaces as well; never expose the proxy port directly on an uncontrolled public interface.
Upgrades, backups, and routine maintenance
Upgrade the command-line core and configuration separately. Record the current version, stop the service, replace /usr/local/bin/mihomo, check the version output again, then start the service and watch the logs. If the configuration format changes, read the notes for the relevant version and validate it in a test environment before replacing the production instance.
Back up the main configuration, manually maintained override rules, the systemd service unit, and environment-variable scripts. Cache databases and automatically downloaded rule sets can usually be regenerated, but deleting the working directory may reset policy groups to their defaults if policy selections depend on cached data.
For a long-running server, periodically check the following:
- Whether
systemctl is-active mihomoreturns an active status. - Whether the local proxy, DNS, and controller ports listen only on the expected addresses.
- Whether the logs continue to show rule-download failures, DNS timeouts, or connection retries.
- Whether the subscription update time and node availability match expectations.
- Whether TUN routes recover correctly after a service restart.
- Whether the service account, device permissions, and security policies changed after a package upgrade.
Continue with installation and configuration
Choose a client that matches your Linux architecture and environment, then follow the quick start to import a subscription, select policies, and configure the proxy mode.