Hermes ce0aa22672 Fix node id collision, host normalization and blank error text
Three defects made the panel look broken to the operator:

- POST /api/proxies with a Chinese name slugged the id down to its ASCII
  digits ("香港01" -> "01"), collided with an existing node and returned
  HTTP 500 "proxy id already exists". Non-ASCII names now get sequential
  node-N ids; ASCII names keep a readable slug. Both paths de-duplicate.
- A host pasted as a URL ("http://192.168.3.71") went straight to DNS, so
  every check failed with "[Errno -2] Name does not resolve". normalize_host
  accepts host, host:port, scheme://user:pass@host:port and [IPv6]:port, and
  existing configs are healed at startup.
- str(asyncio.TimeoutError()) is empty, so a black-holed proxy showed a blank
  error in the UI and looked like an internal bug. describe_exc always
  produces a reason.

Also:
- Expected validation failures return 400 with an error message instead of
  500 + traceback; the frontend surfaces every API error as a toast.
- PUT/DELETE on an unknown proxy id return 404 instead of silently creating
  or reporting ok=false with 200.
- POST /api/check/<id> forces a check on disabled nodes instead of returning
  ok=true without doing anything.
- Port range is validated (1..65535).
- Store.close() lets tests release SQLite handles.
- 33 unittest cases cover id generation, host normalization, error text,
  startup migration and manual checks.
2026-08-23 14:07:37 +08:00
2026-05-28 20:26:44 +08:00

SOCKS5 Monitor

一个轻量的 SOCKS5 代理健康监控面板,支持节点检测、状态记录和通知告警。

功能

  • SOCKS5 连通性检测:协商、认证并 CONNECT 到目标地址
  • 全局默认检测目标与节点级覆盖
  • 检测间隔、超时、失败/恢复阈值可配置
  • 通知渠道:Bark、PushPlus、Autman、Webhook
  • SQLite 保存检测记录、事件和通知日志
  • 可配置单节点最多保留的监测记录数,并可一键清空日志
  • Docker / Docker Compose 部署

快速启动

cp config.example.json config.json
docker compose up -d

访问:

http://127.0.0.1:8787

本地运行

python3 app.py --host 0.0.0.0 --port 8787 --config config.json

配置

默认配置见 config.example.json。实际运行配置写入 config.json,不要提交真实账号、密码、Token 或私有地址。

全局检测设置

{
  "target_host": "www.baidu.com",
  "target_port": 443,
  "interval_seconds": 300,
  "timeout_seconds": 8,
  "fail_threshold": 3,
  "recover_threshold": 1,
  "max_checks_per_proxy": 500
}

节点配置

{
  "id": "proxy-1",
  "name": "Example Proxy",
  "host": "127.0.0.1",
  "port": 1080,
  "username": "",
  "password": "",
  "target_host": "www.baidu.com",
  "target_port": 443,
  "timeout_seconds": 8,
  "interval_seconds": 300,
  "fail_threshold": 3,
  "recover_threshold": 1,
  "enabled": false
}

Autman 通知

Autman 通道适配 /m/push1 消息推送插件,发送 JSON

{
  "message": "标题:...\n内容:...",
  "access_token": "..."
}

配置示例:

{
  "type": "autman",
  "enabled": false,
  "config": {
    "url": "http://example.com/m/push1",
    "access_token": ""
  }
}

API

GET    /api/status
PUT    /api/settings
DELETE /api/logs
POST   /api/check/<id>
POST   /api/notify/test
POST   /api/proxies
PUT    /api/proxies/<id>
DELETE /api/proxies/<id>
GET    /api/channels
POST   /api/channels
PUT    /api/channels/<id>
DELETE /api/channels/<id>
POST   /api/channels/<id>/test

节点列表通过 GET /api/status 返回(含运行状态和最近记录),没有单独的 GET /api/proxies。参数校验失败返回 400 并带 error 说明,仅未预期的内部 错误返回 500

节点字段说明

Host 会被自动归一化

host 支持直接粘贴以下形式,服务端会拆成主机名 + 端口:

192.168.1.10
192.168.1.10:7890
http://192.168.1.10:7890
socks5://user:pass@192.168.1.10:1080
[2001:db8::1]:1080

未显式指定 port(或仍为默认 1080)时采用 URL 中的端口。启动时也会自动修正 历史配置里残留的带协议前缀的 host,避免出现 [Errno -2] Name does not resolve

节点 id 生成规则

未显式提供 id 时由 name 推导:纯 ASCII 名字保留可读 slug(HK Node 01HK-Node-01),含中文/emoji 的名字分配递增 node-N。两种路径都会自动去重, 不会因重名报错。PUT 编辑不会改变已有 id。

测试

python3 -m unittest discover -s tests

Docker 镜像

192.168.2.66:80/hermes/socks5-monitor:latest

上游基础镜像(python:3.11-alpine)拉取受限时,可用 Dockerfile.patch 在上一版 镜像之上只叠加应用源码做增量构建:

docker build -f Dockerfile.patch -t 192.168.2.66:80/hermes/socks5-monitor:latest .

数据目录

data/monitor.db

安全

  • config.jsondata/、日志和缓存不应提交到源码仓库
  • 镜像构建只包含 config.example.json,不包含真实运行配置
  • 公开仓库中只保留占位配置
S
Description
SOCKS5 proxy monitoring panel with notifications
Readme
173 KiB
Languages
Python 68%
HTML 31.3%
Dockerfile 0.7%