Clash Verge is a desktop app; without X or Wayland it will not start. The core, however, is a plain command-line program, and running it directly does everything the desktop build does on your behalf.

Four steps to a working service

  1. Download the archive for your architecture from the mihomo release page (check with uname -m), extract it, make it executable and put it at /usr/local/bin/mihomo.
  2. Create a working directory at /etc/mihomo and place your config as config.yaml. The file from your desktop works as is; client-specific fields are simply ignored by the core.
  3. Write the service unit below.
  4. systemctl daemon-reload && systemctl enable --now mihomo.
[Unit]
Description=mihomo daemon
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
ExecStart=/usr/local/bin/mihomo -d /etc/mihomo
Restart=on-failure
RestartSec=3

[Install]
WantedBy=multi-user.target

If you need TUN, add AmbientCapabilities=CAP_NET_ADMIN rather than running the whole service as root.

Sponsored Where does the subscription link come from? Our partner provider gives you 1 GB of high-speed Hong Kong data at signup — import it in one click. Get high-speed nodes

With no window, the log is everything

curl requests against the mihomo external controller API on port 9097
With no GUI, the external controller API is your console

journalctl -u mihomo -f follows the log live. A malformed config makes the core exit and print the offending line, which is more direct than hunting through a GUI. When the service will not start, look here first — the answer is usually one line.

For more detail, temporarily set log-level to debug in the config and put it back to info afterwards. Debug output is voluminous and will fill a small disk if you leave it on.

Using it and managing it

Command-line tools on the same box need environment variables, as described in proxying the terminal:

export https_proxy=http://127.0.0.1:7897
export http_proxy=http://127.0.0.1:7897

To drive it from a dashboard, do not bind external-controller to 0.0.0.0. Keep it on 127.0.0.1:9097 and bring the port to you over SSH when you need it:

ssh -L 9097:127.0.0.1:9097 user@your-server

Then point a local dashboard at 127.0.0.1:9097. What the API can do is covered in the external controller guide.

external-controller: 0.0.0.0:9097 with a weak secret publishes control of your core to the internet. Scanners find that within hours.

Automating subscription updates

No client means no scheduled refresh, so cron does it: fetch the subscription over the existing config, then restart the service. A restart drops every live connection, so run it when nobody is using the box — 4 a.m. is the usual answer.

Validate before you swap: mihomo -t -d /etc/mihomo parses the config and reports errors. Only overwrite and restart if it passes, otherwise one bad subscription puts the service into a restart loop. If you would rather tune the config on a desktop first and move it over, start from the Linux install guide.