Choose Your Path: Desktop Client or the Mihomo CLI Core
There is no single Linux installation method that fits every use case. Users on Ubuntu, Fedora, Linux Mint, or Arch desktops typically want subscription management, policy-group switching, log viewing, and a system-proxy toggle. Servers, soft-router sidecars, and headless hosts prioritize low resource usage, remote maintenance, and startup automation. These needs map to two paths: a desktop client or the pure core.
| Comparison | Desktop client | Mihomo CLI core |
|---|---|---|
| Best for | Ubuntu, Fedora, Mint, and Arch desktops | Servers, development machines, NAS devices, and headless hosts |
| Subscription import | Paste a URL in the GUI and update | Prepare or schedule updates for config.yaml |
| Policy switching | Click policy groups and nodes directly | Use an external controller API or web panel |
| Background operation | Starts automatically after desktop login | Started by systemd during system boot |
| Typical memory use | About 140–320 MB for the UI and core combined | About 35–110 MB with a standard ruleset |
| TUN permissions | Usually handled by service mode or an authorization component | Requires permissions such as CAP_NET_ADMIN |
Check Your CPU Architecture First
Downloading a package for the wrong architecture usually results in “cannot execute binary file” or Exec format error. Run this command in a terminal first:
uname -m
cat /etc/os-release
x86_64maps to amd64 or x64 and is common on Intel and AMD desktops and servers.aarch64maps to arm64 and is common on Raspberry Pi 4/5 devices, some NAS systems, and ARM cloud hosts.armv7ldenotes 32-bit ARM; you must choose a build that explicitly supports armv7.
Your distribution determines the package format: Ubuntu, Debian, and Linux Mint should generally use .deb; Fedora and RHEL-based distributions should use .rpm; other desktop distributions can use AppImage. For server core deployments, use the executable matching your architecture.
Path One: Install a Linux Desktop Client
For the desktop path, choose a maintained client that includes the Mihomo core and provides a Linux build. Package names may include amd64, x86_64, arm64, or aarch64; match them to the earlier uname -m output. Do not copy the macOS ClashX package to Linux—the executable format and system interfaces are incompatible.
Install a DEB on Ubuntu, Debian, or Linux Mint
Assume the package has been downloaded to the “Downloads” directory. Enter that directory, then let APT install the local package. Using APT instead of running only dpkg -i also resolves the package’s declared dependencies.
cd ~/Downloads
sudo apt install ./Clash-Linux-amd64.deb
On systems using English directory names, use cd ~/Downloads. Replace the filename with the exact name downloaded to your machine; type the first few characters and press Tab to autocomplete. After installation, launch the app from the application menu, or run dpkg -l | grep -i clash to confirm that the package is registered.
Install an RPM on Fedora or a RHEL-based Distribution
cd ~/Downloads
sudo dnf install ./Clash-Linux-x86_64.rpm
dnf install reads the RPM dependency metadata. If the system enforces stricter desktop security policies, enabling TUN or service mode for the first time may trigger an administrator authorization prompt. This permission step is needed to create a virtual network interface and modify routes, so do not repeatedly cancel it.
Run and Keep an AppImage
An AppImage does not need to be registered in the distribution’s package database, but the file must be executable. The example below uses a file in the Downloads directory:
cd ~/Downloads
chmod +x Clash-Linux-x86_64.AppImage
./Clash-Linux-x86_64.AppImage
If the system reports a FUSE-related error, install a compatible FUSE runtime component from your distribution’s repositories. You can also try --appimage-extract-and-run to verify that the program starts. For long-term use, move the AppImage to ~/Applications so it is not accidentally deleted when the Downloads directory is cleaned up.
Import a Subscription and Make the First Connection
- Open the client’s “Subscription” page and choose “New” or “Import from URL.” In some clients, the path is “Subscription” → “New” → “URL.”
- Paste the subscription URL provided by your service provider and run an update once it is confirmed.
- Open the “Proxy” or “Policies” page and choose a node in the main policy group. You can also select a URL latency-test group.
- Enable “System Proxy,” then visit a test page or use a command to check your exit address.
- Configure TUN mode only when you need to capture applications that do not read system-proxy settings. There is no need to change every network setting during the first launch.
curl -I --proxy http://127.0.0.1:7890 https://example.com
curl -I --proxy socks5h://127.0.0.1:7890 https://example.com
The first command tests the HTTP proxy; the second uses SOCKS5 and lets the proxy handle DNS resolution. Use the client’s actual port settings: the common mixed port is 7890, but some configurations separate HTTP and SOCKS onto 7890 and 7891. The settings are usually under “Settings” → “Preferences” → “Port Settings.”
Path Two: Install the Mihomo CLI Core
Mihomo is an open-source core that continues the Clash configuration model, with support for rule-based routing, policy groups, rule providers, DNS, and TUN. A CLI deployment does not include subscription lists or a tray menu. Its core tasks are installing the executable, placing config.yaml, and handing process management to systemd.
Install the Binary and Create a Dedicated Account
The commands below use the already downloaded and extracted mihomo-linux-amd64-v1.19.12 as an example. The version number only illustrates the filename format; for an actual deployment, choose the current version and correct architecture from the download page.
sudo install -Dm755 mihomo-linux-amd64-v1.19.12 /usr/local/bin/mihomo
sudo useradd --system --home-dir /var/lib/mihomo --create-home --shell /usr/sbin/nologin mihomo
sudo install -d -o mihomo -g mihomo -m 750 /var/lib/mihomo
/usr/local/bin/mihomo -v
If the distribution does not provide /usr/sbin/nologin, run command -v nologin to find the actual path. A dedicated system account separates the runtime directory from regular user home directories and makes it easier for systemd to grant network capabilities precisely.
Prepare a Minimal Working Configuration
Save the complete converted or exported Clash/Mihomo configuration as /var/lib/mihomo/config.yaml. The snippet below shows the basic structure for ports, the controller, DNS, and rules, but contains no proxy nodes; it can only verify that the core starts and that direct connections work.
mixed-port: 7890
allow-lan: false
mode: rule
log-level: info
ipv6: true
external-controller: 127.0.0.1:9090
secret: "change-this-controller-secret"
dns:
enable: true
listen: 127.0.0.1:1053
ipv6: true
enhanced-mode: fake-ip
nameserver:
- 1.1.1.1
- 8.8.8.8
proxies: []
rules:
- MATCH,DIRECT
mixed-port: 7890 accepts both HTTP and SOCKS connections; external-controller is the control interface, not a proxy port. Binding the control interface to 127.0.0.1 prevents direct exposure to the local network. In a real configuration, set a separate strong secret; for remote administration, prefer SSH port forwarding.
After copying the configuration, fix its ownership and run a syntax test. YAML is indentation-sensitive: list items are typically two spaces deeper than their parent, and Tab characters should not be used for indentation.
sudo chown mihomo:mihomo /var/lib/mihomo/config.yaml
sudo chmod 640 /var/lib/mihomo/config.yaml
sudo -u mihomo /usr/local/bin/mihomo -t -d /var/lib/mihomo
A successful test means the configuration was parsed. For yaml, mapping, or unmarshal errors, inspect indentation, colons, and field types near the reported line. A subscription response that is a web page, login prompt, or Base64 node list cannot be used directly as a complete config.yaml.
Run in the Background and Start at Boot with systemd
If Mihomo runs directly in an SSH session, the process may exit when the terminal closes. systemd provides consistent startup ordering, automatic restarts, log access, and boot-time startup. Create /etc/systemd/system/mihomo.service with the following contents:
[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
ExecStart=/usr/local/bin/mihomo -d /var/lib/mihomo
Restart=on-failure
RestartSec=5
LimitNOFILE=1048576
AmbientCapabilities=CAP_NET_ADMIN CAP_NET_RAW
CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_RAW
NoNewPrivileges=true
ProtectSystem=strict
ProtectHome=true
PrivateTmp=true
ReadWritePaths=/var/lib/mihomo
[Install]
WantedBy=multi-user.target
ExecStartPre tests the configuration before every start, so an invalid configuration will not replace the currently working process. Restart=on-failure restarts only after an abnormal exit, with a five-second delay. CAP_NET_ADMIN and CAP_NET_RAW support TUN and related network operations. If you only expose local HTTP/SOCKS ports and do not use TUN, remove both capability lines to reduce the permission scope.
sudo systemctl daemon-reload
sudo systemctl enable --now mihomo
systemctl status mihomo --no-pager
journalctl -u mihomo -n 80 --no-pager
active (running) means the service is running. After editing the YAML, run the test command first, then sudo systemctl restart mihomo. Follow the logs with journalctl -u mihomo -f; pressing Ctrl+C exits the log view without stopping the service.
Verify That the Port Is Actually Listening
ss -lntp | grep -E '7890|9090'
curl -I --proxy http://127.0.0.1:7890 https://example.com
If systemd reports that the service is running but 7890 is not listening, check whether the configuration uses another port and whether the process exited after failing to load a ruleset. If the port exists but requests time out, inspect policy-group selection, node connectivity, DNS logs, and the server firewall instead of reinstalling the binary.
Choosing Between TUN, System Proxy, and Terminal Environment Variables
For Everyday Desktop Use, Start with System Proxy
System proxy changes are limited and work well for browsers, desktop chat apps, and applications that follow GNOME or KDE proxy settings. A common client path is “Settings” → “System Proxy” → “Enable.” If you only need everyday web access and developer documentation, start with system proxy to make troubleshooting easier.
For Terminal Tools, Set Proxy Variables Per Process
Many command-line programs read HTTP_PROXY, HTTPS_PROXY, and ALL_PROXY. A temporary setting affects only the current terminal session and expires when the terminal closes:
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
curl -I https://example.com
To restore direct connections, run:
unset HTTP_PROXY HTTPS_PROXY ALL_PROXY
unset http_proxy https_proxy all_proxy
Git can also be configured independently, without permanently affecting every terminal program:
git config --global http.proxy http://127.0.0.1:7890
git config --global https.proxy http://127.0.0.1:7890
git config --global --unset http.proxy
git config --global --unset https.proxy
For Containers, Games, and Apps That Ignore Proxy Settings, Consider TUN
TUN mode creates a virtual network interface and uses routes to send more traffic through Mihomo. It covers programs that do not support HTTP/SOCKS proxies, but adds DNS, route-priority, LAN-access, and permission concerns. Before deploying it remotely on a server, keep a second SSH session open so an incorrect route does not cut off the active management connection.
tun:
enable: true
stack: mixed
auto-route: true
auto-redirect: true
auto-detect-interface: true
dns-hijack:
- any:53
auto-detect-interface identifies the default egress interface; auto-route adds routes for intercepted traffic; dns-hijack sends specified DNS traffic to the core. Supported options vary by core version and operating-system network stack, so run mihomo -t before enabling them. Docker, Podman, virtual-machine bridges, and policy-routing setups also require checking reserved subnets to prevent container traffic from being routed through the proxy accidentally.
Configuration Files, Subscription Updates, and Log Maintenance
Where Desktop Clients Store Configuration
Desktop clients usually store configuration in the user data directory rather than /etc. Common Linux locations include ~/.config/app-directory and ~/.local/share/app-directory; Flatpak apps are often under ~/.var/app/app-id. Do not overwrite an entire directory in bulk while the client is running. Prefer its built-in import, update, and backup functions.
Find recently modified YAML files with:
find ~/.config ~/.local/share -type f \
\( -name '*.yaml' -o -name '*.yml' \) \
-mtime -7 2>/dev/null
Updating Subscriptions in a CLI Deployment
A CLI core does not validate subscription formats for you. The safe workflow is to download the new configuration to a temporary file, run a syntax test, then replace the live configuration and restart the service. Never overwrite the file in use directly; an incomplete download could prevent the service from starting again.
- Save the new content as a temporary YAML file.
- Verify that the response is actually a Clash/Mihomo configuration, not an HTML error page.
- Run
mihomo -tfrom a separate temporary directory. - After the test succeeds, move it to
/var/lib/mihomo/config.yaml. - Fix the file ownership and restart the systemd service.
If the configuration uses proxy-providers, Mihomo can refresh the provider at the interval specified in the configuration. A typical interval: 86400 means an update every 86,400 seconds, or 24 hours. A health-check interval: 300 means checking every five minutes; the two serve different purposes, so do not set both to very small values just to update faster.
Log Levels and Disk Usage
For normal operation, use log-level: info. Temporarily switch to debug when investigating DNS, rule matching, or connection failures, then switch back after the issue is confirmed. systemd logs are managed by journald; use the following command to check service usage:
journalctl --disk-usage
journalctl -u mihomo --since "30 minutes ago"
journalctl -u mihomo -p warning --since today
In logs, connection refused usually means the destination is reachable but no service is listening on the port; i/o timeout more often indicates a network-path or node-response timeout; no such host and DNS resolve failed call for checks of upstream DNS, hijacking settings, and IPv6 availability. First identify whether the error occurs at local listening, DNS resolution, node connectivity, or the destination site; this is more effective than repeatedly switching nodes.
Common Installation Problems and What to Check
Exec format error at startup
This is almost always an architecture mismatch. Run uname -m again, then use file /usr/local/bin/mihomo to inspect the binary’s target architecture. An x86_64 host needs an amd64 build; an aarch64 host needs an arm64 build.
The Desktop Client Opens, but System Proxy Has No Effect
- Under “Settings” → “Preferences,” verify that the mixed port is actually
7890. - Run curl with
--proxyto confirm that the local proxy port works first. - Check whether the browser has a separate proxy extension installed; it may override the system settings.
- Confirm that the current policy group has not selected an unavailable node.
- Terminal programs need their own environment variables; they cannot rely solely on the desktop toggle.
systemd Keeps Restarting
systemctl status mihomo --no-pager
journalctl -u mihomo -b -n 120 --no-pager
sudo -u mihomo /usr/local/bin/mihomo -t -d /var/lib/mihomo
Common causes include YAML indentation errors, a port already occupied by another process, insufficient permission for the runtime account to read the configuration, failed Geo data downloads, or missing TUN permissions. Find port conflicts with sudo ss -lntp; for permission issues, inspect the permissions of every directory level in the output of namei -l /var/lib/mihomo/config.yaml.
LAN Devices Cannot Connect to the Linux Host’s Proxy
The default allow-lan: false permits local access only. If trusted LAN devices genuinely need to use the proxy, change it to allow-lan: true, set an explicit bind-address, and configure the host firewall to allow the proxy ports only from the LAN subnet. Do not expose the external controller at 9090 simply because proxy ports are open.