Choose a setup: desktop client or standalone core

mihomo is a proxy core compatible with the Clash configuration ecosystem and is commonly found in clients and configurations labeled Clash Meta. The core listens on proxy ports, matches rules, and establishes connections. A graphical client adds subscription management, node selection, and system proxy controls. Installing the core alone won’t add a system tray icon or change your browser’s proxy settings.

Use caseRecommended setupHow you manage it
Everyday desktop with GNOME, KDE, or similarA graphical client with Linux supportImport subscriptions and switch rules and nodes in the interface
Server managed over SSHmihomo binary with systemdEdit YAML and review service logs
Container or minimal distributionCheck the init system firstIf PID 1 is not systemd, use the appropriate process manager

The service setup in this guide is for standard Linux hosts running systemd. It starts with an explicit proxy available only on the local machine. With an explicit proxy, an app sends requests to a specified port; this is not a transparent proxy and does not automatically route every connection on the server.

Desktop setup: install a Linux client and import a configuration

Check your distribution and CPU architecture

Open a terminal and run these two commands. The first identifies your distribution; the second reports the CPU architecture. x86_64 usually corresponds to x64 or amd64 downloads, while aarch64 usually corresponds to arm64. Don’t download an ARM package just because the machine has an Intel or AMD processor.

cat /etc/os-release
uname -m
  1. Visit the download page and choose a client with a Linux package, such as Clash Verge Rev or FlClash. Before downloading, check the platforms and architectures supported by that release.
  2. For Debian and Ubuntu-based distributions, choose the corresponding DEB package. For Fedora and similar distributions, choose the RPM package. AppImage availability depends on whether the publisher provides one and whether runtime dependencies such as FUSE are installed.
  3. Launch the client and open its subscription or configuration manager. Add the subscription URL, update it, then select the configuration. Menu names vary by client and may be “Subscriptions” or “Profiles.” Don’t import a node share string as if it were a complete YAML file.
  4. Choose a rule mode and an available node, then enable the system proxy. Check the connection log to confirm requests are reaching the active client.

For a package already downloaded and renamed to client.deb, run sudo apt install ./client.deb from its directory. The user renames the file; this is not the name of a package downloaded from this site. For an RPM package, rename it to client.rpm and run sudo dnf install ./client.rpm.

System proxy vs. terminal proxy

On GNOME, check the current settings under “Settings” → “Network” → “Network Proxy.” The exact location varies slightly by desktop version. Browsers may follow these settings, but command-line tools in a terminal may not. Check the mixed port shown by the client. If it’s 7890, use curl --proxy below to test it directly instead of repeatedly toggling the system setting.

“Launch at login” on a desktop is different from “start at boot” on a server. The former usually requires a user to sign in to a graphical session; the latter can run with no one logged in. If you need a proxy as soon as you connect to a host over SSH, the systemd setup below is a better fit.

Server setup: install the binary and create a dedicated service account

First run ps -p 1 -o comm= and confirm the output is systemd. Then download the mihomo Linux binary that matches the output of uname -m, extract it, and rename the file to mihomo. Some x86 builds also specify a CPU instruction-set level. If you see Illegal instruction, check the build requirements rather than changing the program’s permissions.

The commands below assume the extracted mihomo file is in the current directory. Grant it execute permission, then check that it runs. The -v output shows the installed version for your records and makes rollback easier.

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

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

This creates a dedicated system account for the service, not an account for interactive login. If a mihomo account already exists, run id mihomo to check its user and group, then skip account creation. A separate account makes it easier to control access to the configuration and runtime data. This setup does not require running the entire service as root.

  • /usr/local/bin/mihomo: stores the core executable.
  • /etc/mihomo/config.yaml: stores the administrator-managed configuration.
  • /var/lib/mihomo: stores runtime data; the systemd unit below creates the directory and sets its permissions.

Start with a minimal YAML configuration and verify the port

YAML is a text format that uses indentation to structure fields. Use spaces, not tabs. Start with the minimal configuration below to establish a working baseline: it listens only on localhost port 7890 for both HTTP proxy and SOCKS5 connections, and sends all requests directly without any proxy nodes.

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 /tmp -f /etc/mihomo/config.yaml

To route traffic through proxies, replace this with a complete mihomo configuration from a trusted source. A complete configuration typically includes proxies, proxy-groups, and rules; every policy group referenced by a rule must exist. A provider file containing only a set of nodes, a Base64-encoded node string, or a subscription webpage is not a complete configuration you can pass directly to -f.

After replacing the configuration, keep the listener restricted to localhost and run the configuration check again. Subscription URLs may contain access tokens, and configuration files may contain node credentials. Don’t paste them into public logs, screenshots, or shell history. If the configuration uses relative paths, this service uses /var/lib/mihomo as its data directory. Check that it can also read rule and provider files.

Create a systemd service and enable it at boot

A systemd unit defines how a process starts, which account it runs under, and what happens if it fails. Save the following as /etc/systemd/system/mihomo.service. This unit is for standard proxy ports; it does not configure TUN or grant network administration privileges.

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
StateDirectory=mihomo
StateDirectoryMode=0750
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=5s
UMask=0077
NoNewPrivileges=true
PrivateTmp=true
ProtectHome=true
ProtectSystem=strict

[Install]
WantedBy=multi-user.target
UNIT

sudo systemctl daemon-reload
sudo systemctl enable --now mihomo
systemctl status mihomo --no-pager
systemctl is-enabled mihomo

active (running) means the process is running; an enabled result from is-enabled means it’s configured to start at boot. Check both separately: a service can be enabled at boot but fail to start because of a configuration error.

StateDirectory=mihomo creates a writable data directory. ProtectSystem=strict restricts writes to the rest of the filesystem, and ProtectHome=true restricts access to users’ home directories. Don’t point the configuration to subscription files under /home. If you need additional resources, put them in an appropriate data directory and check ownership and permissions.

network-online.target sets the service start order to wait for the network, but its effect depends on whether the distribution has enabled the corresponding wait-online service. It doesn’t guarantee that a subscription server is reachable at that moment. If the configuration downloads rules remotely, use the logs to distinguish a network readiness issue from an unavailable remote resource.

What to do after changing the configuration

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

Restart only after the configuration check succeeds. Editing YAML does not require daemon-reload; editing the service unit does. This example does not define ExecReload, so don’t use systemctl reload mihomo instead of restarting. A restart interrupts active proxy connections, so avoid doing it during long downloads or remote tasks.

Test requests: listener, HTTP proxy, and SOCKS5

Troubleshoot in this order: process running → port listening → application request → rule match. Start by checking port 7890. The expected listener is 127.0.0.1:7890, not a public interface.

sudo ss -lntp 'sport = :7890'

curl --proxy http://127.0.0.1:7890 \
  --connect-timeout 10 --max-time 20 \
  -I https://example.com

curl --proxy socks5h://127.0.0.1:7890 \
  --connect-timeout 10 --max-time 20 \
  -I https://example.com

The 10-second value is the connection timeout, and 20 seconds is the overall request timeout; neither is a performance benchmark. With socks5h, the proxy resolves the destination hostname. With socks5, curl typically resolves it locally, which can change the conclusions of DNS troubleshooting.

With the minimal configuration, a successful request only confirms that the local proxy path and direct connection work. After switching to your actual configuration, check the logs for the matched rule and selected policy group, and confirm the request didn’t match DIRECT. An HTTP status code alone doesn’t prove that a particular remote node was used.

Use the proxy only in the current terminal

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 --max-time 20 https://example.com

unset http_proxy https_proxy no_proxy

The value for https_proxy can still use http://. This means the client establishes a CONNECT tunnel through an HTTP proxy; it does not downgrade the destination HTTPS connection to plaintext. Environment variables affect only programs that read them. A systemd service that’s already running won’t inherit settings from the current terminal. Lowercase variables are used here to avoid special handling of uppercase HTTP_PROXY by some tools.

Common issues and deployment limits

Service fails to start or keeps restarting

  • 203/EXEC error: Check the ExecStart path, execute permissions, and binary architecture. Don’t put an archive that hasn’t been extracted at the executable path.
  • address already in use error: Use ss to find the process occupying port 7890. A second desktop client or an old core is a common cause.
  • permission denied error: Check that the configuration file belongs to the mihomo group and that every directory in its path is accessible. Don’t make a sensitive configuration readable by every user.
  • YAML parsing error: Check indentation, colons, and list levels, especially for tabs introduced when copying from a webpage. Run the configuration check with -t before starting the service.
  • Start-rate limit reached: Fix the underlying issue first, then run sudo systemctl reset-failed mihomo and sudo systemctl start mihomo. Don’t just keep restarting the service.

Subscription updates, the controller API, and TUN

A standalone core doesn’t automatically handle subscription updates like a graphical client. You need to arrange how a complete remote configuration is fetched and replaced. Download it to a temporary file, restrict its permissions, check its syntax, and only then replace the current configuration. A proxy-providers entry can refresh the set of nodes at its configured interval, but that does not update the main configuration file.

This example does not enable external-controller, so it does not provide a management API. If you need a dashboard, plan for a loopback listener, an access key, and an SSH tunnel. Don’t expose the management port directly to the public internet. With allow-lan: false and a localhost listener, other devices on the LAN also can’t use this server as a proxy directly.

TUN routes traffic through a virtual network interface and also involves /dev/net/tun, routing, DNS, and network permissions. The unprivileged account and hardened unit in this guide are not a TUN setup; adding enable: true alone is not enough. If you manage a server over SSH, preserve a direct path for your management connection before designing transparent traffic routing.

Upgrade or stop the service

Before upgrading, record the output of mihomo -v and back up the current binary and configuration. Stop the service before replacing the binary. Check the new file’s architecture, version, and configuration compatibility, then start the service and repeat the port and request tests. To stop the service and disable it at boot, run the command below. This does not delete the configuration or runtime data.

sudo systemctl disable --now mihomo

A complete deployment check should confirm four things: the configuration passes validation, the service is running, the listener address is correct, and an actual application request matches the expected rule. For desktop use, focus on selecting a configuration and setting the system proxy. For servers, focus on account permissions, service logs, and a repeatable startup process.