Skip to content
aBER

Environment and Installation

System Environment

Linux distribution: Ubuntu 24.04.4 LTS

Install Mihomo

The official Mihomo project is:

MetaCubeX/mihomo

It is itself a binary program compiled in Go, so it does not require Python or pip.

My server is linux amd64, and the installation is:

Mihomo Meta v1.19.30

Download via GitHub CLI:

Terminal window
cd /tmp
gh release download v1.19.30 -R MetaCubeX/mihomo -p 'mihomo-linux-amd64-v1-v1.19.30.gz'

After the download is complete:

Terminal window
gunzip mihomo-linux-amd64-v1-v1.19.30.gz

Install:

Terminal window
install -m 755 mihomo-linux-amd64-v1-v1.19.30 /usr/local/bin/mihomo

Check:

Terminal window
mihomo -v

My output:

Mihomo Meta v1.19.30 linux amd64 with go1.26.6 Sun Aug 16 10:02:19 UTC 2026
Use tags: with_gvisor

Configuration Directory

Store all Mihomo data in one place:

/etc/mihomo

Create:

Terminal window
mkdir -p /etc/mihomo

Main configuration:

/etc/mihomo/config.yaml

Mihomo is used at startup:

Terminal window
mihomo -d /etc/mihomo

Mihomo Configuration

Subscription Management

Nodes are not written directly into the main configuration, but are managed through proxy-providers:

proxy-providers:
Airport Subscription:
type: http
url: "Your subscription URL"
path: ./sublinks/airport.yaml
interval: 86400
health-check:
enable: true
url: https://www.gstatic.com/generate_204
interval: 300

This way, the main configuration handles rules, while the subscription handles nodes. After updating the subscription, there is no need to regenerate the entire configuration.

I use Sublink for subscription aggregation, so the directory is named sublinks/.

Automatic Node Selection

- name: Automatic Selection
type: url-test
use:
- Airport Subscription
exclude-filter: "(?i)套餐|到期|剩余|流量|重置|官网|文档|下载|通知"
url: https://www.gstatic.com/generate_204
interval: 300
tolerance: 50

Manually select a region for overseas traffic:

- name: Overseas Websites
type: select
proxies:
- Automatic Selection
- Japan
- Hong Kong
- Singapore
- United States
- All Nodes
- DIRECT

Automatically Filter Nodes by Region

Different countries and regions use url-test to select nodes.

For example, Japan:

- name: Japan
type: url-test
use:
- Airport Subscription
filter: "(?i)日本|东京|大阪|Japan|\\bJP\\b|🇯🇵"
exclude-filter: "(?i)套餐|到期|剩余|流量|重置|官网|文档|下载|香港|新加坡|台湾|美国"
url: https://www.gstatic.com/generate_204
interval: 300
tolerance: 20

Other regions follow the same logic:

Hong Kong
Japan
Singapore
United States
...

DNS and Fake-IP

Mihomo manages DNS itself:

dns:
enable: true
listen: 127.0.0.1:7874
ipv6: false
prefer-h3: false
enhanced-mode: fake-ip
fake-ip-range: 198.18.0.1/16
fake-ip-filter:
- +.lan
- +.local
- time.*.com
- ntp.*.com

Mainland China DNS:

nameserver:
- https://120.53.53.53/dns-query
- https://223.5.5.5/dns-query

And specify separately for Mainland China sites:

nameserver-policy:
geosite:private: system
geosite:cn,steam@cn,category-games@cn,microsoft@cn,apple@cn:
- 119.29.29.29
- 223.5.5.5
- 1.12.12.12
- 114.114.114.114

On the server, limit DNS listening to:

listen: 127.0.0.1:7874

Instead of:

listen: :7874

This avoids accidentally exposing the DNS service.

Service Traffic Routing

In addition to Mainland China and overseas traffic, separate policy groups can be established for several commonly used services.

For example, GitHub:

- name: GitHub
type: select
proxies:
- Overseas Websites
- DIRECT

Google:

- name: Google
type: select
proxies:
- Blocked Websites
- DIRECT

OpenAI:

- name: openAi
type: select
proxies:
- All Nodes
- Blocked Websites
- DIRECT

You can also route these services separately:

YouTube
Netflix
Twitter
TikTok
Facebook
Discord
OneDrive
Microsoft
Steam
Cloudflare
...

Rule Provider

The rules themselves are not all written into config.yaml, but are instead managed through a remote Rule Provider.

For example:

GitHub-rule:
type: http
interval: 86400
behavior: classical
format: yaml
url: https://cdn.jsdelivr.net/gh/blackmatrix7/ios_rule_script@master/rule/Clash/GitHub/GitHub.yaml
path: ./ruleset/blackmatrix7/GitHub.yaml

Then:

rules:
- RULE-SET,GitHub-rule,GitHub

Ad Blocking:

- RULE-SET,Ad Blocking-rule,Ad Blocking

The final fallback logic:

- RULE-SET,cncidr,DIRECT,no-resolve
- RULE-SET,direct,DIRECT
- GEOSITE,gfw,Blocked Websites
- GEOIP,CN,Domestic Websites
- MATCH,Blocked Websites

The overall logic is roughly:

Advertisements
↓
REJECT
Domestic websites / CN IP
↓
DIRECT
Overseas services
↓
Proxy
Unrecognized traffic
↓
Proxy

Finally, use:

MATCH,Blocked Websites

There is a practical benefit: even if a foreign website is not in the GFWList, it will not therefore accidentally use a direct connection.

TUN Transparent Proxy

TUN Configuration

What truly makes Mihomo the core of the Linux Server system proxy is TUN.

My configuration:

tun:
enable: true
stack: mixed
auto-route: true
auto-redirect: false
auto-detect-interface: true
dns-hijack:
- any:53
- tcp://any:53
mtu: 1500
device: mihomo
strict-route: false

Among these:

stack: mixed

is relatively universal on current Mihomo.

After auto-route is enabled, system traffic will automatically enter the Mihomo TUN.

Excluding Docker, Tailscale, and the Internal Network

route-exclude-address:
- 10.0.0.0/8
- 100.64.0.0/10
- 169.254.0.0/16
- 172.16.0.0/12
- 192.168.0.0/16

Among these:

10.0.0.0/8
172.16.0.0/12
192.168.0.0/16

is a common private network.

Docker is also typically in:

172.16.0.0/12

Within the scope.

Tailscale uses:

100.64.0.0/10

Therefore, after excluding these addresses:ablytyped

SSH
Docker
Local Area Network
Tailscale

Will not have its routes rewritten by Mihomo TUN.

The overall structure becomes:

flowchart TD
A[Linux Server] --> B[LAN / Docker / Tailscale]
B --> C[DIRECT]

A --> D[Internet]
D --> E[Mihomo TUN]
E --> F[Rule Matching]
F --> G[DIRECT]
F --> H[Proxy]

Proxy Ports on the Server

I keep a Mixed Port:

mixed-port: 9870

Because even with TUN already enabled, an explicit proxy port is still convenient for testing, Docker, or certain programs.

For example:

Terminal window
curl -x http://127.0.0.1:9870 https://github.com

If Docker or the local network needs access, then:

allow-lan: true
bind-address: "*"

But do not directly use:

lan-allowed-ips:
- 0.0.0.0/0

Otherwise, a public server can easily become an open proxy by accident.

You can restrict it to:

lan-allowed-ips:
- 127.0.0.0/8
- 10.0.0.0/8
- 172.16.0.0/12
- 192.168.0.0/16

If only the local machine uses it, it is even simpler:

allow-lan: false
bind-address: 127.0.0.1

Service Management

Persistent systemd Service

Create:

/etc/systemd/system/mihomo.service

Content:

[Unit]
Description=Mihomo Proxy Service
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=root
ExecStart=/usr/local/bin/mihomo -d /etc/mihomo
Restart=on-failure
RestartSec=3
LimitNOFILE=1048576
AmbientCapabilities=CAP_NET_ADMIN CAP_NET_RAW CAP_NET_BIND_SERVICE
CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_RAW CAP_NET_BIND_SERVICE
NoNewPrivileges=true
[Install]
WantedBy=multi-user.target

Loading:

Terminal window
systemctl daemon-reload

Starting:

Terminal window
systemctl enable --now mihomo

View status:

Terminal window
systemctl status mihomo --no-pager

View real-time logs:

Terminal window
journalctl -u mihomo -f

Restart:

Terminal window
systemctl restart mihomo

Configuration Check and Restart

Terminal window
mihomo -t -d /etc/mihomo

After it passes:

Terminal window
systemctl restart mihomo

MetaCubeXD WebUI

Mihomo itself provides a Controller API, but does not include a traditional management page.

Here we use MetaCubeXD.

Configuration:

external-controller: 0.0.0.0:9090
external-ui: /etc/mihomo/ui
secret: "Set your own password"

Mihomo can also download it automatically:

external-ui: ui
external-ui-url: "https://github.com/MetaCubeX/metacubexd/archive/refs/heads/gh-pages.zip"

Then:

Terminal window
mihomo -t -d /etc/mihomo
systemctl restart mihomo

Test the API:

Terminal window
curl http://127.0.0.1:9090/version

Normally, it will return something like:

{
"meta": true,
"version": "1.19.30"
}

Test the WebUI:

Terminal window
curl -I http://127.0.0.1:9090/ui/

It should return:

HTTP/1.1 200 OK

If you wish to use it via Tailscale, you can:

external-controller: 0.0.0.0:9090

Final Network Structure

flowchart TD
A[Ubuntu Server]

A --> B[Private Network]
B --> C[Docker / LAN]
B --> D[Tailscale / SSH]
C --> E[Does not enter TUN]
D --> E

A --> F[Internet]
F --> G[Mihomo TUN]
G --> H[Rule Engine]
H --> I[DIRECT]
H --> J[Proxy]
J --> K[Automatically select node]

The management plane is:

flowchart TD
A[Mac] -->|Tailscale| B[Ubuntu Server]
B --> C[SSH]
B --> D[9090/ui/]
D --> E[MetaCubeXD]

Reference Materials