# 输入命令
mkdir -p ~/.config/mihomo
cd ~/.config/mihomo
pwd
# 实际输出
(base) yuuu@DESKTOP-M32KRCT:~/.config/mihomo$ mkdir -p ~/.config/mihomo
(base) yuuu@DESKTOP-M32KRCT:~/.config/mihomo$ cd ~/.config/mihomo
(base) yuuu@DESKTOP-M32KRCT:~/.config/mihomo$ pwd
/home/yuuu/.config/mihomo
# 输入命令
wget https://github.com/MetaCubeX/mihomo/releases/download/v1.19.3/mihomo-linux-amd64-v1.19.3.gz
# 实际输出
--2025-03-23 20:35:08-- https://github.com/MetaCubeX/mihomo/releases/download/v1.19.3/mihomo-linux-amd64-v1.19.3.gz
Resolving github.com (github.com)... 20.205.243.166
Connecting to github.com (github.com)|20.205.243.166|:443... connected.
HTTP request sent, awaiting response... 302 Found
Location: https://objects.githubusercontent.com/github-production-release-asset-2e65be/369178935/78184ca4-301f-4b2f-b971-38caf83fb9b4?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=releaseassetproduction%2F20250323%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20250323T123505Z&X-Amz-Expires=300&X-Amz-Signature=ae34067c6838fc9d244ea24bb439df4a41361d5a3c1562aa9e30edeaf7de1950&X-Amz-SignedHeaders=host&response-content-disposition=attachment%3B%20filename%3Dmihomo-linux-amd64-v1.19.3.gz&response-content-type=application%2Foctet-stream [following]
--2025-03-23 20:35:09-- https://objects.githubusercontent.com/github-production-release-asset-2e65be/369178935/78184ca4-301f-4b2f-b971-38caf83fb9b4?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=releaseassetproduction%2F20250323%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20250323T123505Z&X-Amz-Expires=300&X-Amz-Signature=ae34067c6838fc9d244ea24bb439df4a41361d5a3c1562aa9e30edeaf7de1950&X-Amz-SignedHeaders=host&response-content-disposition=attachment%3B%20filename%3Dmihomo-linux-amd64-v1.19.3.gz&response-content-type=application%2Foctet-stream
Resolving objects.githubusercontent.com (objects.githubusercontent.com)... 185.199.109.133, 185.199.108.133, 185.199.111.133, ...
Connecting to objects.githubusercontent.com (objects.githubusercontent.com)|185.199.109.133|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 11995266 (11M) [application/octet-stream]
Saving to: 'mihomo-linux-amd64-v1.19.3.gz'
mihomo-linux-amd64-v1.19.3.gz 100%[=====================================================================================>] 11.44M 18.8MB/s in 0.6s
2025-03-23 20:35:10 (18.8 MB/s) - 'mihomo-linux-amd64-v1.19.3.gz' saved [11995266/11995266]
# 输入命令
gzip -d mihomo-linux-amd64-v1.19.3.gz
mv mihomo-linux-amd64-v1.19.3 mihomo
chmod +x mihomo
ls -l mihomo
# 实际输出
# gzip、mv、chmod命令无输出,表示执行成功
# ls -l命令输出:
-rwxr-xr-x 1 yuuu yuuu 32260244 Mar 3 11:59 mihomo
# 输入命令
mkdir -p providers
ls
# 实际输出
(base) yuuu@DESKTOP-M32KRCT:~/.config/mihomo$ mkdir -p providers
(base) yuuu@DESKTOP-M32KRCT:~/.config/mihomo$ ls
config.yaml mihomo providers
# HTTP(S) 代理端口
mixed-port: 7890
# 允许局域网
allow-lan: true
# 绑定地址
bind-address: '*'
# 运行模式
mode: rule
# 日志等级
log-level: info
# API接口(用于查询节点信息)
external-controller: '127.0.0.1:9090'
# DNS 设置
dns:
enable: true
ipv6: false
default-nameserver: [119.29.29.29, 223.5.5.5]
enhanced-mode: fake-ip
fake-ip-range: 198.18.0.1/16
use-hosts: true
nameserver: [119.29.29.29, 223.5.5.5, 1.1.1.1, 8.8.4.4]
fallback: [119.29.29.29, 223.5.5.5, 1.1.1.1, 8.8.4.4]
fallback-filter: { geoip: true, ipcidr: [240.0.0.0/4, 0.0.0.0/32] }
# 代理提供者
proxy-providers:
zy_wsl_xfltd:
type: file
path: ./providers/zy_wsl_xfltd.yaml
health-check:
enable: true
interval: 600
url: http://www.gstatic.com/generate_204
# 代理组
proxy-groups:
- name: XFLTD
type: select
proxies:
- 自动选择
- 故障转移
- DIRECT
use:
- zy_wsl_xfltd
- name: 自动选择
type: url-test
url: http://www.gstatic.com/generate_204
interval: 86400
tolerance: 50
use:
- zy_wsl_xfltd
- name: 故障转移
type: fallback
url: http://www.gstatic.com/generate_204
interval: 7200
use:
- zy_wsl_xfltd
# 规则
rules:
# 直连规则
- DOMAIN,xfltd.net,DIRECT
- DOMAIN-SUFFIX,cn,DIRECT
- DOMAIN-KEYWORD,-cn,DIRECT
- GEOIP,CN,DIRECT
# 代理规则
- DOMAIN-SUFFIX,google.com,XFLTD
- DOMAIN-SUFFIX,google.com.hk,XFLTD
- DOMAIN-SUFFIX,googleapis.com,XFLTD
- DOMAIN-SUFFIX,gmail.com,XFLTD
- DOMAIN-SUFFIX,youtube.com,XFLTD
- DOMAIN-SUFFIX,youtu.be,XFLTD
- DOMAIN-SUFFIX,github.com,XFLTD
- DOMAIN-SUFFIX,github.io,XFLTD
- DOMAIN-SUFFIX,githubusercontent.com,XFLTD
- DOMAIN-SUFFIX,githubassets.com,XFLTD
# 广告屏蔽
- DOMAIN-KEYWORD,admarvel,REJECT
- DOMAIN-KEYWORD,admaster,REJECT
- DOMAIN-KEYWORD,adsage,REJECT
- DOMAIN-KEYWORD,adsmogo,REJECT
- DOMAIN-KEYWORD,adsrvmedia,REJECT
- DOMAIN-KEYWORD,adwords,REJECT
- DOMAIN-KEYWORD,adservice,REJECT
- DOMAIN-SUFFIX,appsflyer.com,REJECT
- DOMAIN-SUFFIX,doubleclick.net,REJECT
# 局域网
- IP-CIDR,127.0.0.0/8,DIRECT
- IP-CIDR,172.16.0.0/12,DIRECT
- IP-CIDR,192.168.0.0/16,DIRECT
- IP-CIDR,10.0.0.0/8,DIRECT
- IP-CIDR,17.0.0.0/8,DIRECT
- IP-CIDR,100.64.0.0/10,DIRECT
- IP-CIDR,224.0.0.0/4,DIRECT
- IP-CIDR6,fe80::/10,DIRECT
# 最终规则
- MATCH,XFLTD
proxies:
- name: "剩余流量:15.17 GB"
type: trojan
server: cn1.cdn.xfltd-cdn.top
port: 12001
password: 2502b101-a626-4b99-82ed-c6447d9ccab0
udp: true
sni: cdn.alibaba.com
skip-cert-verify: true
- name: "套餐到期:长期有效"
type: trojan
server: cn1.cdn.xfltd-cdn.top
port: 12001
password: 2502b101-a626-4b99-82ed-c6447d9ccab0
udp: true
sni: cdn.alibaba.com
skip-cert-verify: true
- name: " 香港 01"
type: trojan
server: cn1.cdn.xfltd-cdn.top
port: 12001
password: 2502b101-a626-4b99-82ed-c6447d9ccab0
udp: true
sni: cdn.alibaba.com
skip-cert-verify: true
# ... 更多节点配置 ...
# 为了文档简洁,这里省略了其他节点的配置
# 实际使用时请将完整的节点配置添加到此处
# 输入命令
vim ~/.config/mihomo/start-mihomo.sh
# 脚本内容
#!/bin/bash
cd ~/.config/mihomo
./mihomo -d . > mihomo.log 2>&1 &
# 设置权限
chmod +x start-mihomo.sh
# 编辑.bashrc文件
vim ~/.bashrc
# 添加以下内容到文件末尾
# 启动Mihomo代理服务
if ! pgrep -f "mihomo -d" > /dev/null; then
~/.config/mihomo/start-mihomo.sh
fi
# 使配置生效
source ~/.bashrc
# 创建脚本文件
vim ~/.config/mihomo/proxy.sh
# 脚本内容
#!/bin/bash
# 配置
MIHOMO_PATH="$HOME/.config/mihomo"
PROXY_HOST="127.0.0.1"
PROXY_PORT="7890"
API_PORT="9090"
# 检查依赖
check_dependencies() {
if ! command -v jq &> /dev/null; then
echo "错误: 未找到 jq 命令"
echo "请运行以下命令安装 jq:"
echo "sudo apt update && sudo apt install jq"
exit 1
fi
}
# 不使用jq的备选解析函数
parse_json() {
local json=$1
local key=$2
echo "$json" | grep -o "\"$key\":\"[^\"]*\"" | sed "s/\"$key\":\"//" | sed "s/\"//g"
}
# 帮助信息
show_help() {
echo "Usage: proxy [options]"
echo
echo "Commands:"
echo " on 开启代理"
echo " off 关闭代理"
echo " status 显示当前状态"
echo
echo " mode 切换代理模式"
echo " global - 全局模式"
echo " direct - 直连模式"
echo " rule - 规则模式"
echo
echo " switch 切换代理节点"
echo " auto - 自动选择"
echo " - 指定节点"
echo
echo " now 显示当前节点"
echo " delay 显示当前节点延迟"
echo " list 显示所有节点"
echo " test 测试所有节点延迟"
echo
echo " help 显示本帮助信息"
echo
echo "注意: 本脚本依赖 jq 命令来解析 JSON。如果未安装,请运行:"
echo "sudo apt update && sudo apt install jq"
echo "注意: 带空格的节点名称需要使用引号,例如:"
echo ' proxy switch " 香港 05"'
}
# 检查服务状态
check_service() {
pgrep -f "mihomo -d" > /dev/null
return $?
}
# 启动服务
start_service() {
if ! check_service; then
$MIHOMO_PATH/start-mihomo.sh
sleep 2
fi
}
# 停止服务
stop_service() {
if check_service; then
pkill -f "mihomo -d"
fi
}
# 设置环境变量
set_proxy() {
export http_proxy="http://$PROXY_HOST:$PROXY_PORT"
export https_proxy="http://$PROXY_HOST:$PROXY_PORT"
}
# 清除环境变量
unset_proxy() {
unset http_proxy
unset https_proxy
}
# 切换代理模式
switch_mode() {
local mode=$1
curl -H "Content-Type: application/json" -X PATCH http://$PROXY_HOST:$API_PORT/configs \
-d "{\"mode\":\"$mode\"}"
}
# 切换代理节点
switch_node() {
local node=$1
curl -H "Content-Type: application/json" -X PUT http://$PROXY_HOST:$API_PORT/proxies/XFLTD \
-d "{\"name\":\"$node\"}"
}
# 获取当前节点(带备选实现)
get_current_node() {
local response=$(curl -s -H "Content-Type: application/json" -X GET http://$PROXY_HOST:$API_PORT/proxies/XFLTD)
if command -v jq &> /dev/null; then
echo "$response" | jq -r '.now'
else
parse_json "$response" "now"
fi
}
# 获取节点延迟
get_delay() {
local node=$1
# URL encode the node name
local encoded_node=$(echo "$node" | sed 's/ /%20/g')
# 首先检查是否是代理组
local node_info=$(curl -s -H "Content-Type: application/json" -X GET "http://$PROXY_HOST:$API_PORT/proxies/$encoded_node")
if [ -z "$node_info" ]; then
echo "错误: 无法获取节点信息" >&2
return 1
fi
local node_type=$(echo "$node_info" | jq -r '.type')
# 如果是代理组,获取当前使用的节点
if [[ "$node_type" == "Selector" || "$node_type" == "URLTest" || "$node_type" == "Fallback" ]]; then
local actual_node=$(echo "$node_info" | jq -r '.now')
echo "debug: 代理组 '$node' 当前使用节点: $actual_node" >&2
node=$actual_node
encoded_node=$(echo "$actual_node" | sed 's/ /%20/g')
fi
# 确保curl使用代理
local curl_proxy="http://$PROXY_HOST:$PROXY_PORT"
# 使用最稳定的测试URL
local urls=(
"http://www.gstatic.com/generate_204"
"http://cp.cloudflare.com/generate_204"
)
for test_url in "${urls[@]}"; do
# URL encode the test URL
local encoded_test_url=$(echo "$test_url" | sed 's/:/%3A/g' | sed 's/\//%2F/g')
echo "debug: 正在使用 $test_url 测试节点 $node" >&2
# 使用GET请求,参数通过URL传递
local delay_info=$(curl -v -s -x "$curl_proxy" \
-H "Content-Type: application/json" \
--connect-timeout 3 \
-X GET "http://$PROXY_HOST:$API_PORT/proxies/$encoded_node/delay?timeout=5000&url=$encoded_test_url" 2>&1)
echo "debug: curl响应: $delay_info" >&2
# 尝试解析延迟值
if [ -n "$delay_info" ]; then
local delay=$(echo "$delay_info" | grep -o '"delay":[0-9]*' | cut -d':' -f2)
if [ -n "$delay" ] && [ "$delay" != "null" ]; then
echo "debug: 成功获取延迟: ${delay}ms" >&2
echo "{\"delay\": $delay}"
return 0
fi
fi
# 如果第一个URL失败,尝试下一个
continue
done
echo "debug: 所有URL测试失败" >&2
echo '{"delay": -1}'
return 1
}
# 获取所有节点
get_all_nodes() {
curl -s -H "Content-Type: application/json" -X GET http://$PROXY_HOST:$API_PORT/proxies
}
# 主函数
main() {
# 检查依赖
if [ "$1" != "help" ]; then
check_dependencies
fi
case $1 in
"on")
start_service
set_proxy
echo "代理已开启"
;;
"off")
stop_service
unset_proxy
echo "代理已关闭"
;;
"status")
if check_service; then
echo "代理服务: 运行中"
if command -v jq &> /dev/null; then
echo "当前模式: $(curl -s http://$PROXY_HOST:$API_PORT/configs | jq -r .mode)"
echo "当前节点: $(get_current_node)"
else
echo "当前节点: $(get_current_node)"
echo "提示: 安装 jq 可以获取更多信息"
fi
else
echo "代理服务: 未运行"
fi
;;
"mode")
case $2 in
"global"|"direct"|"rule")
switch_mode $2
echo "已切换到${2}模式"
;;
*)
echo "无效的模式,可用模式: global, direct, rule"
;;
esac
;;
"switch")
if [ -z "$2" ]; then
echo "请指定节点"
exit 1
fi
# 合并所有参数为完整节点名称
shift
node_name="$*"
# 检查节点是否存在
if ! echo "$(get_all_nodes)" | jq -e --arg name "$node_name" '.proxies | has($name)' > /dev/null; then
echo "错误: 节点 '$node_name' 不存在"
echo "可用节点列表:"
get_all_nodes | jq -r '.proxies | keys[]' | grep -v "^COMPATIBLE\|^DIRECT\|^GLOBAL\|^PASS\|^REJECT"
exit 1
fi
switch_node "$node_name"
echo "已切换到节点: $node_name"
;;
"now")
echo "当前节点: $(get_current_node)"
;;
"delay")
current_node=$(get_current_node)
echo "当前节点: $current_node"
if [[ "$current_node" == "自动选择" || "$current_node" == "故障转移" ]]; then
# 如果是代理组,获取该组当前使用的节点
actual_node=$(curl -s -H "Content-Type: application/json" \
-X GET http://$PROXY_HOST:$API_PORT/proxies/$current_node | jq -r '.now')
echo "实际使用节点: $actual_node"
delay_info=$(get_delay "$actual_node")
delay=$(echo "$delay_info" | jq .delay)
if [ "$delay" == "-1" ] || [ "$delay" == "null" ]; then
echo "延迟测试失败"
else
echo "延迟: ${delay}ms"
fi
else
# 直接获取节点延迟
delay_info=$(get_delay "$current_node")
delay=$(echo "$delay_info" | jq .delay)
if [ "$delay" == "-1" ] || [ "$delay" == "null" ]; then
echo "延迟测试失败"
else
echo "延迟: ${delay}ms"
fi
fi
;;
"list")
get_all_nodes | jq -r '.proxies | keys[]'
;;
"test")
echo "测试所有节点延迟..."
# 获取所有节点信息
nodes_info=$(get_all_nodes)
# 过滤并保留完整的节点名称
while IFS= read -r node; do
# 跳过特殊节点
if [[ "$node" == "DIRECT" ]] || [[ "$node" == "REJECT" ]] || \
[[ "$node" == "XFLTD" ]] || [[ "$node" == "自动选择" ]] || \
[[ "$node" == "故障转移" ]] || [[ "$node" == *"流量"* ]] || \
[[ "$node" == *"套餐"* ]]; then
continue
fi
printf "%-30s" "$node:"
delay=$(get_delay "$node" | jq .delay)
if [ "$delay" == "-1" ] || [ "$delay" == "null" ]; then
echo "超时"
else
echo "${delay}ms"
fi
done < <(echo "$nodes_info" | jq -r '.proxies | keys[]')
;;
"help"|*)
show_help
;;
esac
}
main "$@"
chmod +x ~/.config/mihomo/proxy.sh
# 添加到 ~/.bashrc
echo 'alias proxy="bash ~/.config/mihomo/proxy.sh"' >> ~/.bashrc
source ~/.bashrc
# 开启代理
proxy on
# 切换到全局模式
proxy mode global
# 切换到自动选择节点
proxy switch auto
# 查看当前节点
proxy now
# 测试所有节点延迟
proxy test
# 查看帮助
proxy help
# 输入命令
~/.config/mihomo/start-mihomo.sh
# 检查服务状态
ps aux | grep mihomo
# 设置临时代理环境变量
(base) yuuu@DESKTOP-M32KRCT:~$ export http_proxy=http://127.0.0.1:7890
(base) yuuu@DESKTOP-M32KRCT:~$ export https_proxy=http://127.0.0.1:7890
# 验证环境变量设置
(base) yuuu@DESKTOP-M32KRCT:~$ echo $http_proxy
http://127.0.0.1:7890
(base) yuuu@DESKTOP-M32KRCT:~$ echo $https_proxy
http://127.0.0.1:7890
# 添加到.bashrc实现永久配置
(base) yuuu@DESKTOP-M32KRCT:~$ echo 'export http_proxy=http://127.0.0.1:7890' >> ~/.bashrc
(base) yuuu@DESKTOP-M32KRCT:~$ echo 'export https_proxy=http://127.0.0.1:7890' >> ~/.bashrc
(base) yuuu@DESKTOP-M32KRCT:~$ source ~/.bashrc
# 输入命令
curl -v https://www.google.com
# 查看XFLTD代理组当前使用的节点
curl -H "Content-Type: application/json" -X GET http://127.0.0.1:9090/proxies/XFLTD
# 输出示例(精简):
{
"name": "XFLTD",
"type": "Selector",
"now": "自动选择",
"all": ["自动选择", "故障转移", "DIRECT", " 香港 01", " 香港 02", ...]
}
# 查看自动选择组当前使用的节点
curl -H "Content-Type: application/json" -X GET http://127.0.0.1:9090/proxies/自动选择
# 输出示例(精简):
{
"name": "自动选择",
"type": "URLTest",
"now": " 日本 05", # 当前使用的节点
"all": [" 香港 01", " 香港 02", ...]
}
# 查看所有节点信息(包括延迟等状态)
curl -H "Content-Type: application/json" -X GET http://127.0.0.1:9090/proxies
# 输出示例(精简):
{
"proxies": {
"DIRECT": {"type": "Direct", "alive": true},
"REJECT": {"type": "Reject", "alive": true},
"XFLTD": {
"type": "Selector",
"now": "自动选择"
},
"自动选择": {
"type": "URLTest",
"now": " 日本 05"
},
" 香港 01": {
"alive": true,
"history": [{"time": "2025-03-23T21:58:26.284851039+08:00", "delay": 377}]
},
" 日本 05": {
"alive": true,
"history": [{"time": "2025-03-23T21:58:26.846059041+08:00", "delay": 241}]
}
}
}
# 切换到特定节点,比如切换到香港01
curl -H "Content-Type: application/json" -X PUT http://127.0.0.1:9090/proxies/XFLTD -d '{"name":" 香港 01"}'
tail -f ~/.config/mihomo/mihomo.log
pkill -f "mihomo -d"
pkill -f "mihomo -d"
~/.config/mihomo/start-mihomo.sh
延迟测试超时问题:
节点名称处理问题:
错误处理问题:
优化延迟测试:
# 减少超时时间
--connect-timeout 3 \ # 连接超时3秒
timeout=5000 # 总超时5秒
# 精简测试URL
local urls=(
"http://www.gstatic.com/generate_204"
"http://cp.cloudflare.com/generate_204"
)
# 移除多次重试
# 如果第一个URL失败,直接尝试下一个
改进节点名称处理:
# 完整保留节点名称,包括表情符号
nodes_info=$(get_all_nodes)
while IFS= read -r node; do
# 处理完整节点名称
done < <(echo "$nodes_info" | jq -r '.proxies | keys[]')
# 正确的URL编码
local encoded_node=$(echo "$node" | sed 's/ /%20/g')
优化显示格式:
# 使用更宽的显示列以适应完整节点名称
printf "%-30s" "$node:"
# 清晰的状态显示
if [ "$delay" == "-1" ] || [ "$delay" == "null" ]; then
echo "超时"
else
echo "${delay}ms"
fi
性能提升:
可靠性提升:
用户体验改进:
节点名称解析问题:
错误提示不明确:
# 合并所有参数为完整节点名称
shift
node_name="$*"
# 检查节点是否存在
if ! echo "$(get_all_nodes)" | jq -e --arg name "$node_name" '.proxies | has($name)' > /dev/null; then
echo "错误: 节点 '$node_name' 不存在"
echo "可用节点列表:"
get_all_nodes | jq -r '.proxies | keys[]' | grep -v "^COMPATIBLE\|^DIRECT\|^GLOBAL\|^PASS\|^REJECT"
exit 1
fi
# 在帮助信息中添加带空格节点名称的使用说明
echo "注意: 带空格的节点名称需要使用引号,例如:"
echo ' proxy switch " 香港 05"'
# 使用单引号
proxy switch ' 香港 05'
已切换到节点: 香港 05
# 使用双引号
proxy switch " 香港 05"
已切换到节点: 香港 05
# 验证当前节点
proxy now
当前节点: 香港 05
# 切换到自动选择
proxy switch '自动选择'
已切换到节点: 自动选择
# 验证当前节点
proxy now
当前节点: 自动选择
节点名称使用引号:
验证切换结果:
proxy now
命令验证切换是否成功查看可用节点:
proxy list
命令查看所有可用节点