Run Clash on Linux
Install a Linux desktop client, or run mihomo as a persistent systemd service on a headless server. Includes setup and verification steps.
1. Choose a desktop client or command-line service
There are two ways to run Clash on Linux. A desktop client handles subscription imports, proxy group selection, system proxy settings, and logs. mihomo is the proxy core: it reads YAML configuration, listens on ports, matches rules, and establishes connections. Installing the core alone does not configure the desktop system proxy.
| Use case | Recommended setup | What you need to handle |
|---|---|---|
| Ubuntu, Fedora, or another desktop Linux distribution | A GUI client such as Clash Verge Rev or FlClash | Import a subscription, enable the configuration, and check the local port |
| A server managed over SSH | mihomo with a systemd service | Configuration, service account, permissions, logs, and updates |
| Proxy traffic from terminal tools only | Use either setup to provide a local HTTP proxy | Set proxy options or environment variables explicitly |
This guide assumes a standard Linux distribution with systemd enabled. Containers, WSL, and minimal systems may not have a usable system-wide systemd instance. Check your environment with the commands below before choosing a package. Use the version reported by the command itself; do not infer the core version from a client’s interface.
uname -m
cat /etc/os-release
ps -p 1 -o comm=
x86_64usually corresponds to an amd64 or x64 package.aarch64usually corresponds to an arm64 package; x64 binaries will not work.- Debian and Ubuntu typically use DEB packages, while Fedora and similar distributions typically use RPM. The package format and CPU architecture must both match.
2. Install a Linux desktop client and import a subscription
Install a GUI client
Open the Linux section of the download page and choose a client for your distribution and CPU architecture. For the commands below, rename the downloaded DEB package to clash-client.deb or the RPM package to clash-client.rpm, then run the matching command from the directory containing the file.
# Debian / Ubuntu: run this command only
sudo apt install ./clash-client.deb
# Fedora: run this command only
sudo dnf install ./clash-client.rpm
The package manager will check dependencies. If it reports missing graphical components, first make sure a desktop environment is installed; repeatedly launching a windowed app from a plain SSH session will not help. Once installed, open the client from your app menu. You generally do not need to launch the entire GUI with sudo.
Import a configuration, then enable the system proxy
- For example, in Clash Verge Rev, add your subscription URL on the Subscription page, then select the configuration after it downloads. Button labels may vary slightly between versions.
- On the Proxy page, review the proxy groups and select an available node. In Rule mode, requests are still routed according to the configuration’s rules; selecting a node does not send every connection through the proxy.
- In Settings, check System Proxy and the port settings, and note the actual mixed port. This guide uses
7890throughout. If your client uses a different port, update it in the commands as well. - Enable the system proxy and test a browser first, then test the terminal separately. Avoid enabling the system proxy in another client at the same time, as the settings may override each other.
Desktop environments often have their own proxy settings, such as Settings → Network → Network Proxy in GNOME. You can check there whether the client applied the expected address, but not all apps read the desktop proxy settings. Test curl, Git, and package managers individually in the terminal. A working browser alone does not mean the entire system is using the proxy.
3. Install mihomo and create a service account
A headless server does not need a GUI client. Download the mihomo core for your CPU architecture and extract it according to the archive format. Name the extracted executable mihomo. The steps below assume this file is already in the current directory; do not copy the archive itself into a system path.
chmod +x ./mihomo
./mihomo -v
sudo install -m 0755 ./mihomo /usr/local/bin/mihomo
/usr/local/bin/mihomo -v
If you see Exec format error, first check the CPU architecture and confirm the file was extracted correctly. For Permission denied, check the executable bit and whether the filesystem is mounted with the noexec option. Do not solve execution problems by granting arbitrary write permissions to the file.
Keep the program, configuration, and runtime data separate
Run the service under a dedicated system account. Store configuration in /etc/mihomo, cache and rule data in /var/lib/mihomo, and the binary in /usr/local/bin. Run the account creation commands below once. If an account with the same name already exists, check its purpose and permissions first.
sudo useradd --system --user-group \
--home-dir /var/lib/mihomo \
--shell /usr/sbin/nologin mihomo
sudo install -d -o root -g mihomo -m 0750 /etc/mihomo
sudo install -d -o mihomo -g mihomo -m 0750 /var/lib/mihomo
This setup runs as an unprivileged user and listens on 7890, so it does not need permission to bind low-numbered ports. It also does not enable TUN, so no network administration privileges are required. If you later need TUN, reassess device access, capabilities, and routing rather than running the entire service as root indefinitely.
4. Prepare the configuration and check it before startup
Start with a minimal configuration to verify the program, permissions, and listening port before adding a real subscription. The complete local test configuration below has no proxy nodes; all requests go directly to their destination. It is only for checking that the HTTP and SOCKS mixed-port listener works.
sudo tee /etc/mihomo/config.yaml > /dev/null <<'YAML'
mixed-port: 7890
allow-lan: false
bind-address: "127.0.0.1"
mode: rule
log-level: info
ipv6: false
proxies: []
proxy-groups: []
rules:
- MATCH,DIRECT
YAML
sudo chown root:mihomo /etc/mihomo/config.yaml
sudo chmod 0640 /etc/mihomo/config.yaml
sudo -u mihomo /usr/local/bin/mihomo \
-t -d /var/lib/mihomo -f /etc/mihomo/config.yaml
-t tests the configuration, -d sets the working directory, and -f specifies the configuration file. A successful test means the core accepts the configuration; it does not mean a proxy node can connect or that a destination site is reachable. Configurations using GeoIP, GeoSite, or remote rule sets may also require the relevant data files and a working download path.
Replace it with a real subscription configuration
Prepare a mihomo-compatible YAML file saved locally, such as profile.yaml in the current directory. Confirm it contains a valid configuration—not a subscription error page, login page, or encoded text containing only a list of nodes—then copy it to the fixed path:
sudo install -o root -g mihomo -m 0640 \
./profile.yaml /etc/mihomo/config.yaml
sudo -u mihomo /usr/local/bin/mihomo \
-t -d /var/lib/mihomo -f /etc/mihomo/config.yaml
- Keep
mixed-port: 7890and the localhost-only listening setting required by this service. If the configuration already has these fields, edit the existing values; do not add duplicate keys. - Check that the node names referenced in
proxy-groupsmatch the names used by your rules. - If you use
proxy-providersorrule-providers, store their local caches under the working directory, for example./providers. Do not point them to a configuration directory the service cannot write to. - Check that
tun, LAN access, or the external controller API has not been enabled unintentionally. Review runtime options included with the subscription as well.
5. Run mihomo as a persistent systemd service
Create a system-level service unit. It runs under a dedicated account, tests the configuration before startup, and waits five seconds before restarting after an unexpected exit. Hardening options make system directories read-only and allow writes only to the runtime data directory. Store any configuration caches there too.
sudo tee /etc/systemd/system/mihomo.service > /dev/null <<'UNIT'
[Unit]
Description=mihomo local proxy service
Wants=network-online.target
After=network-online.target
[Service]
Type=simple
User=mihomo
Group=mihomo
WorkingDirectory=/var/lib/mihomo
ExecStartPre=/usr/local/bin/mihomo -t -d /var/lib/mihomo -f /etc/mihomo/config.yaml
ExecStart=/usr/local/bin/mihomo -d /var/lib/mihomo -f /etc/mihomo/config.yaml
Restart=on-failure
RestartSec=5
UMask=0077
NoNewPrivileges=true
PrivateTmp=true
ProtectHome=true
ProtectSystem=strict
ReadWritePaths=/var/lib/mihomo
[Install]
WantedBy=multi-user.target
UNIT
sudo systemctl daemon-reload
sudo systemctl enable --now mihomo.service
systemctl status mihomo.service --no-pager
sudo journalctl -u mihomo.service -n 80 --no-pager
enable --now enables the service at boot and starts it immediately. network-online.target only sets a startup ordering constraint; its effect also depends on the distribution’s network-wait service. It does not guarantee that the subscription server or proxy nodes are reachable at startup.
Apply changes
For YAML changes, first run the -t test above. If it passes, run sudo systemctl restart mihomo.service. For service unit changes, run sudo systemctl daemon-reload first, then restart the service. This guide does not configure ExecReload, so systemctl reload is not a valid way to reload the configuration.
6. Verify the listener, requests, and rules separately
Step 1: Confirm the port is listening
sudo ss -lntp 'sport = :7890'
curl --proxy http://127.0.0.1:7890 \
--connect-timeout 10 --max-time 30 \
-I https://example.com/
curl --proxy socks5h://127.0.0.1:7890 \
--connect-timeout 10 --max-time 30 \
-I https://example.com/
The expected listening address is the loopback address, not the externally exposed 0.0.0.0:7890. The two curl commands test the HTTP and SOCKS interfaces on the mixed port. socks5h sends the destination hostname to the proxy for resolution, which helps rule out curl resolving it locally first. It does not determine which DNS upstream mihomo ultimately uses.
With the minimal configuration, a successful request only confirms that direct connections work. After switching to a real configuration, check the logs for rule matches and policy selection to confirm the test domain uses the expected node. A successful HTTP connection, a response status from the destination site, and the expected exit route are three separate checks.
Step 2: Configure terminal apps to use the proxy explicitly
export http_proxy=http://127.0.0.1:7890
export https_proxy=http://127.0.0.1:7890
export no_proxy=localhost,127.0.0.1,::1
curl -I --connect-timeout 10 --max-time 30 https://example.com/
# Clear only the settings above in the current terminal
unset http_proxy https_proxy no_proxy
The value of https_proxy can still use http://. This means HTTPS sites are accessed through an HTTP proxy using a CONNECT tunnel; it does not downgrade the destination to HTTP. Environment variables affect only the current process and its child processes. Other terminals, desktop apps, and already-running systemd services do not inherit them automatically.
If only one application fails, check that application’s proxy support. sudo may also filter environment variables by default. Getting curl to work does not prove that APT, container builds, or background services are using the same proxy.
7. Remote access and TUN permissions
On a server, 127.0.0.1 refers to the server itself, not your local computer. To temporarily test the server’s proxy from your computer, use SSH port forwarding instead of exposing the mixed port to the public internet. 192.0.2.10 is an example documentation address; replace it with your server’s actual address, and replace ops with your SSH account name.
# Run on your local computer and keep this session open
ssh -N -o ExitOnForwardFailure=yes \
-L 127.0.0.1:17890:127.0.0.1:7890 [email protected]
# Test from another terminal on your local computer
curl --proxy http://127.0.0.1:17890 \
--connect-timeout 10 --max-time 30 \
-I https://example.com/
The local port 17890 avoids common ports used by local clients. If you need to provide a proxy to your LAN, configure allow-lan, the listening address, authentication, and firewall rules together, and restrict access to trusted source networks. The controller API and proxy listener use different ports; the controller port is not a proxy address.
TUN is not required for a successful setup
TUN uses a virtual network interface and routes to capture eligible IP traffic, making it useful for apps that ignore system proxy settings. On Linux, it typically involves /dev/net/tun, network administration privileges, and DNS routing. The unprivileged account and hardening settings in this guide are not configured for TUN. Adding tun.enable: true to the YAML may fail because the service lacks the required permissions.
8. Troubleshooting and routine updates
| Symptom | Check first | What to do |
|---|---|---|
| Service exits and no port is listening | journalctl output and configuration test results | Fix YAML, file permissions, or rule resource issues, then start the service |
| Logs show address already in use | Check which process is using port 7890 with ss | Stop the duplicate core, or use the same listening port and proxy address throughout |
| Browser works, but terminal traffic goes direct | Terminal proxy options and environment variables | Start by testing explicitly with curl --proxy |
| Proxy connects, but requests still go direct | Rule order, proxy group selection, and outbound shown in logs | Check whether the request matches DIRECT or selects a direct connection policy |
| Rule set download fails | Working directory permissions, download URL, and network connectivity | Make sure the cache path is writable and the update path does not depend on a proxy that is not yet available |
Keep the previous binary and configuration available for rollback
Before updating the core, record the output of mihomo -v and keep the old binary. Put the new binary in a temporary location, then check its version and test the configuration to confirm it supports your current protocols and fields. Only then stop the service, replace the binary, and start it again. Do not overwrite a running executable directly, or combine a core update with a major rule rewrite during the same troubleshooting session.
Before updating the subscription configuration, back up /etc/mihomo/config.yaml and compare the port, listening address, controller API, TUN, and provider paths. Restart only after the configuration test passes, then recheck the port and make an explicit proxy request. This sequence isolates issues to the binary, configuration, or network instead of changing several variables at once and losing track of the cause.
For desktop setups, focus on whether the active configuration, proxy group, and system proxy agree. For servers, focus on account permissions, the fixed configuration path, and systemd logs. Get a basic local proxy working reliably before adding automatic updates, remote management, or TUN; this keeps maintenance manageable.