# 云端 mihomo 代理部署教程

> 本文档教你在一台 Linux 云服务器上部署 mihomo（Clash Meta 内核）代理，用于绕过 Polymarket 的 geo-block（地理封锁），让 live trading bot 能在禁单地区（美国/英国/法国等）的服务器上下单。
>
> **适用场景**：paper bot 不需要代理（只读 API 全球开放），live bot 必须走代理（下单 API 有 geo-block）。

---

## 快速复用（代理已部署完成）

> 如果你所在的服务器**已经部署过 mihomo 代理**（按本文档下方教程完成），直接看这一节就能让新应用走代理。不用重新装。

### 代理位置

| 文件/服务 | 位置 | 说明 |
|-----------|------|------|
| mihomo 程序 | `/usr/local/bin/mihomo` | 二进制本体 |
| 配置文件 | `/etc/mihomo/config.yaml` | 订阅配置 |
| 节点记忆 | `/etc/mihomo/cache.db` | 重启后自动恢复上次选的节点 |
| systemd 服务 | `/etc/systemd/system/mihomo.service` | 24/7 后台运行 |
| 健康检查脚本 | `/opt/mihomo-healthcheck.sh` | 每 5 分钟自动检测 + 轮换 |
| 监听地址 | `127.0.0.1:7890` | HTTP + SOCKS5 混合代理 |
| 管理 API | `127.0.0.1:9090` | 切换节点 / 查状态 |

### 让你的应用走代理

**方法 A：环境变量（最常用）**

在应用的 systemd unit 里加 `EnvironmentFile`，或在启动命令前设环境变量：

```bash
# 临时测试
HTTPS_PROXY=http://127.0.0.1:7890 curl -s https://ipinfo.io/json

# 或写入 env 文件让 systemd 服务用
echo "HTTPS_PROXY=http://127.0.0.1:7890" >> /etc/copybot/你的应用.env
```

Python 的 `requests` / `urllib` / `httpx` 都会自动读 `HTTPS_PROXY` 环境变量，**不需要改代码**。

**方法 B：代码里显式指定（需要改代码）**

```python
import requests
proxies = {"https": "http://127.0.0.1:7890", "http": "http://127.0.0.1:7890"}
r = requests.get("https://clob.polymarket.com/order", proxies=proxies)
```

**方法 C：curl 命令行**

```bash
curl -x http://127.0.0.1:7890 https://目标网址
# 或
HTTPS_PROXY=http://127.0.0.1:7890 curl https://目标网址
```

### 验证代理在工作

```bash
# 1. 代理服务活着？
systemctl is-active mihomo
# 预期: active

# 2. 端口在监听？
ss -tlnp | grep 7890
# 预期: LISTEN ... 127.0.0.1:7890 ...

# 3. 出口 IP 对不对？
HTTPS_PROXY=http://127.0.0.1:7890 curl -s https://ipinfo.io/json
# 预期: country 不是 US/GB/FR 等禁单地区

# 4. Polymarket 能下单？
HTTPS_PROXY=http://127.0.0.1:7890 python3 /opt/winning-wallet-finder/host/geocheck.py | tail -1
# 预期: VERDICT: TRADABLE
```

### 只让特定应用走代理（不影响其他服务）

mihomo **不是系统级透明代理**（没开 TUN 模式），只有设了 `HTTPS_PROXY` 的程序才走代理。

**正确做法**：只在需要的应用的 env 文件里设 `HTTPS_PROXY`：
```
# /etc/copybot/live.env
HTTPS_PROXY=http://127.0.0.1:7890
```

**错误做法**：全局设（会让所有程序走代理）：
```bash
# ❌ 不要这样做
echo "HTTPS_PROXY=http://127.0.0.1:7890" >> /etc/environment
echo "export HTTPS_PROXY=http://127.0.0.1:7890" >> ~/.bashrc
```

### 让 systemd 服务依赖代理

如果你的应用**必须**走代理才能工作（如 live bot），在 systemd unit 里加依赖：

```ini
[Unit]
After=network-online.target mihomo.service
Requires=mihomo.service
```

这样 mihomo 挂了你的应用也会停（不会在没代理的情况下裸奔），mihomo 恢复后自动重启。

### 当前节点状态 + 手动切换

```bash
# 看当前用的哪个节点
curl -s http://127.0.0.1:9090/proxies/GLOBAL | python3 -c "import sys,json; print('当前:', json.load(sys.stdin).get('now'))"

# 手动换节点（节点名从 config.yaml 里找）
curl -s -X PUT http://127.0.0.1:9090/proxies/GLOBAL \
  -H "Content-Type: application/json" \
  -d '{"name":"🇯🇵日本高速06|BGP|CTCU"}'

# 手动跑健康检查（测当前节点通不通，不通自动换）
/opt/mihomo-healthcheck.sh && echo "正常" || echo "异常"
```

### 健康检查自动轮换

已配置 cron 每 5 分钟自动检查：
- 当前节点通 -> 什么都不做
- 当前节点挂 -> 自动遍历所有非美国节点，找到能用的就切换
- 全部挂 -> 写 syslog 告警

```bash
# 查看自动切换记录
journalctl -t mihomo-healthcheck
```

---

## 新服务器部署教程

> 以下是从零开始在新服务器上部署 mihomo 代理的完整步骤。如果你的服务器已经部署过，跳过这一部分，直接看上面的[快速复用](#快速复用代理已部署完成)。

---

## 目录（完整部署）

1. [为什么需要代理](#1-为什么需要代理)
2. [前置条件](#2-前置条件)
3. [安装 mihomo](#3-安装-mihomo)
4. [获取代理订阅配置](#4-获取代理订阅配置)
5. [启动与节点选择](#5-启动与节点选择)
6. [做成 systemd 服务](#6-做成-systemd-服务)
7. [自动健康检查 + IP 轮换](#7-自动健康检查--ip-轮换)
8. [让 live bot 走代理](#8-让-live-bot-走代理)
9. [验证全链路](#9-验证全链路)
10. [日常运维命令](#10-日常运维命令)
11. [常见坑](#11-常见坑)

---

## 1. 为什么需要代理

### Polymarket 的 geo-block

Polymarket 禁止以下地区的 IP 下单（CLOB order API 返回 403）：

```
美国 · 英国 · 法国 · 德国 · 意大利 · 荷兰 · 波兰 · 新加坡 · 澳大利亚 · 加拿大安大略 · 巴西
```

**允许的常见地区**：日本、香港、瑞典、南非、印度、韩国、台湾等。

### 两种 API 的区别

| API | 用途 | 有 geo-block？ | 需要代理？ |
|-----|------|---------------|-----------|
| data-api / gamma-api | 读取市场/钱包数据 | ❌ 全球开放 | paper bot 不需要 |
| clob.polymarket.com/order | **下单** | ✅ 禁单地区 403 | **live bot 必须** |

### geo-gate 检测

项目自带 `host/geocheck.py` 脚本检测服务器能否下单：

```bash
cd /opt/winning-wallet-finder
python3 host/geocheck.py
```

结果判读：
- `VERDICT: TRADABLE` → 不需要代理，跳过本教程
- `VERDICT: BLOCKED` → 需要代理，继续往下看
- `VERDICT: UNKNOWN` → 网络问题，检查服务器能不能连 Polymarket

### 代理的工作原理

```
你的服务器（美国/英国等禁单地区）
    │
    │  HTTPS_PROXY=http://127.0.0.1:7890
    ▼
mihomo 代理（监听 127.0.0.1:7890）
    │
    │  通过日本/香港等节点中转
    ▼
Polymarket CLOB API  ← 看到的是节点的 IP（日本），不是你服务器的 IP（美国）
```

**关键**：mihomo 不是系统级透明代理（不开 TUN 模式），只有**显式设置了 `HTTPS_PROXY` 环境变量的程序**才走代理。其他程序（paper bot、dashboard、Gitea、SSH 等）全部直连，不受影响。

---

## 2. 前置条件

- [ ] 一台 Linux 服务器（Ubuntu 20.04+ / Debian 11+），root 权限
- [ ] 服务器在 Polymarket 禁单地区（`geocheck.py` 返回 `BLOCKED`）
- [ ] 一个 Clash 订阅链接（机场提供），且订阅里有**非禁单地区**的节点（日本/香港/新加坡/韩国等）
- [ ] 你知道订阅里哪些节点是美国的（要避开）

### 确认禁单地区

```bash
python3 /opt/winning-wallet-finder/host/geocheck.py
```

如果输出 `VERDICT: BLOCKED`，说明你的服务器在禁单地区，需要配代理。

---

## 3. 安装 mihomo

mihomo（原名 Clash Meta）是 Clash 的开源内核，纯命令行，无 GUI，适合服务器。

```bash
# 下载
cd /tmp
wget -q https://github.com/MetaCubeX/mihomo/releases/download/v1.19.0/mihomo-linux-amd64-v1.19.0.gz
gzip -d mihomo-linux-amd64-v1.19.0.gz
mv mihomo-linux-amd64-v1.19.0 /usr/local/bin/mihomo
chmod +x /usr/local/bin/mihomo

# 验证
mihomo -v
```

预期输出类似 `Mihomo Meta v1.19.0 ...`。

> 如果 GitHub 下载慢，可以用代理或镜像站下载后 `scp` 到服务器。

---

## 4. 获取代理订阅配置

### 4.1 找到你的订阅链接

你的代理机场（如 Clash Verge 订阅）会提供一个订阅 URL，通常长这样：

```
https://xxx.com/api/v1/client/subscribe?token=abcdef123456...
```

**如何找到**：
- Clash Verge 客户端 → 订阅页面 → 右键订阅卡片 → 复制订阅链接
- 或机场官网 → 用户中心 → 复制订阅链接

### 4.2 下载订阅配置

⚠️ **大坑**：机场会检测 User-Agent，`wget` 默认 UA 会被识别为非 Clash 客户端，返回**假节点**（名字是"当前Clash客户端不支持本机场协议"之类的提示，实际连接 127.0.0.1:65535）。

**必须伪装 User-Agent + 指定 flag=meta**：

```bash
mkdir -p /etc/mihomo

wget -O /etc/mihomo/config.yaml \
  --user-agent="clash-verge/v1.7.7" \
  "你的订阅链接&flag=meta"
```

### 4.3 验证拿到的是真实节点

```bash
# 查看节点列表
grep "name:" /etc/mihomo/config.yaml | head -30
```

**正确**：看到真实节点名，如 `🇯🇵日本高速01|BGP|CTCU`、`🇭🇰香港高速02|BGP|CMCU` 等。

**错误**（假节点）：
```
name: 当前Clash客户端不支持本机场协议
name: 请更换以下支持协议的代理软件
```

如果拿到假节点，尝试以下方法：
1. 换 User-Agent：`--user-agent="clash.meta"` 或 `--user-agent="ClashforWindows/0.20.39"`
2. 换 flag 参数：`&flag=clash` 或 `&flag=meta`
3. 直接在本地 Clash 客户端导出配置文件，`scp` 到服务器

### 4.4 筛选非美国节点

Polymarket 禁单地区包括美国，必须选**非美国**节点。

```bash
# 列出所有节点名
grep "name:" /etc/mihomo/config.yaml | grep -oP "name: [^,}]+" | sed 's/name: //'
```

**可用节点**（不在禁单列表）：
- 🇯🇵 日本（JP）
- 🇭🇰 香港（HK）
- 🇸🇬 新加坡（SG）⚠️ 新加坡在禁单列表！不能用
- 🇰🇷 韩国（KR）
- 🇨🇳 台湾（TW）
- 🇸🇪 瑞典（SE）

**不可用节点**（在禁单列表）：
- 🇺🇸 美国（US）
- 🇬🇧 英国（GB）
- 🇫🇷 法国（FR）
- 🇩🇪 德国（DE）
- 🇮🇹 意大利（IT）
- 🇳🇱 荷兰（NL）
- 🇵🇱 波兰（PL）
- 🇸🇬 新加坡（SG）
- 🇦🇺 澳大利亚（AU）

> **注意**：新加坡虽然在很多机场里速度快，但 Polymarket 禁单！必须避开。

### 4.5 改全局模式

mihomo 默认是 `rule` 模式（按规则分流），我们需要 `global` 模式（所有流量走指定节点）：

```bash
sed -i 's/^mode: rule/mode: global/' /etc/mihomo/config.yaml
```

---

## 5. 启动与节点选择

### 5.1 前台启动（测试用）

```bash
mihomo -d /etc/mihomo
```

等待几秒（首次启动会下载 GeoSite 数据库），看到 `Mixed(http+socks) proxy listening at: 127.0.0.1:7890` 表示成功。

`Ctrl+C` 退出（后面会做成 systemd 服务）。

### 5.2 选择非美国节点

mihomo 启动后默认 GLOBAL 组走 DIRECT（直连），需要通过 API 手动选节点。

```bash
# 查看当前 GLOBAL 选的什么
curl -s http://127.0.0.1:9090/proxies/GLOBAL | python3 -c "import sys,json; print('当前:', json.load(sys.stdin).get('now'))"

# 切换到日本节点（替换成你订阅里的真实节点名）
curl -s -X PUT http://127.0.0.1:9090/proxies/GLOBAL \
  -H "Content-Type: application/json" \
  -d '{"name":"🇯🇵日本高速06|BGP|CTCU"}'
```

> **节点名必须跟 config.yaml 里的 `name:` 字段完全一致**（包括 emoji 和特殊字符）。

### 5.3 验证代理 + geo-gate

```bash
# 测出口 IP（应该不是美国）
HTTPS_PROXY=http://127.0.0.1:7890 curl -s https://ipinfo.io/json

# 测 Polymarket geo-gate（关键！）
HTTPS_PROXY=http://127.0.0.1:7890 python3 /opt/winning-wallet-finder/host/geocheck.py
```

预期最后一行：`VERDICT: TRADABLE - order endpoint reachable past the geo-gate`

如果还是 `BLOCKED`，说明选的节点也在禁单地区，换一个节点再试。

### 5.4 mihomo 自动记住节点选择

mihomo 会把节点选择保存在 `/etc/mihomo/cache.db`，重启后自动恢复。**第一次手动选完，以后重启不用再选**。

验证：
```bash
# 选好节点后重启 mihomo
systemctl restart mihomo  # 或 kill 后重启
sleep 5

# 看它记不记得
curl -s http://127.0.0.1:9090/proxies/GLOBAL | python3 -c "import sys,json; print('当前:', json.load(sys.stdin).get('now'))"
```

如果输出你之前选的节点名，说明记住了。

---

## 6. 做成 systemd 服务

### 6.1 杀掉前台进程

```bash
kill $(pgrep mihomo)
```

### 6.2 写 systemd unit

```bash
cat > /etc/systemd/system/mihomo.service <<'EOF'
[Unit]
Description=Mihomo (Clash Meta) Proxy
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
ExecStart=/usr/local/bin/mihomo -d /etc/mihomo
Restart=always
RestartSec=5

StandardOutput=journal
StandardError=journal
SyslogIdentifier=mihomo

NoNewPrivileges=true

[Install]
WantedBy=multi-user.target
EOF
```

### 6.3 启动 + 验证

```bash
systemctl daemon-reload
systemctl enable --now mihomo
sleep 5

# 确认服务活着
systemctl status mihomo --no-pager | head -5

# 确认端口在监听
ss -tlnp | grep 7890

# 确认节点选择还在（mihomo 应该记住了）
curl -s http://127.0.0.1:9090/proxies/GLOBAL | python3 -c "import sys,json; print('当前节点:', json.load(sys.stdin).get('now'))"

# 确认代理 + geo-gate 通过
HTTPS_PROXY=http://127.0.0.1:7890 python3 /opt/winning-wallet-finder/host/geocheck.py | tail -1
```

预期：
- `Active: active (running)`
- `:7890` 在监听
- 当前节点是你选的非美国节点
- `VERDICT: TRADABLE`

---

## 7. 自动健康检查 + IP 轮换

### 7.1 为什么需要

代理节点可能随时挂掉（服务器维护、被封 IP、网络抖动等）。如果节点挂了：
- live bot 的所有请求超时
- bot 无法下单
- `CASH≠CHAIN` 警告可能出现

需要**自动检测 + 自动切换**到其他可用节点。

### 7.2 健康检查脚本

```bash
cat > /opt/mihomo-healthcheck.sh <<'SCRIPT'
#!/bin/bash
# 检查代理是否通，不通就自动换非美国节点
API="http://127.0.0.1:9090"
PROXY="http://127.0.0.1:7890"

# 1. 测当前节点能不能连 Polymarket CLOB API
code=$(curl -s -o /dev/null -w "%{http_code}" --max-time 10 -x $PROXY \
  "https://clob.polymarket.com/markets?next_cursor=" 2>/dev/null)

if [ "$code" = "200" ]; then
  exit 0  # 通的，不用换
fi

# 2. 不通，拉所有节点列表，挑非美国的试
nodes=$(curl -s "$API/proxies" | python3 -c "
import sys, json
d = json.load(sys.stdin)
skip = {'DIRECT','REJECT','自动选择','故障转移','良心云','GLOBAL'}
# Polymarket 禁单地区关键词（节点名里包含这些的不选）
blocked = ['美国','US','United States','英国','GB','法国','FR','德国','DE',
           '意大利','IT','荷兰','NL','波兰','PL','新加坡','SG','新加坡',
           '澳大利亚','AU','澳洲','巴西','BR']
for name, info in d.get('proxies', {}).items():
    if name in skip:
        continue
    if info.get('type') in ('Selector','URLTest','Fallback','LoadBalance'):
        continue
    if any(k in name for k in blocked):
        continue
    print(name)
")

# 3. 逐个试，找到能用的就切
for node in $nodes; do
  curl -s -X PUT "$API/proxies/GLOBAL" \
    -H "Content-Type: application/json" \
    -d "{\"name\":\"$node}" > /dev/null
  sleep 2
  code=$(curl -s -o /dev/null -w "%{http_code}" --max-time 10 -x $PROXY \
    "https://clob.polymarket.com/markets?next_cursor=" 2>/dev/null)
  if [ "$code" = "200" ]; then
    logger "mihomo-healthcheck: switched to $node (previous was down)"
    exit 0
  fi
done

logger "mihomo-healthcheck: ALL nodes failed - check mihomo or subscription"
exit 1
SCRIPT

chmod +x /opt/mihomo-healthcheck.sh
```

### 7.3 加 cron 定时任务

```bash
# 每 5 分钟检查一次
(crontab -l 2>/dev/null | grep -v mihomo-healthcheck; \
  echo "*/5 * * * * /opt/mihomo-healthcheck.sh") | crontab -

# 验证
crontab -l | grep mihomo
```

### 7.4 手动测试健康检查

```bash
/opt/mihomo-healthcheck.sh && echo "代理正常 ✓" || echo "代理异常 ✗"
```

### 7.5 健康检查的工作逻辑

```
每 5 分钟 cron 触发
    │
    ▼
测当前节点能否连 Polymarket CLOB API
    │
    ├── 200 OK → 退出（代理正常）
    │
    └── 非 200 / 超时 → 当前节点挂了
            │
            ▼
        遍历所有非美国节点
            │
            ├── 找到一个能连的 → 切换 + 写 syslog
            │
            └── 全部失败 → 写 syslog 告警
```

### 7.6 查看健康检查日志

```bash
# 查看切换记录
journalctl -t mihomo-healthcheck

# 或
grep mihomo-healthcheck /var/log/syslog
```

---

## 8. 让 live bot 走代理

### 8.1 原理

`py_clob_client`（Polymarket 下单 SDK）底层用 Python `requests` 库，`requests` 自动读 `HTTPS_PROXY` 环境变量。所以只要在 live bot 的环境变量里设 `HTTPS_PROXY`，所有下单请求自动走代理。

### 8.2 配置 live.env

在 `/etc/copybot/live.env` 里加一行：

```
HTTPS_PROXY=http://127.0.0.1:7890
```

完整 live.env 示例：

```
LIVE_PRIVATE_KEY=0x你的私钥
LIVE_FUNDER_ADDRESS=0x你的钱包地址
LIVE_SIGNATURE_TYPE=1
LIVE_CONFIRM=TRADE LIVE
HTTPS_PROXY=http://127.0.0.1:7890
```

### 8.3 live systemd unit 依赖 mihomo

确保 live bot 的 systemd unit 有 `Requires=mihomo.service` 和 `After=mihomo.service`：

```ini
[Unit]
Description=Polymarket LIVE Copybot (real money)
After=network-online.target mihomo.service
Wants=network-online.target
Requires=mihomo.service
```

这样 mihomo 挂了 live bot 也会停（不会在没代理的情况下尝试下单），mihomo 恢复后 live bot 自动重启。

### 8.4 隔离原则

| 服务 | 走代理？ | 为什么 |
|------|---------|--------|
| live bot | ✅ 走 | 下单需要绕 geo-block |
| paper bot | ❌ 直连 | 只读 API 不受 geo-block，直连更快 |
| dashboard | ❌ 直连 | 本地文件服务，不需要外网 |
| Gitea | ❌ 直连 | 推代码不需要代理 |
| mihomo 本身 | ❌ 直连 | 代理连节点用直连 |

> **不要**把 `HTTPS_PROXY` 写进 `/etc/environment` 或 `~/.bashrc`（全局生效），只放在 `/etc/copybot/live.env` 里，只有 live systemd service 读它。

---

## 9. 验证全链路

### 9.1 代理层

```bash
# mihomo 服务状态
systemctl status mihomo

# 端口监听
ss -tlnp | grep 7890

# 出口 IP（应该非美国）
HTTPS_PROXY=http://127.0.0.1:7890 curl -s https://ipinfo.io/json | python3 -m json.tool

# Polymarket geo-gate
HTTPS_PROXY=http://127.0.0.1:7890 python3 /opt/winning-wallet-finder/host/geocheck.py | tail -1
```

### 9.2 健康检查

```bash
/opt/mihomo-healthcheck.sh && echo "代理正常" || echo "代理异常"
```

### 9.3 live bot 启动验证

```bash
# 重启 live bot
systemctl restart copybot-live
sleep 10

# 看日志，应该有 geo-gate: TRADABLE
journalctl -u copybot-live --since "15 seconds ago" --no-pager | grep -E "geo-gate|armed|TRADABLE|BLOCKED"
```

预期看到 `geo-gate: TRADABLE - order endpoint reachable`。

---

## 10. 日常运维命令

### 看日志

```bash
# mihomo 日志
journalctl -u mihomo -f

# 健康检查切换记录
journalctl -t mihomo-healthcheck

# live bot 日志（确认代理在工作）
journalctl -u copybot-live -f
```

### 代理管理

```bash
# 看当前节点
curl -s http://127.0.0.1:9090/proxies/GLOBAL | python3 -c "import sys,json; print('当前节点:', json.load(sys.stdin).get('now'))"

# 手动换节点（替换节点名）
curl -s -X PUT http://127.0.0.1:9090/proxies/GLOBAL \
  -H "Content-Type: application/json" \
  -d '{"name":"🇯🇵日本高速06|BGP|CTCU"}'

# 手动健康检查
/opt/mihomo-healthcheck.sh && echo "正常" || echo "异常"

# 测代理 + geo-gate
HTTPS_PROXY=http://127.0.0.1:7890 python3 /opt/winning-wallet-finder/host/geocheck.py | tail -1
```

### 服务管理

```bash
systemctl restart mihomo          # 重启代理
systemctl stop mihomo             # 停代理（live bot 也会停）
systemctl start mihomo            # 启代理（live bot 自动重启）
systemctl status mihomo           # 看状态
```

### 更新订阅

```bash
# 重新拉订阅（UA 不能忘！）
wget -O /etc/mihomo/config.yaml \
  --user-agent="clash-verge/v1.7.7" \
  "你的订阅链接&flag=meta"

# 重启生效
systemctl restart mihomo
sleep 5

# 重新选节点（订阅更新后节点名可能变）
curl -s http://127.0.0.1:9090/proxies/GLOBAL | python3 -c "import sys,json; print('当前:', json.load(sys.stdin).get('now'))"
```

### Cron 管理

```bash
crontab -l                        # 看所有定时任务
# 健康检查每 5 分钟跑一次
# 如果想改频率，编辑 crontab:
crontab -e
```

---

## 11. 常见坑

### 坑 1：机场返回假节点

**症状**：`grep "name:" config.yaml` 看到的节点名是"当前Clash客户端不支持本机场协议"之类的提示，连接地址是 127.0.0.1:65535。

**原因**：机场检测到 wget 的 User-Agent 不是 Clash 客户端。

**解法**：加 `--user-agent="clash-verge/v1.7.7"` + `&flag=meta` 参数：

```bash
wget -O /etc/mihomo/config.yaml \
  --user-agent="clash-verge/v1.7.7" \
  "订阅链接&flag=meta"
```

如果还是假节点，尝试不同的 UA：`clash.meta`、`ClashforWindows/0.20.39`、`clash-verge/v1.7.7`。

### 坑 2：选了新加坡节点，还是 BLOCKED

**症状**：切到新加坡节点后 `geocheck.py` 还是 `BLOCKED`。

**原因**：新加坡在 Polymarket 禁单列表里（很多人不知道）。

**解法**：换日本/香港/韩国/台湾等不在禁单列表的节点。禁单列表见 [§1](#1-为什么需要代理)。

### 坑 3：mihomo 重启后节点回到 DIRECT

**症状**：重启 mihomo 后 `geocheck.py` 变成 `BLOCKED`，检查发现 GLOBAL 回到 DIRECT。

**原因**：第一次启动后没手动选过节点，cache.db 里没记录。

**解法**：启动后手动选一次节点，mihomo 会记住（保存到 cache.db），以后重启自动恢复。

### 坑 4：代理影响其他服务

**症状**：paper bot / dashboard / Gitea 全部变慢或连不上。

**原因**：`HTTPS_PROXY` 被设成了全局环境变量（写进了 `/etc/environment` 或 `~/.bashrc`）。

**解法**：只在 `/etc/copybot/live.env` 里设 `HTTPS_PROXY`，不要全局设。mihomo 不是透明代理，只有显式设了 `HTTPS_PROXY` 的程序才走代理。

### 坑 5：config.yaml 追加 proxy-groups 导致启动失败

**症状**：mihomo 重启后报 YAML 解析错误，端口不监听。

**原因**：在 config.yaml 末尾追加了重复的 `proxy-groups:` 段，YAML 不允许重复键。

**解法**：不要追加，用 API 切换节点即可。如果一定要改 proxy-groups，编辑原有段而不是追加。

### 坑 6：健康检查脚本里的节点名有特殊字符

**症状**：健康检查脚本切换节点失败，`curl -X PUT` 返回 400。

**原因**：节点名包含 emoji 或特殊字符（如 `🇯🇵日本高速06|BGP|CTCU`），JSON 转义有问题。

**解法**：脚本里用 `python3` 读取节点列表并输出，`curl` 用 `-d` 传 JSON 时用双引号包裹。本文的脚本已处理此问题。

### 坑 7：mihomo 首次启动慢

**症状**：启动 mihomo 后 `curl` 连不上 7890 端口。

**原因**：首次启动会下载 GeoSite/MMDB 数据库（几 MB），需要几秒钟。

**解法**：等 5-10 秒再测试。看日志确认 `Mixed(http+socks) proxy listening at: 127.0.0.1:7890` 出现后再操作。

### 坑 8：live bot 报 CASH≠CHAIN

**症状**：live bot 日志出现 `⚠ CASH≠CHAIN $+X.XX`。

**原因**：代理在订单提交中途断了或切换了，bot 以为订单没成交但实际成交了，账本与链上不一致。

**解法**：
1. 停 bot：`systemctl stop copybot-live`
2. 查链上实际 pUSD 余额
3. 更新 `config.live.json` 的 `bankroll_usd` 为实际余额
4. 清 state：`rm -f /opt/winning-wallet-finder/copybot_state.live.json /opt/winning-wallet-finder/copybot_fills.live.jsonl /opt/winning-wallet-finder/live/copybot_live_real.json`
5. 重启：`systemctl start copybot-live`

---

## 附录：完整部署一键脚本

> ⚠️ 不建议直接跑，建议按上面步骤一步步来。此脚本仅供参考。

```bash
#!/bin/bash
set -e

# 1. 装 mihomo
cd /tmp
wget -q https://github.com/MetaCubeX/mihomo/releases/download/v1.19.0/mihomo-linux-amd64-v1.19.0.gz
gzip -d mihomo-linux-amd64-v1.19.0.gz
mv mihomo-linux-amd64-v1.19.0 /usr/local/bin/mihomo
chmod +x /usr/local/bin/mihomo

# 2. 拉订阅（替换 SUB_URL）
SUB_URL="你的订阅链接"
mkdir -p /etc/mihomo
wget -O /etc/mihomo/config.yaml --user-agent="clash-verge/v1.7.7" "${SUB_URL}&flag=meta"
sed -i 's/^mode: rule/mode: global/' /etc/mihomo/config.yaml

# 3. systemd 服务
cat > /etc/systemd/system/mihomo.service <<'EOF'
[Unit]
Description=Mihomo (Clash Meta) Proxy
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
ExecStart=/usr/local/bin/mihomo -d /etc/mihomo
Restart=always
RestartSec=5
StandardOutput=journal
StandardError=journal
SyslogIdentifier=mihomo
NoNewPrivileges=true
[Install]
WantedBy=multi-user.target
EOF

systemctl daemon-reload
systemctl enable --now mihomo
sleep 8

# 4. 健康检查脚本
cat > /opt/mihomo-healthcheck.sh <<'SCRIPT'
#!/bin/bash
API="http://127.0.0.1:9090"
PROXY="http://127.0.0.1:7890"
code=$(curl -s -o /dev/null -w "%{http_code}" --max-time 10 -x $PROXY "https://clob.polymarket.com/markets?next_cursor=" 2>/dev/null)
if [ "$code" = "200" ]; then exit 0; fi
nodes=$(curl -s "$API/proxies" | python3 -c "
import sys, json
d = json.load(sys.stdin)
skip = {'DIRECT','REJECT','自动选择','故障转移','良心云','GLOBAL'}
blocked = ['美国','US','United States','英国','GB','法国','FR','德国','DE','意大利','IT','荷兰','NL','波兰','PL','新加坡','SG','澳大利亚','AU','澳洲','巴西','BR']
for name, info in d.get('proxies', {}).items():
    if name in skip: continue
    if info.get('type') in ('Selector','URLTest','Fallback','LoadBalance'): continue
    if any(k in name for k in blocked): continue
    print(name)
")
for node in $nodes; do
  curl -s -X PUT "$API/proxies/GLOBAL" -H "Content-Type: application/json" -d "{\"name\":\"$node}" > /dev/null
  sleep 2
  code=$(curl -s -o /dev/null -w "%{http_code}" --max-time 10 -x $PROXY "https://clob.polymarket.com/markets?next_cursor=" 2>/dev/null)
  if [ "$code" = "200" ]; then
    logger "mihomo-healthcheck: switched to $node"
    exit 0
  fi
done
logger "mihomo-healthcheck: ALL nodes failed"
exit 1
SCRIPT
chmod +x /opt/mihomo-healthcheck.sh

# 5. cron
(crontab -l 2>/dev/null | grep -v mihomo-healthcheck; echo "*/5 * * * * /opt/mihomo-healthcheck.sh") | crontab -

echo "=== 部署完成 ==="
echo "下一步：手动选一个非美国节点"
echo "  curl -s http://127.0.0.1:9090/proxies | python3 -m json.tool | grep name"
echo "  curl -s -X PUT http://127.0.0.1:9090/proxies/GLOBAL -H 'Content-Type: application/json' -d '{\"name\":\"节点名\"}'"
echo "然后验证："
echo "  HTTPS_PROXY=http://127.0.0.1:7890 python3 /opt/winning-wallet-finder/host/geocheck.py | tail -1"
```

---

## 文件结构速查

```
服务器
├── /usr/local/bin/mihomo              代理程序本体
├── /etc/mihomo/
│   ├── config.yaml                    订阅配置（机场下载）
│   └── cache.db                       节点选择记忆
├── /etc/systemd/system/
│   └── mihomo.service                 systemd 服务定义
├── /opt/mihomo-healthcheck.sh         健康检查脚本
├── /etc/copybot/
│   └── live.env                       live bot 环境变量（含 HTTPS_PROXY）
└── crontab
    └── */5 * * * * healthcheck.sh     每 5 分钟健康检查
```
