Proxy Monitor / 控制面手册
# IPv6 代理使用手册

本文档记录当前公网入口 `20.163.32.83` 上的 Windows IPv6 出口代理使用方式。

## 架构

```text
客户端
  -> 20.163.32.83:17889
  -> entry sing-box 按用户名路由
  -> entry 本地 throttle 端口
  -> SSH 反向隧道
  -> Windows 出口机 WIN-H8J6D25OKFS
  -> Windows 本地 sing-box 绑定指定 IPv6 出口
```

当前 Windows 出口机:

```text
hostname: WIN-H8J6D25OKFS
LAN IP:   192.168.3.34
入口控制: 20.163.32.83 -> 127.0.0.1:41085
```

### 故障处理职责

当前采用“出口节点主处理、入口控制器兜底”的职责划分:

| 组件 | 负责内容 |
|---|---|
| Windows 出口节点 | 每分钟检测 RA IPv6 前缀、本地 v6 SOCKS、sing-box 任务和反向隧道;发现前缀变化或连续健康失败时,本机独立重绑对应节点并重启对应任务 |
| 公网入口控制器 | 监控每个节点的前缀和出口健康状态,记录状态,协调手动轮换;发现 Windows 没有完成自愈时执行 SSH 兜底轮换 |
| 入口 sing-box/throttle | 保持公网代理地址和账号不变,把每个账号固定转发到对应的独立反向隧道 |

Windows 本机轮换成功后,入口控制器会先读取 Windows 当前配置并同步状态,不会因为状态延迟再次轮换同一个节点。`auto_change_every` 建议保持为空或设为 `0`,定时轮换由业务策略或 Windows 节点侧负责;入口控制器的健康和前缀检查仍保持启用。

## 代理账号

公网入口统一为:

```text
host: 20.163.32.83
port: 17889
```

当前保留的账号:

| 用户名 | 用途 | 说明 |
|---|---|---|
| `H8J6D25OKFS` | IPv4 出口 | 保留给原 v4 代理 |
| `H8J6D25OKFS-v6` | IPv6 出口 | 老 v6 用户,映射到 `v6-1` |
| `H8J6D25OKFS-v6-1` | IPv6 出口 | `v6-1` 别名,和 `H8J6D25OKFS-v6` 同一个出口 |
| `H8J6D25OKFS-v6-2` | IPv6 出口 | 独立实例,可单独轮换 |
| `H8J6D25OKFS-v6-3` | IPv6 出口 | 独立实例,可单独轮换 |

不要把真实密码和控制器 token 提交到 Git。使用时通过环境变量传入:

```bash
export PROXY_HOST='20.163.32.83'
export PROXY_PORT='17889'
export PROXY_PASS='替换成代理密码'
export CONTROLLER_TOKEN='替换成控制器 token'
```

## 客户端使用

IPv6 `v6-1`:

```bash
export HTTP_PROXY="http://H8J6D25OKFS-v6:${PROXY_PASS}@${PROXY_HOST}:${PROXY_PORT}"
export HTTPS_PROXY="http://H8J6D25OKFS-v6:${PROXY_PASS}@${PROXY_HOST}:${PROXY_PORT}"
export ALL_PROXY="socks5h://H8J6D25OKFS-v6:${PROXY_PASS}@${PROXY_HOST}:${PROXY_PORT}"
```

IPv6 `v6-2`:

```bash
export HTTP_PROXY="http://H8J6D25OKFS-v6-2:${PROXY_PASS}@${PROXY_HOST}:${PROXY_PORT}"
export HTTPS_PROXY="http://H8J6D25OKFS-v6-2:${PROXY_PASS}@${PROXY_HOST}:${PROXY_PORT}"
export ALL_PROXY="socks5h://H8J6D25OKFS-v6-2:${PROXY_PASS}@${PROXY_HOST}:${PROXY_PORT}"
```

IPv6 `v6-3`:

```bash
export HTTP_PROXY="http://H8J6D25OKFS-v6-3:${PROXY_PASS}@${PROXY_HOST}:${PROXY_PORT}"
export HTTPS_PROXY="http://H8J6D25OKFS-v6-3:${PROXY_PASS}@${PROXY_HOST}:${PROXY_PORT}"
export ALL_PROXY="socks5h://H8J6D25OKFS-v6-3:${PROXY_PASS}@${PROXY_HOST}:${PROXY_PORT}"
```

IPv4:

```bash
export HTTP_PROXY="http://H8J6D25OKFS:${PROXY_PASS}@${PROXY_HOST}:${PROXY_PORT}"
export HTTPS_PROXY="http://H8J6D25OKFS:${PROXY_PASS}@${PROXY_HOST}:${PROXY_PORT}"
export ALL_PROXY="socks5h://H8J6D25OKFS:${PROXY_PASS}@${PROXY_HOST}:${PROXY_PORT}"
```

单条命令测试推荐用 `socks5h://`,让 DNS 也走代理:

```bash
curl -x "socks5h://H8J6D25OKFS-v6:${PROXY_PASS}@${PROXY_HOST}:${PROXY_PORT}" https://api64.ipify.org
curl -x "socks5h://H8J6D25OKFS-v6-2:${PROXY_PASS}@${PROXY_HOST}:${PROXY_PORT}" https://api64.ipify.org
curl -x "socks5h://H8J6D25OKFS-v6-3:${PROXY_PASS}@${PROXY_HOST}:${PROXY_PORT}" https://api64.ipify.org
```

业务网站连通性测试:

```bash
curl -x "socks5h://H8J6D25OKFS-v6:${PROXY_PASS}@${PROXY_HOST}:${PROXY_PORT}" \
  -o /dev/null -w 'http=%{http_code} total=%{time_total}\n' \
  https://www.goofish.com/
```

## 查看当前 IPv6 节点

控制器监听:

```text
http://20.163.32.83:18085
```

查看全部节点:

```bash
curl -H "X-Controller-Token: ${CONTROLLER_TOKEN}" \
  "http://${PROXY_HOST}:18085/api/nodes"
```

在入口机本地查看:

```bash
ssh ubuntu@20.163.32.83

TOKEN='替换成控制器 token'
curl -H "X-Controller-Token: ${TOKEN}" \
  http://127.0.0.1:18085/api/nodes | jq .
```

正常结果里每个节点应该满足:

```text
verified=true
ipv6 和 verify_got 一致
v6-1 / v6-2 / v6-3 是不同 IPv6
```

## 手动轮换

只轮换 `v6-1`:

```bash
curl -X POST \
  -H "X-Controller-Token: ${CONTROLLER_TOKEN}" \
  "http://${PROXY_HOST}:18085/api/change-ip?node=v6-1"
```

只轮换 `v6-2`:

```bash
curl -X POST \
  -H "X-Controller-Token: ${CONTROLLER_TOKEN}" \
  "http://${PROXY_HOST}:18085/api/change-ip?node=v6-2"
```

只轮换 `v6-3`:

```bash
curl -X POST \
  -H "X-Controller-Token: ${CONTROLLER_TOKEN}" \
  "http://${PROXY_HOST}:18085/api/change-ip?node=v6-3"
```

指定 suffix:

```bash
curl -X POST \
  -H "X-Controller-Token: ${CONTROLLER_TOKEN}" \
  "http://${PROXY_HOST}:18085/api/change-ip?node=v6-2&suffix=9708"
```

注意:

- 轮换 `v6-2` 不会影响 `v6-1` 和 `v6-3`。
- `H8J6D25OKFS-v6` 和 `H8J6D25OKFS-v6-1` 指向同一个 `v6-1` 出口。
- 路由器重新分配 IPv6 前缀后,Windows 自愈任务会自动使用新 RA 前缀重绑各节点;入口控制器只在 Windows 自愈失败时执行兜底。

## 当前端口映射

入口机:

| 节点 | 用户名 | throttle 端口 | 反向隧道端口 | Windows 本地 SOCKS |
|---|---|---:|---:|---:|
| v4 | `H8J6D25OKFS` | 无 | `40085` | `31080` |
| v6-1 | `H8J6D25OKFS-v6` / `H8J6D25OKFS-v6-1` | `40087` | `40086` | `31081` |
| v6-2 | `H8J6D25OKFS-v6-2` | `40097` | `40096` | `31082` |
| v6-3 | `H8J6D25OKFS-v6-3` | `40107` | `40106` | `31083` |

入口检查:

```bash
ssh ubuntu@20.163.32.83

ss -lntp | grep -E ':(17889|18085|40085|40086|40087|40096|40097|40106|40107|41085)'
systemctl is-active sing-box reverse-ipv6-entry-controller socks-throttle-proxy-v6 socks-throttle-proxy-v6-2 socks-throttle-proxy-v6-3
```

## Windows 出口检查

通过入口机跳到 Windows:

```bash
ssh ubuntu@20.163.32.83

sudo ssh -i /opt/reverse-ipv6-entry-controller/id_ed25519 \
  -p 41085 \
  -o BatchMode=yes \
  -o StrictHostKeyChecking=no \
  -o UserKnownHostsFile=/dev/null \
  Administrator@127.0.0.1 hostname
```

Windows 计划任务:

```powershell
Get-ScheduledTask |
  Where-Object {$_.TaskName -like "*SingBox*"} |
  Select-Object TaskName, State
```

启动任务:

```powershell
Start-ScheduledTask -TaskName SingBoxReverseExitTunnel
Start-ScheduledTask -TaskName SingBoxReverseExitNode
Start-ScheduledTask -TaskName SingBoxReverseExitNodeIPv6
Start-ScheduledTask -TaskName SingBoxReverseExitNodeIPv6-v6-2
Start-ScheduledTask -TaskName SingBoxReverseExitNodeIPv6-v6-3
```

检查本地监听:

```powershell
Get-NetTCPConnection -State Listen |
  Where-Object { $_.LocalPort -in 31080,31081,31082,31083 } |
  Select-Object LocalAddress,LocalPort,OwningProcess
```

检查 Windows 当前 IPv6:

```powershell
Get-NetIPAddress -AddressFamily IPv6 -InterfaceAlias WLAN |
  Where-Object { $_.IPAddress -like "2408:*" } |
  Select-Object IPAddress,PrefixLength,AddressState,PrefixOrigin,SkipAsSource
```

检查 Windows IPv6 默认路由:

```powershell
Get-NetRoute -AddressFamily IPv6 -InterfaceAlias WLAN -DestinationPrefix "::/0"
```

Windows 本机直连测试:

```powershell
curl.exe -6 -sS --max-time 15 https://api64.ipify.org
curl.exe -4 -sS --max-time 15 https://www.goofish.com/ -o NUL -w "http=%{http_code} total=%{time_total}"
```

Windows 本地 SOCKS 测试:

```powershell
curl.exe --socks5-hostname 127.0.0.1:31081 -sS --max-time 15 https://api64.ipify.org
curl.exe --socks5-hostname 127.0.0.1:31082 -sS --max-time 15 https://api64.ipify.org
curl.exe --socks5-hostname 127.0.0.1:31083 -sS --max-time 15 https://api64.ipify.org
```

## 日志

入口机日志:

```bash
ssh ubuntu@20.163.32.83

sudo journalctl -u sing-box --since "30 minutes ago" --no-pager
sudo journalctl -u reverse-ipv6-entry-controller --since "30 minutes ago" --no-pager
sudo journalctl -u socks-throttle-proxy-v6 --since "30 minutes ago" --no-pager
sudo journalctl -u socks-throttle-proxy-v6-2 --since "30 minutes ago" --no-pager
sudo journalctl -u socks-throttle-proxy-v6-3 --since "30 minutes ago" --no-pager
```

入口 throttle 指标:

```bash
curl http://127.0.0.1:18087/metrics
curl http://127.0.0.1:18097/metrics
curl http://127.0.0.1:18107/metrics
```

Windows 日志:

```powershell
Get-Content C:\sing-box-reverse-exit\logs\windows-v6-self-heal.log -Tail 100
Get-Content C:\sing-box-reverse-exit\logs\tunnel.log -Tail 100
Get-Content C:\sing-box-reverse-exit\logs\sing-box-v4.log -Tail 100
Get-Content C:\sing-box-reverse-exit\logs\sing-box-v6.log -Tail 100
Get-Content C:\sing-box-reverse-exit\logs\sing-box-v6-2.log -Tail 100
Get-Content C:\sing-box-reverse-exit\logs\sing-box-v6-3.log -Tail 100
```

Windows 自愈状态:

```powershell
Get-Content C:\sing-box-reverse-exit\windows-v6-self-heal-state.json
Get-ScheduledTask -TaskName SingBoxReverseExitSelfHeal |
  Select-Object TaskName,State,LastRunTime,NextRunTime
```

## 常见故障

### curl: (97) Can't complete SOCKS5 connection

常见原因:

- 用户名或密码错误。
- 入口 sing-box 能连到后端 SOCKS,但 Windows 出口无法连目标站。
- Windows 本地 SOCKS 端口未监听。
- Windows IPv6 地址前缀变了,配置仍绑定旧前缀。

排查顺序:

```bash
curl -x "socks5h://H8J6D25OKFS-v6:${PROXY_PASS}@${PROXY_HOST}:${PROXY_PORT}" https://api64.ipify.org

ssh ubuntu@20.163.32.83
ss -lntp | grep -E ':(17889|40086|40087|41085)'
sudo journalctl -u sing-box --since "10 minutes ago" --no-pager | grep H8J6D25OKFS-v6
```

如果日志里是 `authentication failed`,优先检查账号密码。

如果日志里是 `socks5: request rejected, code=1`,继续检查 Windows 本地 SOCKS 和 IPv6 外网。

### Windows IPv6 前缀变化

表现:

```text
Windows curl.exe -6 https://api64.ipify.org 能返回新 IPv6
但代理仍绑定旧前缀,代理访问超时或 code=1
```

处理:

```bash
curl -X POST -H "X-Controller-Token: ${CONTROLLER_TOKEN}" \
  "http://${PROXY_HOST}:18085/api/change-ip?node=v6-1"

curl -X POST -H "X-Controller-Token: ${CONTROLLER_TOKEN}" \
  "http://${PROXY_HOST}:18085/api/change-ip?node=v6-2"

curl -X POST -H "X-Controller-Token: ${CONTROLLER_TOKEN}" \
  "http://${PROXY_HOST}:18085/api/change-ip?node=v6-3"
```

### Windows 自己 IPv6 外网不通

表现:

```powershell
curl.exe -6 -sS --max-time 15 https://api64.ipify.org
```

也超时。

这时不是入口机和代理配置问题,优先检查路由器/光猫/运营商 IPv6。可以在 Windows 看默认路由:

```powershell
Get-NetRoute -AddressFamily IPv6 -InterfaceAlias WLAN -DestinationPrefix "::/0"
ping.exe -6 fe80::3296:10ff:fec4:4a5f%12
tracert.exe -6 -d -h 5 2400:3200::1
```

如果能 ping 到 `fe80::...` 网关,但公网 IPv6 超时,问题通常在路由器上游或运营商链路。

控制器默认每分钟检查 Windows 网卡上的当前 `RouterAdvertisement` IPv6 前缀。发现节点仍绑定旧前缀时,会只轮换该节点并验证出口,不影响其他节点。也可以在配置中显式设置检查周期:

```json
{
  "prefix_check_every": "1m"
}
```

轮换脚本只接受 `AddressState=Preferred` 且 `PrefixOrigin=RouterAdvertisement` 的全局 IPv6 地址,不再从旧的手工地址中选择前缀。如果当前网卡没有可用的 RA IPv6,轮换会失败并保留错误状态,避免绑定一个看似成功但无法出网的地址。

控制器还会默认每分钟通过每个 Windows 本地 SOCKS 端口执行一次健康检查。连续 2 次失败才自动轮换该节点,轮换后有 5 分钟冷却时间,避免短暂丢包造成频繁重启。可以通过配置调整:

```json
{
  "health_check_every": "1m",
  "health_url": "https://api64.ipify.org",
  "health_fail_limit": 2,
  "health_cooldown": "5m"
}
```

健康检查结果会出现在 `/api/nodes` 的 `health_ok`、`health_got`、`health_error` 和 `health_failures` 字段中。

Windows 节点同时运行本机自愈任务 `SingBoxReverseExitSelfHeal`,每分钟优先检查当前 RA 前缀。当前前缀变化时由 Windows 本机直接更新各 v6 sing-box 实例,不依赖入口控制器或 `41085` 控制隧道;隧道任务停止时也会尝试本地拉起。自愈日志和失败计数位于:

```text
C:\sing-box-reverse-exit\logs\windows-v6-self-heal.log
C:\sing-box-reverse-exit\windows-v6-self-heal-state.json
```

### v4 不通但 Windows IPv4 直连正常

检查 Windows 本地 v4 SOCKS `31080` 是否监听:

```powershell
Get-NetTCPConnection -State Listen |
  Where-Object { $_.LocalPort -eq 31080 }
```

如果没有监听:

```powershell
Start-ScheduledTask -TaskName SingBoxReverseExitNode
```

然后从客户端测:

```bash
curl -x "socks5h://H8J6D25OKFS:${PROXY_PASS}@${PROXY_HOST}:${PROXY_PORT}" \
  https://www.goofish.com/ -o /dev/null -w 'http=%{http_code} total=%{time_total}\n'
```

## 当前最后一次验证结果

最后一次人工验证时间:`2026-09-08`

```text
H8J6D25OKFS      -> 114.254.32.67                  goofish=200
H8J6D25OKFS-v6   -> 2408:8207:3c12:dcd1::9618      goofish=200
H8J6D25OKFS-v6-2 -> 2408:8207:3c12:dcd1::9704      goofish=200
H8J6D25OKFS-v6-3 -> 2408:8207:3c12:dcd1::9806      goofish=200
```