Deploy Clash on Linux: GUI Clients and mihomo with systemd
Use a Linux desktop client on workstations, or run mihomo as a systemd service on headless servers. This guide covers installation, config paths, startup, and proxy environment variables.
Choose a deployment path: GUI for desktops, standalone core for servers
The short version: if you use a desktop environment such as GNOME or KDE and regularly switch subscriptions and proxy groups, start with a Linux GUI client. For machines managed over SSH without a desktop session, mihomo with systemd is a better fit. Both approaches provide local proxy ports, but differ in startup behavior, config location, and permissions. Avoid running both cores on the same ports.
Clash is often used as a catch-all name for this type of client. mihomo is the core that evolved from Clash Meta. GUI clients handle the interface, subscriptions, and service management, while actual connectivity depends on the core they bundle. Don’t apply instructions for an older client directly to current mihomo, or assume every Clash-format subscription supports the same protocols.
| Criteria | GUI client | mihomo with systemd |
|---|---|---|
| Typical environment | Logged-in desktop session | Server or headless machine |
| Configuration | Subscription, config, and proxy-group interface | Local YAML file |
| Startup | Start at desktop login or through the client service | System service starts at boot |
| Port used in this guide | Use the port shown by your client | Example uses 127.0.0.1:7890 |
Before installation: check architecture, package format, and listening ports
Run these three commands first. The first checks your CPU architecture, the second confirms whether systemd is available, and the third checks the port you plan to use. If a process is already listening on 7890, identify whether it is another proxy core before stopping it or choosing a different port.
uname -m
systemctl --version
sudo ss -lntup 'sport = :7890'
x86_64usually corresponds to amd64 or x64 packages;aarch64usually means arm64. A 32-bit ARM system cannot run an arm64 binary.- For Debian and Ubuntu, choose a DEB package that matches your architecture; for Fedora and other RPM-based distributions, choose an RPM. Check package format and CPU architecture separately.
- For older CPUs, check the instruction-set requirements in the release notes too. If you see
Illegal instruction, check the build variant first; the amd64 filename alone doesn’t guarantee compatibility. - Alpine commonly uses OpenRC and a musl-based userspace, so the systemd unit in this guide won’t work there unchanged.
Get the client and core from their official project release channels. This guide doesn’t pin an unverified version. Record the installed version and architecture so you have a consistent baseline for troubleshooting. After installation, check the core version with mihomo -v. For a GUI client, record both the app and core versions.
Path 1: Linux desktop GUI client
Import a complete config before enabling the system proxy
Clash Verge Rev, FlClash, and other clients offer Linux GUIs, but their packages and system integration differ. Compare platform options and requirements in our download center, then follow the relevant project’s installation instructions. To install a DEB, run sudo apt install ./filename.deb, replacing the example filename with the actual file in your downloads folder. Don’t copy the explanatory filename as-is.
- Import the Clash/mihomo config provided by your service in the client’s subscription or configuration page. Subscription URLs often contain credentials, so don’t share them in public screenshots or logs.
- Update the config and confirm that nodes and proxy groups appear. A node list alone doesn’t mean DNS, rules, and proxy groups are fully configured.
- Choose rule mode, then select a node in the relevant proxy group. Note the HTTP, SOCKS, or mixed port shown in the interface.
- Enable the system proxy, visit a site that should clearly match a proxy rule, and check the connection log for the matched rule, proxy group, and outbound node.
Menus vary between clients, so there’s no single navigation path that applies to every app. Check four things instead: whether the config is enabled, whether the core is running, which port it uses, and whether the system proxy is set. A tray icon alone doesn’t prove traffic is reaching the core.
Config location and desktop autostart
GUI clients may store data in XDG user directories, such as an app-specific folder under ~/.config or ~/.local/share. The exact path depends on the app. Use the client’s own config-location option rather than guessing and deleting files in bulk. Subscription caches, override files, and the config ultimately used by the core may all be separate files.
First confirm that the client works when started manually. Then enable its launch-at-login option and verify it after logging out and back in. Desktop autostart generally means “start after a user logs in,” not “run when nobody is logged in.” If the client has its own service mode, follow its service setup instructions; don’t add another systemd service on the same ports.
Path 2: Prepare the mihomo binary and config directory
The steps below run a standard proxy service as a dedicated, unprivileged user, without granting the network administration capabilities required by TUN. Download the official archive for your architecture. If you downloaded a standalone gzip file, rename it locally to mihomo.gz, then run the following in that directory:
gzip -dk mihomo.gz
file ./mihomo
chmod u+x ./mihomo
./mihomo -v
sudo install -o root -g root -m 0755 ./mihomo /usr/local/bin/mihomo
Exec format error commonly means the binary doesn’t match your architecture or you’re trying to run a compressed archive as a program. Go back to the download and extraction steps instead of repeatedly changing file permissions. Next, create a service account. If an account with that name already exists, check what it’s used for; don’t create it again or change its permissions blindly.
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
Save a complete, prepared config as config.yaml in the current directory, then install it in the service config directory. This guide doesn’t provide public nodes or treat a snippet containing only DNS and ports as a complete subscription. Your config must include nodes or providers, proxy groups, and rules that match your service.
sudo install -o root -g mihomo -m 0640 \
./config.yaml /etc/mihomo/config.yaml
Edit the existing fields in your complete config rather than appending duplicate keys at the end of the YAML file. These are the key fields for a local proxy; this snippet is not a standalone, working config:
mixed-port: 7890
allow-lan: false
bind-address: 127.0.0.1
mode: rule
log-level: info
tun:
enable: false
mixed-port accepts both HTTP and SOCKS proxy connections on the same port. This example is for local use only. If your full config also enables other inbound ports, DNS listeners, or a controller API, check each bind address separately. You can leave external-controller disabled if you don’t need remote management. If you do enable it, bind it to a loopback address and set a separate access secret.
This guide keeps the read-only main config in /etc/mihomo and caches, databases, and runtime data in /var/lib/mihomo. If you use proxy-providers or rule-providers, put files that need updating in the working directory, such as ./providers/main.yaml, rather than in a config directory that will later be made read-only.
sudo -u mihomo /usr/local/bin/mihomo \
-t -d /var/lib/mihomo -f /etc/mihomo/config.yaml
A successful test only confirms that the config loads; it doesn’t prove that nodes are reachable. If you see a file-permission or missing-database error, fix the path, permissions, or required resources before creating the service.
Run mihomo with systemd: start, enable at boot, and check logs
Create the unit below with sudoedit /etc/systemd/system/mihomo.service. It explicitly sets the executable, config, and working directory, and restricts writes elsewhere on the system. Network administration capabilities aren’t enabled here, so don’t turn on TUN in the config as well.
[Unit]
Description=mihomo local proxy service
Wants=network-online.target
After=network-online.target
[Service]
Type=simple
User=mihomo
Group=mihomo
StateDirectory=mihomo
StateDirectoryMode=0750
WorkingDirectory=/var/lib/mihomo
ExecStart=/usr/local/bin/mihomo -d /var/lib/mihomo -f /etc/mihomo/config.yaml
Restart=on-failure
RestartSec=5s
UMask=0027
NoNewPrivileges=true
PrivateTmp=true
ProtectHome=true
ProtectSystem=strict
ReadWritePaths=/var/lib/mihomo
[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable --now mihomo.service
systemctl is-enabled mihomo.service
systemctl is-active mihomo.service
sudo journalctl -u mihomo.service -b -n 80 --no-pager
sudo ss -lntp 'sport = :7890'
enable --now enables the service at boot and starts it immediately. enabled and active answer different questions: “Will it start later?” and “Is it running now?” Check that the listener matches the example config: 127.0.0.1:7890, not an unexpected public address.
- After editing the YAML, test the config first, then run
sudo systemctl restart mihomo. The brief restart will interrupt existing proxy connections. - After editing the service unit, run
sudo systemctl daemon-reloadbefore restarting the service. - If the service keeps failing, check the first actual error in the logs. After fixing it, if systemd limits further start attempts, run
sudo systemctl reset-failed mihomoand start the service again.
network-online.target doesn’t guarantee access to the internet, DNS, or subscription servers. If remote rules or providers fail to update, distinguish between an unavailable network, an invalid URL, and file-permission issues. Remove subscription URLs, secrets, and other sensitive data before sharing logs.
Proxy environment variables in the terminal: they only affect processes that read them
Starting the service doesn’t automatically proxy traffic from every command-line tool. Set an HTTP proxy in the current terminal first. HTTPS destinations typically use the same http:// proxy address, with the client establishing a tunnel via CONNECT. Don’t change the proxy URL’s scheme just because the destination uses HTTPS.
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 20 https://example.com
You can also leave the environment unchanged and specify a proxy for a single request. The commands below test HTTP and SOCKS5 proxies, respectively. In socks5h, the h means the proxy resolves the destination hostname, though the actual resolution path still depends on the core config and node protocol.
curl --noproxy "" -x http://127.0.0.1:7890 \
-I --connect-timeout 10 --max-time 20 https://example.com
curl --noproxy "" --proxy socks5h://127.0.0.1:7890 \
-I --connect-timeout 10 --max-time 20 https://example.com
To make the settings persistent, add them to ~/.bashrc for interactive Bash sessions or ~/.zshrc for Zsh, then reopen the terminal to verify. Login shells, desktop apps, and systemd services each load their environment differently; don’t assume they all read Bash config. Some tools accept only lowercase variables, while others also support uppercase. Follow each tool’s documentation.
sudo usually filters proxy environment variables. APT, containers, and other services may also need separate configuration. Don’t set proxy variables globally just for convenience; test with a one-off command first, then decide what needs to persist. To clear the settings from the current terminal, run:
unset http_proxy https_proxy all_proxy no_proxy
unset HTTP_PROXY HTTPS_PROXY ALL_PROXY NO_PROXY
TUN, remote access, and common troubleshooting limits
When to consider TUN
Consider TUN only after confirming that browsers and tools supporting proxy variables work, but some apps still ignore the system proxy and environment variables. TUN involves a virtual network interface, routing, and DNS interception; changing enable to true won’t make it work on every machine.
First check ls -l /dev/net/tun. Containers also need the host to grant the required device access and network capabilities, and VPS providers may impose restrictions. The unprivileged service in this guide doesn’t have these capabilities and can’t be used for TUN as-is. If you need TUN, reassess the service permissions against the current mihomo documentation, especially network administration, automatic routing, and DNS hijacking. Don’t run the entire service as root as a blanket fix.
When changing routes on a remote host over SSH, keep a second session and your provider’s console available, and prepare a rollback plan. TUN automatic or strict routing may disrupt your management connection. Connection logs also don’t prove that DNS is being intercepted; check app-specific encrypted DNS separately.
Safely use a local listener on a remote machine
If you just want your computer to use a proxy on a server, don’t expose port 7890 to the public internet. Create an SSH local port forward with ssh -L 17890:127.0.0.1:7890, followed by the usual server login target. Then point local apps to 127.0.0.1:17890. The server’s nodes, rules, and network still need to work.
Troubleshoot by symptom; change one variable at a time
- Connection refused: Check the service status and listening port first. The request usually hasn’t reached rule evaluation yet.
- Service is running, but requests time out: Check provider updates, the selected node, the destination’s rule, and the server’s outbound connectivity. Don’t reinstall the client right away.
- Terminal works, browser doesn’t: Check the browser and desktop proxy settings. Environment variables don’t automatically change the network behavior of an already-running browser.
- Browser works, terminal doesn’t: Check the current shell’s variables, whether the tool supports proxies, and whether sudo is filtering the environment.
- Stops working after a reboot: Distinguish desktop login autostart from a system boot service. Check
systemctl is-enabled mihomoand review the logs from the latest boot.
Before you finish, verify three things: the service starts after a reboot; port 7890 listens only on the expected address; and a request that clearly matches a proxy rule appears in the connection log with the expected node. Record these alongside the actual core version so you can repeat the checks after an upgrade or migration. For config basics, see Getting Started. For DNS and rule concepts, consult the user guide.