Choose how to run mihomo: desktop client or standalone service
For switching nodes and managing subscriptions on a Linux desktop, start with a graphical client. For a server that needs to run continuously without a desktop—or a proxy endpoint that should start before login—use the standalone mihomo core with systemd. Both approaches use the same configuration concepts, but differ in config locations, update workflows, and permissions. Client autostart and a system service are separate settings.
mihomo is a network processing core, also known as the Clash Meta core. A graphical client handles configuration, the interface, and system integration. Installing the core does not add a system tray, change GNOME proxy settings, or automatically route every command-line app through the proxy. This guide first sets up a proxy listening only on 127.0.0.1:7890, then checks whether apps actually connect to that port.
| Item | Desktop client | Standalone mihomo with systemd |
|---|---|---|
| Best for | Desktop use, subscription management, and switching nodes | Servers, fixed configurations, and background operation |
| When it starts | Usually after the user logs in | Can start during system boot |
| Configuration source | Client settings and subscription overrides | An explicitly specified YAML file |
| Where to find logs | Client log view | journalctl -u mihomo |
| Permissions | Regular user; TUN requires additional authorization | A dedicated, unprivileged service user |
Install a desktop client on Ubuntu, Debian, or Arch
Check your architecture and package format
Run these two commands first. x86_64 usually means an x64 or amd64 package; aarch64 usually means arm64. On Ubuntu or Debian, prefer a DEB package built for your distribution. Arch does not install DEB or RPM packages directly. Whether a client runs also depends on system libraries and the desktop environment—not just the CPU architecture.
uname -m
cat /etc/os-release
Visit the client downloads page to check available Linux packages and maintenance status. Compare the actual release support for clients such as Clash Verge Rev and FlClash. This guide doesn’t pin a client version. After installation, note the client version in its About page and the core version in the logs or core information page to help reproduce issues later.
- Ubuntu / Debian: Download the DEB package for your system. You can rename the local file to
client.deb, then runsudo apt install ./client.deb. This is just a local filename convention, not the package’s official name. - Arch: Choose an installation method maintained for Arch. Before using the AUR, review the PKGBUILD and download sources. AUR packages are community-maintained, not official repository packages. Don’t mix system libraries from another distribution just to make a package install.
- Portable package: If the publisher provides an AppImage, make it executable and run it. If you encounter a FUSE or graphics library error, install the dependencies specified for that release. Don’t work around the error by launching the graphical app as root.
Import a configuration, then check the local port
- In the client’s Configuration page, import a mihomo-compatible YAML file or subscription and confirm which one is enabled. Subscription URLs often contain credentials; don’t post them in public logs.
- In Settings, check the actual HTTP, SOCKS, or mixed-port value. This guide uses 7890 as the example mixed port. Your client may use a different default, so adjust the commands to match your settings.
- Turn off TUN first, and enable only the proxy endpoint you need to test. Check the logs to confirm the configuration loaded, then run the explicit proxy commands below.
- To connect desktop apps, enable System Proxy in the client. In GNOME, you can also check the address and port under Settings → Network → Network Proxy → Manual. Menu paths vary across desktop environments.
Desktop clients’ Start on boot option usually depends on the user session. If the service must run without anyone logged in, use the systemd setup below, and disable the desktop core’s autostart. Before quitting the client, make sure it has cleared the system proxy setting so the system doesn’t keep pointing to a closed port.
Standalone mihomo: Set up directories and a minimal configuration
Install the binary and create a dedicated user
Get a Linux binary for the matching architecture from a mihomo release source. Extract it according to the package format and name the executable mihomo. The commands below install that file from the current directory; they don’t assume a particular remote package filename. Confirm that the version command works before setting up the service.
chmod +x ./mihomo
./mihomo -v
sudo install -m 0755 ./mihomo /usr/local/bin/mihomo
sudo useradd --system --user-group --no-create-home \
--home-dir /var/lib/mihomo --shell /bin/false mihomo
sudo install -d -o root -g mihomo -m 0750 /etc/mihomo
sudo install -d -o mihomo -g mihomo -m 0750 /var/lib/mihomo
If the dedicated user already exists, don’t create it again. Check its identity and groups with id mihomo. Keep the binary under root’s control and runtime data owned by the service user. Restrict the configuration directory to root and the mihomo group. Subscription data may include node passwords, so don’t store it in a directory readable by everyone.
| Path | Purpose | Recommended permissions |
|---|---|---|
/usr/local/bin/mihomo | Core executable | Root-owned, 0755 |
/etc/mihomo/config.yaml | Main configuration and node settings | root:mihomo,0640 |
/var/lib/mihomo | Cache, rule providers, and runtime data | mihomo:mihomo,0750 |
/etc/systemd/system/mihomo.service | Service definition | Root-owned, 0644 |
Test the service with a direct-connection config—not a node configuration
Run sudoedit /etc/mihomo/config.yaml and add the configuration below. It provides only a local mixed proxy endpoint; all requests still connect directly. Use it to isolate installation, permission, and listening issues. Without proxy nodes, a successful start does not mean you have a remote proxy exit.
mixed-port: 7890
allow-lan: false
bind-address: 127.0.0.1
mode: rule
log-level: info
ipv6: false
tun:
enable: false
rules:
- MATCH,DIRECT
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
Use -f to specify the main configuration, -d for the data directory, and -t to test the configuration. A successful test means the config can be loaded; it doesn’t guarantee that remote nodes are reachable. After switching to a real subscription config, check policy group names, rule references, and provider paths. Keep relative runtime data paths in a writable data directory, not a desktop user’s private directory.
Run mihomo with systemd: Start, logs, and boot activation
Run sudoedit /etc/systemd/system/mihomo.service and add the complete service definition below. This setup is for a regular local proxy: it doesn’t enable TUN or bind to privileged ports such as 53. The working directory matches the writable data directory, and the configuration file remains read-only.
[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=5
UMask=0027
NoNewPrivileges=true
PrivateTmp=true
ProtectHome=true
ProtectSystem=strict
ReadWritePaths=/var/lib/mihomo
[Install]
WantedBy=multi-user.target
Whether network-online.target works as expected depends on whether the system has the relevant network-wait service enabled. It doesn’t guarantee that remote subscriptions will be reachable. If the first start needs to download rules or geodata, check the logs to confirm the downloads completed. For systems without network access at boot, prepare the required data in advance.
sudo systemd-analyze verify /etc/systemd/system/mihomo.service
sudo systemctl daemon-reload
sudo systemctl enable --now mihomo.service
systemctl status mihomo.service --no-pager
sudo journalctl -u mihomo.service -b -n 80 --no-pager
ss -lntp 'sport = :7890'
enable --nowboth enables the service at boot and starts it immediately. Runningenablealone won’t start the process right away.- The expected status is
active (running), and the port check should show a local listener on 7890. When run as a regular user,ssmay not show the process name for another user’s process. - After updating the configuration, run the
-ttest again, then runsudo systemctl restart mihomo. Changing YAML doesn’t requiredaemon-reload; changing the service file does. - To stop the service temporarily, run
sudo systemctl stop mihomo. To also disable it at boot, runsudo systemctl disable --now mihomo.
This guide doesn’t configure ExecReload, so don’t use systemctl reload instead of restarting the service. If you add an external controller for hot-reloading configuration, plan its authentication and listening scope separately. The basic service doesn’t need an exposed control port just to provide a management panel.
Verify the proxy path: Check the port, request, and rules separately
Specify the proxy explicitly before checking environment variables
These commands test HTTP proxy and SOCKS5 proxy access, respectively. --noproxy "" clears the bypass list for this request, preventing an existing NO_PROXY setting from skipping the proxy. The SOCKS example uses socks5h so the proxy resolves the destination hostname.
curl --noproxy "" -I --connect-timeout 10 --max-time 20 \
-x http://127.0.0.1:7890 https://example.org/
curl --noproxy "" -I --connect-timeout 10 --max-time 20 \
--proxy socks5h://127.0.0.1:7890 https://example.org/
An HTTP response means the request completed; check the core logs as well to confirm which rule matched. The minimal config will show a direct connection. With real nodes configured, check that the expected policy group matched and which node it selected. A successful latency test doesn’t replace an actual HTTPS request.
If the explicit proxy test succeeds but regular terminal commands still bypass the proxy, set environment variables temporarily in the current shell. Variable names vary by app; the example below works with many common command-line tools but won’t route every app on the system.
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 --max-time 20 https://example.org/
unset http_proxy https_proxy all_proxy no_proxy
Using http:// for https_proxy is intentional: it tells the client to reach HTTPS destinations through an HTTP proxy’s CONNECT tunnel. If you add these variables to a shell config file, remember to unset them when the service stops. Browsers, APT, and other services launched by systemd may not inherit them; configure each app separately.
Diagnose common failures by error type
- Connection refused: First check whether 7890 is listening, then verify the port and service status. Don’t start by changing nodes.
- Address already in use: Check whether a desktop client or an old core process has taken the port. Keep only one listener.
- Permission denied: Check permissions on the file and its parent directories, then test the configuration as the service user. Don’t mask the cause with
chmod 777. - Rule or data download failed: Check provider URLs, whether the data directory is writable, and whether the network is available at startup. Preserve the full error context before deciding whether DNS is the problem.
- Service keeps restarting: Use
journalctlto find the earliest configuration or resource error. After fixing it, if systemd has rate-limited restarts, runsudo systemctl reset-failed mihomobefore starting the service again.
TUN and updates: Keep permission boundaries intact
TUN requires more than setting enable to true
TUN needs access to /dev/net/tun and typically requires network administration permissions to create interfaces and manage routes and DNS. Checking ls -l /dev/net/tun confirms only that the device node exists; it doesn’t prove the service has the required permissions. The unprivileged service in this guide deliberately lacks them, so it can’t be used for TUN as-is.
For TUN, use an authorization service provided by your client, or redesign the systemd permissions and capability restrictions according to the documentation for your mihomo version. Don’t simply switch the service user to root and copy all the other settings unchanged. Disable any other traffic interception first, define the DNS listening port and routing scope, and decide whether LAN traffic should be captured. Then test LAN access and verify that routes are restored after stopping the service.
Record the version before updating, then repeat the checks
- Record the output of
/usr/local/bin/mihomo -v, and back up the current binary and configuration. Keep the backup config’s permissions restricted as well. - Download the new core for your architecture, then run its
-vand-tchecks first. Test it as the service user with the same data directory. - Stop the service, replace the binary using
install -m 0755, then start it again. Don’t try to overwrite a file while it’s running. - Recheck the logs, the listener on 7890, and an HTTPS request. If the new version causes compatibility issues, stop the service, restore the previous binary and configuration, and restart.
Check three things before calling the deployment complete: systemd runs the process reliably, local apps can reach the proxy port, and real requests match the intended rules and nodes. All three must pass. For more on the basics, see the Getting Started guide. If browser and terminal results differ, use the Troubleshooting guide to check how each app gets its proxy settings.