Choose the deployment path first: desktop client or mihomo service
On Linux, “installing Clash” usually means one of two different deployment paths. The first is installing a graphical client in a desktop environment such as GNOME, KDE Plasma, or Xfce. The client handles subscription imports, profile switching, kernel startup, the system proxy, and log viewing. The second is running the mihomo kernel directly on a server, software router, development machine, or headless host, with systemd managing the process. Both paths may use similar YAML configuration, but their entry points, permission boundaries, and troubleshooting methods are different.
| Deployment method | Best for | Configuration entry point | Process management | Traffic capture |
|---|---|---|---|---|
| Desktop client | Everyday desktops and development workstations | Client interface and config directory | The client itself | System proxy or TUN |
| mihomo service | Servers, headless hosts, and transparent gateways | Manually maintained YAML files | systemd | Environment variables, explicit proxy, or TUN |
A Linux desktop client and mihomo are not interchangeable product layers. The client provides the interface, updates, and configuration management; mihomo reads the configuration and handles proxying, DNS, and rules. Some clients bundle mihomo, while others let you choose the kernel version. If a desktop client has already started the kernel, do not also start a systemd service listening on the same ports, or you will typically see address already in use.
Linux desktop clients: verify the kernel and config directory after installation
Choose a package for your distribution
Debian, Ubuntu, and Linux Mint typically use .deb packages; Fedora, RHEL-based systems, and openSUSE commonly use .rpm. Other distributions may offer an AppImage or archive. Before downloading, check the architecture with uname -m: x86_64 corresponds to amd64 or x64, while aarch64 corresponds to arm64. The package format and CPU architecture must both match.
uname -m
# Install a local deb on Debian or Ubuntu
sudo apt install ./client-linux-amd64.deb
# Install a local rpm on Fedora
sudo dnf install ./client-linux-x86_64.rpm
After the first launch, open “Settings” → “Kernel Settings” or “Settings” → “Preferences” and verify the kernel name, kernel version, and working directory. Menu labels vary slightly between clients; focus on locating the kernel, config directory, listening ports, and logs. Do not confuse the client version with the kernel version. Record both when troubleshooting rule or DNS compatibility.
Importing a subscription does not route traffic by itself
- On the “Profiles” or “Subscriptions” page, paste the subscription URL and import it.
- Select the newly imported profile and wait for the client to parse it and start the kernel.
- On the “Proxies” page, choose a proxy group.
PROXYis generally a group name defined by the profile, not a fixed built-in exit. - Enable “System Proxy” or “TUN Mode” as needed; they cover different types of traffic.
- Check the logs for port conflicts, YAML parsing errors, or DNS initialization failures.
The system proxy usually writes HTTP and SOCKS proxy settings to the desktop environment, making it suitable for browsers and graphical applications that honor system proxy settings. TUN mode uses a virtual network interface to capture a broader range of traffic and may require administrator authorization, network capabilities, or additional DNS configuration. If you only import a subscription without enabling a traffic entry point, applications will not use the running kernel automatically.
Use the listening port to confirm that the client actually started the kernel
Clash configurations often use 7890 as the mixed proxy port, or separate HTTP on 7890 and SOCKS on 7891. These are common values only; use the ports shown in the current configuration and client settings. Use ss to inspect listening processes:
ss -lntp | grep -E '7890|7891|9090'
# Test through the local HTTP proxy
curl -I -x http://127.0.0.1:7890 https://example.com
# Test through SOCKS5 with proxy-side DNS resolution
curl -I --proxy socks5h://127.0.0.1:7891 https://example.com
If curl succeeds but the browser fails, check the browser’s own proxy extension or the desktop system proxy. If the browser succeeds but terminal commands fail, check the terminal environment variables. These applications may use completely separate proxy entry points; switching rule modes cannot replace entry-point configuration.
Headless hosts: prepare the mihomo binary and working directory
Create a fixed directory and dedicated account
A server deployment should keep the binary, configuration, and runtime state separate. The example below places the program at /usr/local/bin/mihomo, the main configuration at /etc/mihomo/config.yaml, and runtime data at /var/lib/mihomo. A dedicated system account can limit the files accessible to the proxy service.
sudo install -m 0755 mihomo /usr/local/bin/mihomo
sudo useradd --system --home /var/lib/mihomo --shell /usr/sbin/nologin mihomo
sudo install -d -o mihomo -g mihomo /etc/mihomo
sudo install -d -o mihomo -g mihomo /var/lib/mihomo
sudo install -m 0640 -o mihomo -g mihomo config.yaml /etc/mihomo/config.yaml
On some distributions, nologin is located at /sbin/nologin; run command -v nologin first to confirm the path. If the configuration references GeoIP, GeoSite, rule-set, or certificate files, make sure the mihomo account can read them. When the configuration uses relative paths, they are usually resolved from mihomo’s working directory, so WorkingDirectory in systemd and the startup arguments must agree.
Test the configuration before handing it to systemd
sudo -u mihomo /usr/local/bin/mihomo \
-t \
-d /var/lib/mihomo \
-f /etc/mihomo/config.yaml
-t tests the configuration, -d sets the runtime directory, and -f specifies the config file. A successful test only means the current kernel can parse the configuration; it does not mean every node is reachable or that system traffic is using the proxy. Repeat the test after upgrading mihomo or changing rule providers, then restart the service.
Manage the mihomo service with systemd
Basic proxy service unit
If you provide only HTTP, SOCKS, or a mixed port, TUN permissions are usually unnecessary. Create /etc/systemd/system/mihomo.service:
[Unit]
Description=mihomo proxy service
After=network-online.target
Wants=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
LimitNOFILE=1048576
[Install]
WantedBy=multi-user.target
After saving, reload the systemd configuration and start the service:
sudo systemctl daemon-reload
sudo systemctl enable --now mihomo
systemctl status mihomo --no-pager
sudo journalctl -u mihomo -n 100 --no-pager
ExecStartPre validates the YAML before every start. If the test fails, the main process will not start; during a restart, the old process may already have exited, so you should still run the test command manually before changing production configuration. Restart=on-failure handles unexpected exits, but it cannot fix invalid configuration or a port occupied by another process.
Add network capabilities only when enabling TUN
A typical mihomo TUN configuration looks like this. The available fields depend on the current mihomo version and the system network stack, so consult the documentation for the version in use when migrating an older configuration.
tun:
enable: true
stack: mixed
auto-route: true
auto-detect-interface: true
dns-hijack:
- any:53
When TUN runs under a dedicated account, the service usually needs CAP_NET_ADMIN, and the host must provide /dev/net/tun. Add the following to the service’s [Service] section:
AmbientCapabilities=CAP_NET_ADMIN
CapabilityBoundingSet=CAP_NET_ADMIN
DeviceAllow=/dev/net/tun rw
After modifying the service, run sudo systemctl daemon-reload and sudo systemctl restart mihomo. Then use ip link, ip route, and the service logs to inspect the virtual interface and routes. In a container, the host must also expose the TUN device and network-management capabilities; changing the YAML inside the container cannot bypass the host’s device and capability limits.
Proxy environment variables: make terminal programs use mihomo
Temporarily apply settings to the current shell
Without TUN, command-line programs usually need an explicit proxy. If mihomo is listening on mixed-port 7890 on the local host, set:
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=localhost,127.0.0.1,::1
curl -I https://example.com
Variable names commonly appear in both uppercase and lowercase, and different programs do not read them consistently. For compatibility with specific tools, set HTTP_PROXY, HTTPS_PROXY, ALL_PROXY, and NO_PROXY together. CGI environments impose additional security restrictions on uppercase HTTP_PROXY, so verify the actual execution context before setting it globally on a server.
In socks5h, the h means the SOCKS proxy resolves the hostname. With socks5, the application may resolve the hostname locally and send the IP address to the proxy, changing the DNS path. When diagnosing DNS issues, record whether you are using socks5 or socks5h.
Configure Git, APT, and systemd services separately
Git can use its own configuration instead of relying on the current shell:
git config --global http.proxy http://127.0.0.1:7890
git config --global https.proxy http://127.0.0.1:7890
# Show
git config --global --get http.proxy
# Remove
git config --global --unset http.proxy
git config --global --unset https.proxy
APT can be configured to use a proxy in /etc/apt/apt.conf.d/80proxy:
Acquire::http::Proxy "http://127.0.0.1:7890";
Acquire::https::Proxy "http://127.0.0.1:7890";
If another systemd service must use mihomo, do not assume it will inherit variables from the login shell. Create an override with systemctl edit service-name:
[Unit]
After=mihomo.service
Wants=mihomo.service
[Service]
Environment="HTTP_PROXY=http://127.0.0.1:7890"
Environment="HTTPS_PROXY=http://127.0.0.1:7890"
Environment="NO_PROXY=localhost,127.0.0.1,::1"
After saving, run sudo systemctl daemon-reload and restart the target service. Note that After controls startup order, while Wants expresses a weak dependency; neither waits for a mihomo proxy node to pass connectivity checks. For tasks that must reach the network during startup, add retry logic in the application itself.
Configure ports, rules, and the control interface
Scope of a minimal listening configuration
mixed-port: 7890
allow-lan: false
mode: rule
log-level: info
ipv6: false
external-controller: 127.0.0.1:9090
secret: "replace-with-a-long-random-secret"
rules:
- DOMAIN-SUFFIX,example.org,DIRECT
- IP-CIDR,192.168.0.0/16,DIRECT,no-resolve
- MATCH,PROXY
mixed-port accepts both HTTP and SOCKS connections. allow-lan: false is suitable when only the local host needs access; if LAN access is truly required, configure the listen address, firewall, and access boundaries together. external-controller is a control interface, not a proxy port; the example binds it to the loopback address 127.0.0.1:9090. Replace the control key with a real random value and avoid exposing the control interface directly to an untrusted network.
Rules are evaluated in order, and the first match determines the route. DIRECT means a direct connection, REJECT means deny, and PROXY must refer to a proxy group defined in the configuration. no-resolve prevents an IP rule from actively triggering hostname resolution; it does not disable all DNS.
Separate subscription maintenance from local overrides
Graphical clients typically have their own subscription cache, runtime configuration, and override mechanisms. Manual changes to generated runtime files may be overwritten during the next update. Headless mihomo does not automatically treat a subscription URL as a complete production configuration; use a separate update script, config generator, or proxy provider to download and convert it, then test, replace, and reload the configuration.
- Download remote content to a temporary file instead of overwriting the active configuration.
- Check proxy group names, rule references, DNS fields, and rule-provider paths.
- Run the
-ttest with the mihomo binary currently in use. - Atomically replace the configuration file after the test passes.
- Restart the service and inspect the latest 100 log lines and listening ports.
Logs and Troubleshooting: verify the process, port, and entry point layer by layer
The systemd service fails to start
systemctl status mihomo --no-pager
sudo journalctl -u mihomo -b --no-pager
sudo journalctl -u mihomo -f
- For YAML line or field errors, run the configuration test first, then check indentation and fields supported by the current kernel.
- For
permission denied, check the permissions for the configuration, rule sets, working directory, and/dev/net/tun. - For
address already in use, usess -lntpto identify the process occupying 7890, 7891, or 9090. - If the service keeps restarting, inspect the first failure in the logs instead of looking only at the restart count.
- For TUN startup failures, verify the kernel module, device node, systemd capabilities, and routing permissions.
The port is open, but requests still fail
First send a request through the local proxy to rule out application configuration issues. Then inspect the mihomo logs for the destination, matched rule, and final policy. If the request does not appear in the logs at all, it usually has not reached the proxy port. If it appears but the policy is unexpected, check rule order and proxy-group selection. If the policy is correct but the connection times out, check node availability, server time, DNS, and the upstream network.
# HTTP proxy entry point
curl -v -x http://127.0.0.1:7890 https://example.com
# SOCKS proxy entry point with remote DNS resolution
curl -v --proxy socks5h://127.0.0.1:7890 https://example.com
# Show local routes
ip route
# Show DNS status for systemd-resolved
resolvectl status
If mihomo runs on another host, replace the test address with that host’s LAN IP and verify allow-lan, the listen address, and firewall rules. Do not use the control port 9090 as an HTTP proxy port, and do not write a SOCKS URL as an HTTP URL.
Desktop client and systemd conflicts
When a Linux workstation has both a desktop client and a systemd service configured, let only one of them run persistently. Run systemctl disable --now mihomo to stop the system service before launching the desktop client; alternatively, quit the desktop client, confirm that its kernel process has ended, and then start systemd. Closing the client window may not exit its tray process, so check the listening ports and process command line again.
Post-deployment checklist
- Record the client version and mihomo kernel version, and identify which component currently starts the kernel.
- Confirm that the runtime account can read the configuration, working directory, and rule-set files.
- Test the current configuration with
mihomo -t. - Use
ss -lntpto confirm that the proxy and control ports do not conflict. - Use
curl -xorcurl --proxyto verify the explicit proxy entry point. - Configure terminal variables, Git, APT, or systemd environment variables separately for each application.
- After enabling TUN, check the virtual interface, default route, DNS, and SSH return path.
- Retest the configuration and review startup logs after updating the subscription or kernel.
The key to a Linux desktop deployment is letting the client manage the configuration, kernel, and system entry point in one place. For a headless deployment, manage mihomo like any other system service. Keeping these four states distinct—“configuration imported,” “kernel listening,” “application pointed at the proxy,” and “TUN capturing traffic”—avoids most port conflicts and proxy-not-working issues.