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.
172 lines
3.6 KiB
Markdown
172 lines
3.6 KiB
Markdown
# SOCKS5 Monitor
|
||
|
||
一个轻量的 SOCKS5 代理健康监控面板,支持节点检测、状态记录和通知告警。
|
||
|
||
## 功能
|
||
|
||
- SOCKS5 连通性检测:协商、认证并 CONNECT 到目标地址
|
||
- 全局默认检测目标与节点级覆盖
|
||
- 检测间隔、超时、失败/恢复阈值可配置
|
||
- 通知渠道:Bark、PushPlus、Autman、Webhook
|
||
- SQLite 保存检测记录、事件和通知日志
|
||
- 可配置单节点最多保留的监测记录数,并可一键清空日志
|
||
- Docker / Docker Compose 部署
|
||
|
||
## 快速启动
|
||
|
||
```bash
|
||
cp config.example.json config.json
|
||
docker compose up -d
|
||
```
|
||
|
||
访问:
|
||
|
||
```text
|
||
http://127.0.0.1:8787
|
||
```
|
||
|
||
## 本地运行
|
||
|
||
```bash
|
||
python3 app.py --host 0.0.0.0 --port 8787 --config config.json
|
||
```
|
||
|
||
## 配置
|
||
|
||
默认配置见 `config.example.json`。实际运行配置写入 `config.json`,不要提交真实账号、密码、Token 或私有地址。
|
||
|
||
### 全局检测设置
|
||
|
||
```json
|
||
{
|
||
"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
|
||
}
|
||
```
|
||
|
||
### 节点配置
|
||
|
||
```json
|
||
{
|
||
"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:
|
||
|
||
```json
|
||
{
|
||
"message": "标题:...\n内容:...",
|
||
"access_token": "..."
|
||
}
|
||
```
|
||
|
||
配置示例:
|
||
|
||
```json
|
||
{
|
||
"type": "autman",
|
||
"enabled": false,
|
||
"config": {
|
||
"url": "http://example.com/m/push1",
|
||
"access_token": ""
|
||
}
|
||
}
|
||
```
|
||
|
||
## API
|
||
|
||
```text
|
||
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` 支持直接粘贴以下形式,服务端会拆成主机名 + 端口:
|
||
|
||
```text
|
||
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 01` →
|
||
`HK-Node-01`),含中文/emoji 的名字分配递增 `node-N`。两种路径都会自动去重,
|
||
不会因重名报错。`PUT` 编辑不会改变已有 id。
|
||
|
||
## 测试
|
||
|
||
```bash
|
||
python3 -m unittest discover -s tests
|
||
```
|
||
|
||
## Docker 镜像
|
||
|
||
```text
|
||
192.168.2.66:80/hermes/socks5-monitor:latest
|
||
```
|
||
|
||
上游基础镜像(`python:3.11-alpine`)拉取受限时,可用 `Dockerfile.patch` 在上一版
|
||
镜像之上只叠加应用源码做增量构建:
|
||
|
||
```bash
|
||
docker build -f Dockerfile.patch -t 192.168.2.66:80/hermes/socks5-monitor:latest .
|
||
```
|
||
|
||
## 数据目录
|
||
|
||
```text
|
||
data/monitor.db
|
||
```
|
||
|
||
## 安全
|
||
|
||
- `config.json`、`data/`、日志和缓存不应提交到源码仓库
|
||
- 镜像构建只包含 `config.example.json`,不包含真实运行配置
|
||
- 公开仓库中只保留占位配置
|