Skip to main content
EN

Home / Blog / Advanced

Running the Mihomo core from the command line, from unpack to systemd

Running the Mihomo core from the command line, from unpack to systemd

Servers, routers and NAS boxes have no desktop, so installing Clash Verge there makes no sense. Run the Mihomo core instead — it is a single command-line binary.

This walks through the whole thing on Linux amd64.

1. Download and install

What we host is a .gz archive containing one executable:

# extract
gunzip mihomo-linux-amd64-v1.19.29.gz

# make it executable
chmod +x mihomo-linux-amd64-v1.19.29

# put it on PATH with a shorter name
sudo mv mihomo-linux-amd64-v1.19.29 /usr/local/bin/mihomo

# verify
mihomo -v

You should get a version string and build information.

2. Prepare a working directory

Mihomo needs somewhere to keep its config and data files:

sudo mkdir -p /etc/mihomo
cd /etc/mihomo

Put your config.yaml in there. If you have a subscription URL, download it:

sudo curl -L -o /etc/mihomo/config.yaml \
  -A "clash.meta" \
  "your-subscription-url"

At minimum the config needs these to work:

mixed-port: 7890          # combined HTTP + SOCKS5 port
allow-lan: true           # let other LAN devices connect
bind-address: "*"
mode: rule
log-level: info
external-controller: 0.0.0.0:9090   # control API
secret: "set your own password"      # API password, mandatory if reachable

3. Run it in the foreground first

mihomo -d /etc/mihomo

-d sets the working directory. A healthy start looks like:

INFO[0000] Start initial configuration in progress
INFO[0000] Geodata Loader mode: memconservative
INFO[0000] HTTP proxy listening at: [::]:7890
INFO[0000] RESTful API listening at: [::]:9090

Once you see listening at, it is up.

Confirm it works, Ctrl+C to stop, then turn it into a service.

Deployment sequenceDownload and extractsingle binaryPrepare configconfig.yaml in the working directoryRun in foregroundconfirm it startsWrite a systemd unitmake it persistentEnable at bootsystemctl enable
Do not skip the foreground run — config errors are clearest there

4. The systemd unit

Create /etc/systemd/system/mihomo.service:

[Unit]
Description=Mihomo Daemon
Documentation=https://wiki.metacubex.one
After=network.target nss-lookup.target

[Service]
Type=simple
User=root
LimitNPROC=500
LimitNOFILE=1000000
CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_RAW CAP_NET_BIND_SERVICE CAP_SYS_TIME CAP_SYS_PTRACE CAP_DAC_READ_SEARCH
AmbientCapabilities=CAP_NET_ADMIN CAP_NET_RAW CAP_NET_BIND_SERVICE CAP_SYS_TIME CAP_SYS_PTRACE CAP_DAC_READ_SEARCH
Restart=always
RestartSec=5
ExecStartPre=/usr/local/bin/mihomo -t -d /etc/mihomo
ExecStart=/usr/local/bin/mihomo -d /etc/mihomo

[Install]
WantedBy=multi-user.target

The ExecStartPre line runs a config check (-t for test). A broken config then fails the check instead of taking down a running service — a small detail that saves a lot of grief.

sudo systemctl daemon-reload
sudo systemctl enable mihomo      # start at boot
sudo systemctl start mihomo       # start now
sudo systemctl status mihomo      # check

active (running) means you are done.

Day-to-day commands

sudo systemctl restart mihomo     # after changing the config
sudo systemctl stop mihomo
journalctl -u mihomo -f           # follow the log
journalctl -u mihomo -n 100       # last 100 lines

5. Letting other devices use it

allow-lan: true already permits LAN access. Other devices just point their proxy at this machine's IP and port:

LAN sharingPhone laptop Router or NAS192.168.1.10:7890Mihomo coredecides by rulesInternetLocal traffic exits directly from this machine without touching a node
Configure one device, every device benefits

On the client devices:

  • Windows: Settings → Network & Internet → Proxy → Manual → enter 192.168.1.10 and 7890
  • Phone (Wi-Fi): long-press the current network → Modify → Advanced → Proxy: Manual → same address and port
  • Router level: if the router itself is the gateway, you can pair this with TUN/TProxy for transparent proxying so every device is covered automatically (a more involved setup, not covered here)

6. The control API and a web panel

external-controller: 0.0.0.0:9090 exposes a RESTful API for switching nodes, inspecting connections and reloading the config.

Quick check:

curl -H "Authorization: Bearer your-secret" http://127.0.0.1:9090/version

Useful endpoints:

EndpointPurpose
GET /proxiesList all nodes and policy groups
PUT /proxies/{group}Switch the selected node in a group
GET /connectionsCurrent connections
DELETE /connectionsClose all connections
GET /logsLive log stream
PUT /configs?force=trueReload the config

Paired with a web panel you get something close to a graphical client. Put the panel files in a local directory and point external-ui at it:

external-ui: /etc/mihomo/ui
external-ui-name: metacubexd

Then visit http://server-ip:9090/ui in a browser.

7. Keeping the subscription updated

A headless deployment has no client to refresh the subscription, so use cron:

sudo crontab -e

Add a line (update at 4am and restart):

0 4 * * * curl -L -A "clash.meta" -o /etc/mihomo/config.yaml "your-subscription-url" && systemctl restart mihomo

A safer version downloads to a temporary file, validates it, and only then replaces the live config:

#!/bin/bash
TMP=$(mktemp)
curl -fsSL -A "clash.meta" -o "$TMP" "your-subscription-url" || exit 1
# minimal sanity check: it must contain a proxies section
grep -q "^proxies:" "$TMP" || { rm -f "$TMP"; exit 1; }
mv "$TMP" /etc/mihomo/config.yaml
systemctl restart mihomo

Save it as /usr/local/bin/update-mihomo.sh, chmod +x, and call it from cron. That way a temporarily broken subscription endpoint cannot overwrite a good config with an error page.

Common problems

Fails to start with unmarshal error The YAML is invalid, or uses a field this core version does not know. Run mihomo -t -d /etc/mihomo for a config check.

Port already in use sudo ss -tlnp | grep 7890 shows what has it. Change the port in the config or stop the other process.

GeoIP database will not download Fetch geoip.metadb and geosite.dat manually into the working directory, or disable auto-update:

geo-auto-update: false

In short

Four steps: put the binary somewhere, put a config next to it, make it a systemd service, and firewall the port.

Once running it is a background service that needs essentially no maintenance — considerably less work than installing a client on every device.

Related: sharing a proxy across your LAN and installing Clash Verge on Linux.