Choose a setup: desktop client or standalone core

There are two common ways to use Clash configs on Linux: install a GUI client on a desktop and let it manage mihomo, or run mihomo directly on a server or minimal system and use systemd to manage the process. mihomo is a proxy core, not a desktop settings panel. Installing the binary alone won't enable the system proxy or route every terminal command through the proxy.

Use caseRecommended setupWhat you'll manage
Everyday desktop use; frequent config changesGUI clientConfig imports, proxy groups, system proxy, and launch at login
SSH server; command-line toolsmihomo and systemdConfig file, service account, ports, and terminal environment variables
Need to proxy apps that don't support proxiesConfigure TUN separatelyVirtual interface, permissions, routes, and DNS

The commands below use Debian 12 or Ubuntu 24.04 with systemd, and bind to the loopback address 127.0.0.1 on mixed port 7890. First run ps -p 1 -o comm= and confirm PID 1 is systemd. The service-management steps won't apply as-is to containers, some WSL environments, or OpenRC systems.

Linux desktop: install a client and verify the proxy

Choose a package for your distro and CPU architecture

On the client downloads page, select Linux to see available packages and system requirements for clients such as Clash Verge Rev and FlClashs. Debian and Ubuntu typically use DEB packages; Fedora and similar distros typically use RPM. Run these commands first to avoid installing an ARM64 package on an x86_64 device.

uname -m
cat /etc/os-release
  • x86_64 usually maps to x64 or amd64; aarch64 usually maps to arm64.
  • Open DEB or RPM packages with your desktop software installer. If you run into dependency errors, use your distro's package manager rather than downloading shared libraries built for another system.
  • If the app installs but won't open, launch it from a terminal and keep the error output. Missing graphics libraries and proxy configuration issues are separate problems.

Import a config, then enable the system proxy

Import a compatible config provided by your service on the client's config or subscription page, switch to it, then check the connection logs and proxy groups. Menu names vary between clients, so use the options shown in your app. Enable the system proxy only after confirming the core is running and listening on port 7890.

If you need to set it manually, the usual path in GNOME is Settings → Network → Network Proxy → Manual. For both HTTP and HTTPS, enter host 127.0.0.1 and port 7890. Here, HTTPS refers to the proxy used for HTTPS requests; it does not mean the local listening port must use TLS.

The desktop system proxy provides connection settings to apps that honor them. Browsers may use it, but SSH, some games, and terminal tools may not. Turn off the system proxy before quitting the client. Otherwise, the desktop may still point to a port that is no longer listening, leaving pages unable to load.

Command-line setup: fixed paths for the binary, config, and data

Install the binary and create a dedicated service account

Get a Linux core compatible with your device's architecture and instruction set from the mihomo project's release channel. Extract it, name the executable mihomo, and place it in the current directory. Don't try to install the compressed archive as an executable. First check the architecture and version, then move the core to a fixed path.

file ./mihomo
chmod u+x ./mihomo
./mihomo -v
sudo install -m 0755 ./mihomo /usr/local/bin/mihomo

getent group mihomo >/dev/null || sudo groupadd --system mihomo
id mihomo >/dev/null 2>&1 || sudo useradd \
  --system --gid mihomo --home-dir /var/lib/mihomo \
  --no-create-home --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 example stores the config at /etc/mihomo/config.yaml and runtime data in /var/lib/mihomo. An administrator maintains the config, which the service account can read but not modify; cache and rule resources go in the data directory. Don't rely on the startup working directory or assume the SSH user's ~/.config will be used by a system service.

Start with a minimal config to verify the listener

This config is only for checking the service and local port. All requests go direct; it contains no proxy nodes and isn't a substitute for a real subscription. If you already have a config, back it up before running commands that could overwrite it. A minimal config helps rule out subscription format, remote rule downloads, and node availability as sources of trouble.

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
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 config; -d sets the working data directory; -f specifies the config file. Test again whenever you switch to a real config. Passing syntax checks doesn't mean a node is reachable or remote rule resources downloaded successfully; check the startup logs too.

If a subscription URL returns a Base64 node list, a web page, or a login prompt, you can't save it directly as a mihomo main config. Get a compatible, complete YAML config, or configure proxy-providers in a complete main config using the appropriate format. Subscription URLs often contain access credentials; don't share them in public logs or screenshots.

systemd service: startup, logs, and config changes

Create a system-level unit file. This setup runs under a dedicated unprivileged account and provides a local HTTP/SOCKS mixed proxy. TUN is disabled, so the core doesn't need to run permanently as root.

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
ExecStart=/usr/local/bin/mihomo -d /var/lib/mihomo -f /etc/mihomo/config.yaml
Restart=on-failure
RestartSec=5s
LimitNOFILE=65536
UMask=0077

[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
sudo ss -lntup | grep ':7890'
  • enable --now enables the service at boot and starts it immediately. Running enable alone won't start it right away.
  • Restart=on-failure retries after an unexpected exit, but won't restart the service after you stop it manually.
  • How long network-online.target actually waits depends on the system's network manager. It doesn't guarantee that a remote subscription server is reachable.
  • After the service shows active (running), confirm it's listening on 127.0.0.1:7890, not unexpectedly exposed on every network interface.

Config changes and unit changes require different steps

After editing the YAML, test it under the same service account, then restart the service. This unit doesn't define ExecReload, so don't assume systemctl reload is a universal way to apply changes. Restarting briefly interrupts existing proxy connections.

sudo -u mihomo /usr/local/bin/mihomo -t \
  -d /var/lib/mihomo -f /etc/mihomo/config.yaml
sudo systemctl restart mihomo.service
sudo journalctl -u mihomo.service -n 40 --no-pager

Run sudo systemctl daemon-reload only after changing /etc/systemd/system/mihomo.service or a related drop-in. Before updating the core, keep a backup of the old binary and config. Stop the service, replace the file, check mihomo -v and the config test, then start the service again.

Terminal proxy: environment variables only affect apps that read them

Once mihomo is listening on port 7890, set these variables in your current terminal. Most HTTP tools that support them will use the proxy, but this doesn't transparently proxy all Linux network traffic.

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 --connect-timeout 10 https://example.com
curl -I --proxy http://127.0.0.1:7890 https://example.com
curl -I --proxy socks5h://127.0.0.1:7890 https://example.com

socks5h lets the proxy resolve the destination hostname; socks5 typically resolves it locally first. The https_proxy value above still uses http:// because it points to a local HTTP proxy; HTTPS destinations are usually reached through a CONNECT tunnel.

With the minimal direct-connection config, a successful request that explicitly uses the proxy only proves the app can reach its target through the local core. To test a remote proxy node, switch to a working config, select a node in the proxy group, and check the connection logs for the actual rule and outbound route.

Persisting and undoing proxy settings

To apply these settings in every new Bash terminal, add the export lines above to ~/.bashrc; Zsh typically uses ~/.zshrc. GUI apps, scheduled jobs, and systemd services don't automatically read interactive shell config, so this doesn't mean proxying is enabled for them too.

unset http_proxy https_proxy all_proxy no_proxy
unset HTTP_PROXY HTTPS_PROXY ALL_PROXY NO_PROXY

sudo may filter proxy variables by default, and APT can have its own proxy settings. Don't pass your entire user environment to an administrator process just to download something temporarily. For a one-off curl test, use the explicit --proxy option; for apps that don't support proxy variables, check their own proxy settings.

Common issues: troubleshoot config, permissions, ports, then routing

Service exits on startup: check whether the service account can read the config

sudo journalctl -u mihomo.service -b -n 100 --no-pager
namei -l /etc/mihomo/config.yaml
sudo -u mihomo test -r /etc/mihomo/config.yaml && echo readable
sudo -u mihomo test -w /var/lib/mihomo && echo writable

permission denied may not come from the config file itself. A parent directory may lack execute permission, or remote rule files may point to a location the service account can't write to. Fix ownership and grant only the permissions needed on the target directory; don't mask the issue with chmod -R 777. On systems with SELinux enabled, check the relevant denial logs rather than disabling the security mechanism.

Port 7890 is in use: check whether two cores are running

sudo ss -lntp 'sport = :7890'
pgrep -a mihomo

A desktop client, manually launched core, and systemd service may all be running at once. Identify which process owns the port, then stop the one you don't need; don't kill every process with the same name. If you need to switch to 7891, update mixed-port, the desktop proxy, and terminal variables together. Restart and check the listener again.

Service is running but requests fail: distinguish proxy access from outbound issues

  • Connection refused: The port may not be listening, the process may have exited, or the address may be wrong. Check ss first; don't change routing rules yet.
  • Timeout after connecting to the proxy: Check the core logs for node connection, DNS resolution, and rule-resource errors. A matching rule doesn't mean the outbound route is working.
  • Certificate error: Check the system clock, CA certificates, and destination hostname. Don't disable TLS verification as a permanent fix.
  • Service stops retrying after repeated startup failures: Fix the underlying issue, run sudo systemctl reset-failed mihomo.service, then start the service.

For TUN, handle permissions, DNS, and remote-access risks separately

The unprivileged service in this example isn't a complete TUN setup. Linux TUN typically needs access to /dev/net/tun; configuring a virtual interface and routes also requires the appropriate network permissions. Plan capabilities, service restrictions, and DNS handling together. Adding enable: true to the YAML alone won't do it.

Especially on an SSH server, keep a second admin session or console available before enabling automatic routing. Plan the return path for SSH traffic, LAN subnets, and internal DNS. Verify the explicit local proxy on port 7890 first, then introduce TUN. Don't change the port, DNS, and default route all at once, or it will be hard to tell what caused the lockout.

Config maintenance: keep a recovery path and know what you're updating

After setup, record at least the binary path, config path, data directory, listening port, and service name. Subscription, core, and client updates are separate: replacing the core won't update nodes, and systemd startup won't refresh the main config.

  • With a GUI client, check the config page's auto-update toggle and interval, then verify the updated config is active.
  • For a standalone core, the update interval for proxy-providers applies only to the relevant provider; it doesn't periodically replace the entire main YAML.
  • Automating main-config downloads requires a safe workflow for downloading, testing, replacing, and rolling back on failure. Never overwrite the live config with an untested response.
  • To stop using the system service, run sudo systemctl disable --now mihomo.service, then remove the terminal variables and desktop proxy settings too.

For everyday desktop use, a GUI client is often the simplest option; for unattended systems, fixed paths and a systemd service are a better fit. Either way, first confirm where the config is read from, which port the process listens on, and how apps connect. Then add rule-based routing and TUN one step at a time. See the protocol reference for configuration concepts and the configuration guide for walkthroughs.