部署架構與執行邊界
Linux 伺服器通常不需要圖形化客戶端。較穩定的做法是讓 mihomo 核心以獨立系統服務執行,由 systemd 負責啟動、重新啟動、權限收斂與日誌收集。設定檔放在 /etc/mihomo/,可寫入的執行資料放在 /var/lib/mihomo/,二進位檔固定於 /usr/local/bin/mihomo。如此一來,更新程式、修改設定與清理快取時不會彼此混在一起。
本文以 Ubuntu 24.04.2 LTS、Debian 12.10、systemd 255/252 與 mihomo 1.19.10 作為參考環境。不同發行版的套件管理指令可能不同,但 systemd 服務、TUN 裝置與 Linux capabilities 的處理思路一致。若使用原始 Clash 核心,部分 TUN、DNS 與規則提供者參數可能不存在,建議先執行版本指令確認實際核心類型。
uname -m
/usr/local/bin/mihomo -v
systemctl --version
ip -Version
uname -m 常見結果包括 x86_64、aarch64 或 armv7l;下載二進位檔時必須符合 CPU 架構。版本輸出應清楚顯示 mihomo 版本與建置資訊;若指令直接出現「Exec format error」,通常是架構選錯,而不是檔案權限問題。
| 路徑 | 用途 | 建議權限 |
|---|---|---|
/usr/local/bin/mihomo |
固定的核心可執行檔 | root:root 0755 |
/etc/mihomo/config.yaml |
主要設定、代理與規則入口 | root:clash 0640 |
/var/lib/mihomo/ |
Geo 資料、規則快取與執行資料 | clash:clash 0750 |
/etc/systemd/system/mihomo.service |
systemd 服務單元 | root:root 0644 |
安裝二進位檔與獨立服務使用者
以下操作假設已取得符合目前 CPU 架構的 mihomo 可執行檔,並暫存為 /tmp/mihomo。先安裝至固定路徑,再建立無法登入的系統使用者。使用獨立使用者可避免服務長期以 root 身分執行,也能讓設定檔中的訂閱網址、控制器密鑰與代理資訊僅限指定使用者群組讀取。
sudo install -o root -g root -m 0755 /tmp/mihomo /usr/local/bin/mihomo
sudo useradd \
--system \
--home-dir /var/lib/mihomo \
--create-home \
--shell /usr/sbin/nologin \
clash
sudo install -d -o root -g clash -m 0750 /etc/mihomo
sudo install -d -o clash -g clash -m 0750 /var/lib/mihomo
/usr/local/bin/mihomo -v
若系統已存在名為 clash 的使用者,useradd 會回傳使用者已存在;此時使用 id clash 檢查其家目錄與使用者群組即可。服務使用者不需要密碼,也不需要加入 sudo、docker 等額外群組。
寫入最小可執行設定
以下設定先建立本機 mixed 代理連接埠、REST 控制器與 TUN 接管。mixed-port: 7890 同時接受 HTTP 與 SOCKS5 連線;控制器限制在迴路位址的 9090 連接埠;DNS 使用非特權連接埠 1053,避免額外申請繫結 53 連接埠所需的權限。
mixed-port: 7890
bind-address: 127.0.0.1
allow-lan: false
mode: rule
log-level: info
ipv6: false
external-controller: 127.0.0.1:9090
secret: "請替換為足夠長的隨機控制器密鑰"
profile:
store-selected: true
store-fake-ip: true
tun:
enable: true
stack: mixed
auto-route: true
auto-detect-interface: true
strict-route: true
dns-hijack:
- any:53
- tcp://any:53
dns:
enable: true
listen: 127.0.0.1:1053
ipv6: false
enhanced-mode: fake-ip
fake-ip-range: 198.18.0.1/16
default-nameserver:
- 223.5.5.5
- 1.1.1.1
nameserver:
- https://223.5.5.5/dns-query
- https://1.1.1.1/dns-query
proxies: []
proxy-groups:
- name: PROXY
type: select
proxies:
- DIRECT
rules:
- GEOIP,CN,DIRECT
- MATCH,PROXY
這份設定可用來驗證程序、連接埠與 TUN 是否正常,但 PROXY 群組目前只有 DIRECT,不會產生實際代理轉送。正式使用時,應將既有訂閱轉換為 mihomo 可識別的設定,或透過 proxy-providers 引用服務商提供的相容訂閱。不要把網頁訂閱網址直接當成單一代理節點填寫。
儲存後收緊權限,並以服務使用者身分執行語法檢查。-d 指定執行資料目錄,-f 明確指定設定檔;分開指定後,mihomo 下載的 Geo 資料與規則快取不會寫入 /etc。
sudo chown root:clash /etc/mihomo/config.yaml
sudo chmod 0640 /etc/mihomo/config.yaml
sudo -u clash /usr/local/bin/mihomo \
-t \
-d /var/lib/mihomo \
-f /etc/mihomo/config.yaml
設定 TUN 裝置與 capabilities
TUN 模式需要核心提供 /dev/net/tun,程序也必須具備修改路由、策略路由與虛擬網路介面的能力。對應的關鍵 capability 是 CAP_NET_ADMIN。預設的 7890、9090 與 1053 都高於 1024,因此不需要 CAP_NET_BIND_SERVICE。
檢查 TUN 模組
test -c /dev/net/tun && echo "TUN device ready"
ls -l /dev/net/tun
sudo modprobe tun
cat /sys/class/misc/tun/dev
正常情況下,最後一個指令會輸出 10:200。若 modprobe tun 成功但裝置仍不存在,可以檢查目前核心是否裁剪了 TUN 支援。在容器內還需要由主機向容器開放字元裝置 10:200;僅在容器內建立同名檔案無法提供 TUN 功能。
若需要在每次開機時明確載入模組,可以寫入 modules-load 設定:
echo tun | sudo tee /etc/modules-load.d/tun.conf
sudo systemctl restart systemd-modules-load.service
優先由 systemd 授予能力
Linux 常見的兩種方式,是為二進位檔寫入檔案 capability,或由 systemd 在啟動程序時授予 capability。服務化部署較適合第二種:升級二進位檔後不會因檔案被替換而遺失擴充屬性,權限範圍也能直接在服務單元中檢視。
建立 /etc/systemd/system/mihomo.service:
[Unit]
Description=mihomo proxy service
Documentation=https://wiki.metacubex.one/
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=clash
Group=clash
WorkingDirectory=/var/lib/mihomo
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=3s
TimeoutStopSec=15s
LimitNOFILE=1048576
AmbientCapabilities=CAP_NET_ADMIN
CapabilityBoundingSet=CAP_NET_ADMIN
NoNewPrivileges=true
DevicePolicy=closed
DeviceAllow=/dev/net/tun rw
PrivateDevices=false
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=/var/lib/mihomo
PrivateTmp=true
ProtectKernelTunables=true
ProtectKernelModules=true
ProtectControlGroups=true
RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6 AF_NETLINK
[Install]
WantedBy=multi-user.target
AmbientCapabilities 將 CAP_NET_ADMIN 交給非 root 服務程序,CapabilityBoundingSet 則限制它無法取得清單以外的 capability。DevicePolicy=closed 搭配 DeviceAllow=/dev/net/tun rw,只開放執行所需的 TUN 字元裝置。ProtectSystem=strict 會將系統目錄設為唯讀,而 ReadWritePaths 則單獨允許 mihomo 寫入狀態目錄。
若發行版或舊版 systemd 不支援其中某項加固指令,日誌會明確指出未知欄位。此時應依實際 systemd 版本調整對應行,不要為了繞過單一錯誤就改回以 root 使用者執行。
檔案 capability 作為備選方案
不使用 systemd 管理時,可以授予二進位檔 CAP_NET_ADMIN,但安裝新版二進位檔覆蓋舊檔後,該屬性會消失。使用此方案時,不要再重複設定 systemd 的 AmbientCapabilities。
sudo setcap cap_net_admin=+ep /usr/local/bin/mihomo
getcap /usr/local/bin/mihomo
# 需要撤銷時
sudo setcap -r /usr/local/bin/mihomo
部分掛載了 nosuid 的檔案系統會忽略檔案 capability,某些容器執行環境也會過濾 capability。遇到 Operation not permitted 時,應同時檢查掛載參數、容器能力清單與主機裝置映射。
啟動、開機自動啟動與執行驗證
寫入服務單元後,先讓 systemd 重新讀取設定,再啟動服務並加入開機目標。enable --now 會同時建立開機自動啟動連結並啟動服務。
sudo systemctl daemon-reload
sudo systemctl enable --now mihomo.service
sudo systemctl status mihomo.service --no-pager
正常狀態應顯示 Active: active (running),主程序使用者為 clash。在參考環境中,約 620 條規則、2 個代理提供者的設定冷啟動約需 0.8 至 1.2 秒;穩定執行後的常駐記憶體約為 45 至 85 MB。規則集數量、Geo 資料與連線數增加後,記憶體用量也會相應變化。
檢查連接埠與介面
sudo ss -lntup | grep -E ':(7890|9090|1053)\b'
ip tuntap show
ip rule show
ip route show table all | grep -E '198\.18\.|default'
systemctl show mihomo.service -p User -p MainPID
連接埠監聽位址應與設定一致:7890、9090 與 1053 都只監聽 127.0.0.1。mihomo 建立的 TUN 介面名稱可能隨版本與設定變化,不應只依固定名稱判斷;同時查看 ip tuntap show、策略路由與服務日誌會更可靠。
驗證 HTTP 代理與 TUN 路由
先明確指定 mixed 連接埠測試代理入口,再測試未設定代理環境變數的普通連線。由於範例策略群組暫時指向 DIRECT,此處重點是確認請求經過 mihomo、DNS 沒有逾時,且路由沒有形成迴圈。
curl --proxy http://127.0.0.1:7890 \
--connect-timeout 5 \
https://www.example.com/ -I
env -u http_proxy -u https_proxy -u all_proxy \
curl --connect-timeout 5 \
https://www.example.com/ -I
sudo journalctl -u mihomo.service -n 50 --no-pager
正式匯入代理節點後,可以暫時將 log-level 改為 debug,觀察目標網域命中了哪條規則、選用了哪個策略群組。排查完成後改回 info,否則長時間執行會產生大量日誌。
設定更新與平滑重新載入
修改 YAML 後不要立即重新啟動。先執行測試指令,確認縮排、規則格式、策略群組引用與 provider 路徑有效,再讓 systemd 重新啟動服務。YAML 使用空格縮排,Tab 字元會造成解析失敗;規則引用的策略群組名稱也必須與 proxy-groups 完全一致。
sudo -u clash /usr/local/bin/mihomo \
-t \
-d /var/lib/mihomo \
-f /etc/mihomo/config.yaml
sudo systemctl restart mihomo.service
sudo systemctl status mihomo.service --no-pager
sudo journalctl -u mihomo.service --since "2 minutes ago" --no-pager
若設定來自訂閱,建議先下載至暫存檔,完成語法測試後再以原子方式替換正式設定。如此一來,systemd 重新啟動時只會讀取完整檔案,不會遇到尚未下載完成的半份 YAML。
sudo install -o root -g clash -m 0640 \
/tmp/config.yaml \
/etc/mihomo/config.yaml.new
sudo -u clash /usr/local/bin/mihomo \
-t \
-d /var/lib/mihomo \
-f /etc/mihomo/config.yaml.new
sudo mv /etc/mihomo/config.yaml.new /etc/mihomo/config.yaml
sudo systemctl restart mihomo.service
mihomo 的外部控制器也支援重新載入設定,但遠端自動化腳本需要妥善處理控制器密鑰、介面監聽範圍與失敗回復。對單機伺服器而言,先測試再執行 systemctl restart 更直觀,停頓通常在數秒內。
日誌定位與常見故障
服務反覆重新啟動
先查看目前啟動週期的日誌與結束碼。由於服務設定了 Restart=on-failure,語法錯誤會觸發連續重新啟動;排查時可以先停止服務,直接執行設定測試。
sudo journalctl -u mihomo.service -b --no-pager
sudo systemctl show mihomo.service \
-p ExecMainCode \
-p ExecMainStatus \
-p NRestarts
sudo systemctl stop mihomo.service
sudo -u clash /usr/local/bin/mihomo \
-t \
-d /var/lib/mihomo \
-f /etc/mihomo/config.yaml
常見錯誤包括 YAML 縮排不一致、策略群組引用不存在、設定檔無法由 clash 使用者讀取,以及 provider 目錄不可寫入。可使用 namei -l /etc/mihomo/config.yaml 逐層檢查目錄權限。
建立 TUN 時顯示 permission denied
依序確認 TUN 裝置、服務 capability 與 systemd 裝置策略。僅確認 /dev/net/tun 是否存在並不足夠;程序缺少 CAP_NET_ADMIN 時,同樣無法建立介面或寫入策略路由。
ls -l /dev/net/tun
systemctl show mihomo.service \
-p AmbientCapabilities \
-p CapabilityBoundingSet \
-p DevicePolicy
sudo journalctl -u mihomo.service -n 100 --no-pager | \
grep -Ei 'tun|permission|operation not permitted'
若服務執行於 LXC、Docker 或其他容器中,還需要主機開放 /dev/net/tun 並授予 NET_ADMIN。雲端伺服器核心不包含 TUN 時,容器端設定無法補足核心能力。
啟用 TUN 後 DNS 逾時
先確認 1053 連接埠正在監聽,再檢查上游 DNS 是否可連線。若系統同時執行 systemd-resolved,它通常會佔用本機 127.0.0.53:53,這與 mihomo 監聽 127.0.0.1:1053 並不直接衝突。真正需要注意的是 TUN 的 DNS 劫持是否將 mihomo 自身發出的上游查詢再次送回 TUN,形成迴圈。
sudo ss -lnup | grep ':1053'
resolvectl status
dig @127.0.0.1 -p 1053 www.example.com
sudo journalctl -u mihomo.service -n 100 --no-pager | \
grep -Ei 'dns|timeout|loop'
處理順序應為:確認預設出口介面辨識正確,確認 nameserver 位址可連線,再檢查規則是否錯誤攔截 DNS 上游。多網卡伺服器可以在 TUN 設定中明確指定介面,避免自動偵測選中 Docker、WireGuard 或暫時性的 VPN 介面。
本機可用,區域網路裝置無法連線
範例設定刻意使用 bind-address: 127.0.0.1 與 allow-lan: false,因此其他裝置無法存取 7890。若確實需要提供區域網路代理,請將監聽位址改為伺服器的內網位址並啟用 LAN 存取,同時只在防火牆中放行可信任的網段。
# 僅供示例:允許 192.168.10.0/24 存取 TCP 7890
sudo ufw allow from 192.168.10.0/24 to any port 7890 proto tcp
sudo ufw status numbered
外部控制器 9090 建議繼續繫結迴路位址,透過 SSH 連接埠轉送存取。若必須監聽內網位址,至少設定隨機密鑰並限制來源位址,不要將控制介面直接暴露於公網。
執行維護檢查清單
- 二進位檔架構與
uname -m一致,升級後重新執行mihomo -v。 - 主要設定由
root:clash擁有,權限為0640,執行目錄由服務使用者寫入。 - 每次替換設定前執行
mihomo -t,測試通過後再重新啟動服務。 - TUN 模式只授予
CAP_NET_ADMIN,預設連接埠不需要低連接埠繫結能力。 /dev/net/tun存在;在容器環境中,也已完成主機裝置映射與 capability 授權。- 控制器繫結
127.0.0.1:9090並設定密鑰,遠端管理使用 SSH 轉送。 - 日誌維持
info,僅在短時間排錯期間切換至debug。 - 修改 TUN 路由前準備自動停止工作,避免遠端 SSH 因預設路由變更而中斷。
完成這些步驟後,mihomo 會由 systemd 在網路就緒後啟動,異常結束時等待 3 秒自動重試,並在關機時獲得 15 秒的停止時間。設定、二進位檔與執行資料分開管理,後續無論更新核心、調整訂閱或遷移伺服器,都能依清晰邊界操作。