9890cfc488
- AdminUser model: multi-admin accounts with bcrypt hashing (admin_users table) - Three roles: superadmin / admin / viewer with granular permission bits - auth.py: login migrated from env-var single admin to DB-backed accounts; seed_initial_admin() auto-creates first superadmin from SM_ADMIN_PASSWORD - Web UI: /system/admins page (add/edit role/toggle/reset pwd/delete) + change-my-password; sidebar entry; permission-guarded routes - REST API: /api/admins CRUD with protection checks - Protections: cannot delete/disable self; keep >=1 enabled superadmin; disabled accounts fail permission checks immediately - README: document roles, permission bits, API
330 lines
13 KiB
Markdown
330 lines
13 KiB
Markdown
# SOCKS Manager — SOCKS5 代理管理平台
|
||
|
||
内建 asyncio SOCKS5 服务器(RFC 1928/1929)的完整代理管理平台,一个 Python 进程即可运行。支持多实例管理、流量控制、用户管理、审计日志、实时监控。
|
||
|
||
## 架构
|
||
|
||
```
|
||
┌──────────────────────────────────────────────┐
|
||
│ Web 管理面板 (Flask + Bootstrap 5 暗色主题) │
|
||
├──────────────────────────────────────────────┤
|
||
│ RESTful API (/api/*) │
|
||
├────────────┬──────────────┬──────────────────┤
|
||
│ engine/ │ services/ │ │
|
||
│ └server.py │ └user_service│ 数据: SQLite │
|
||
│ asyncio │ 流量/认证 │ socks_manager.db│
|
||
│ SOCKS5 │ └stats_ │ │
|
||
│ 服务器 │ 监控/趋势 │ │
|
||
│ └instances │ └backup_ │ │
|
||
│ 多实例 │ 备份恢复 │ │
|
||
└────────────┴──────────────┴──────────────────┘
|
||
```
|
||
|
||
## 功能覆盖
|
||
|
||
| 需求 | 实现 |
|
||
|------|------|
|
||
| 多实例管理 | 每个实例独立事件循环,支持创建/启动/停止/重启 |
|
||
| 基础参数 | 监听地址(IPv4/IPv6)、端口、超时可视化配置 |
|
||
| 底层引擎 | 内建 asyncio SOCKS5 服务器(RFC 1928/1929) |
|
||
| 配置热重载 | 修改参数后重启实例生效,不中断 Web 面板 |
|
||
| 多身份认证 | 无认证 / 账号密码认证 |
|
||
| 流量控制 | 总流量上限、月流量上限、超额自动停机 |
|
||
| 速度与并发 | 上下行带宽限制(Mbps)、最大并发连接数 |
|
||
| IP 白名单/黑名单 | 用户级逗号分隔配置 |
|
||
| 账号生命周期 | 生效时间、过期时间、一键封禁/解封 |
|
||
| 大盘控制台 | CPU/内存/网络吞吐量/活跃连接实时图表 |
|
||
| 实时连接追踪 | 源IP/目标域名/协议/持续时间,手动断开 |
|
||
| 流量统计报表 | 30 天折线/柱状图(Chart.js) |
|
||
| 详细审计日志 | 按事件/用户/IP 筛选,分页查询 |
|
||
| 级联代理 | 连接建立时自动代理至目标(可扩展 upstream) |
|
||
| 负载均衡 | 多实例配置后按端口轮询 |
|
||
| 管理员认证 | 多管理员账户存数据库(`AdminUser` 表,bcrypt 哈希),支持角色权限 |
|
||
| 角色权限 | superadmin / admin / viewer 三级角色,细粒度权限位控制 |
|
||
| 管理员管理 | Web/API 增删改、启停、改角色、重置密码(带保护校验) |
|
||
| 防爆破 | 自动阻断频繁登录尝试(Fail2Ban 机制) |
|
||
| 密码安全 | bcrypt 哈希存储 SOCKS5 用户密码(兼容旧明文自动迁移) |
|
||
| 会话管理 | 自定义 Cookie 域名/安全/名称,支持 HTTPS 部署 |
|
||
| 自动备份 | 一键备份 SQLite,按份数清理 |
|
||
| 每日流量快照 | 后台线程每小时记录一次,用于月度趋势图表 |
|
||
| RESTful API | 全部管理功能通过 `/api/` 暴露 |
|
||
|
||
## 快速开始
|
||
|
||
```bash
|
||
cd /root/socks-manager
|
||
|
||
# 安装依赖
|
||
pip install -r requirements.txt --break-system-packages
|
||
|
||
# 设置管理员密码(首次启动如未设置,自动使用默认密码 admin123 并写入 .env)
|
||
export SM_ADMIN_PASSWORD=你的密码
|
||
|
||
# 启动
|
||
python3 run.py
|
||
```
|
||
|
||
访问 `http://你的IP:5000`,用户名 `admin`,密码为环境变量值。
|
||
|
||
> ⚠️ 首次启动时如果 `SM_ADMIN_PASSWORD` 未设置,会自动写入默认密码 `admin123` 到 `.env` 文件。**生产环境请务必修改此密码。**
|
||
|
||
## 系统账户管理
|
||
|
||
Web 后台管理员账户存储在数据库(`admin_users` 表),支持多账户与角色权限,通过 **系统管理 → 管理员账户** 管理(也可用 REST API `/api/admins`)。
|
||
|
||
### 三级角色
|
||
|
||
| 角色 | 权限 |
|
||
|------|------|
|
||
| **superadmin** 超级管理员 | 全部权限,含管理员账户管理(增删改/启停/改角色/重置密码) |
|
||
| **admin** 管理员 | 用户/实例/系统管理,可查看管理员账户但不能修改 |
|
||
| **viewer** 只读用户 | 仅查看仪表盘/实例/用户/日志,无任何写操作 |
|
||
|
||
### 角色权限位
|
||
每个角色对应一组权限位(`users:read`、`users:write`、`instances:read`、`instances:write`、`system:read`、`system:write`、`admins:read`、`admins:write`、`logs:read`、`stats:read`),可在 `models.py` 的 `ROLE_PERMISSIONS` 中扩展。
|
||
|
||
### 安全保护
|
||
- **不能删除/禁用当前登录账户**
|
||
- **至少保留一个启用的超级管理员**(删除最后一位 superadmin 会被拒绝)
|
||
- 登录密码 bcrypt 哈希存储
|
||
- 账户禁用后立即失效(权限校验实时检查)
|
||
|
||
### REST API
|
||
```
|
||
GET /api/admins # 列出管理员
|
||
POST /api/admins # 创建 {username, password, role}
|
||
PUT /api/admins/<id> # 更新 {role?, password?, enabled?}
|
||
DELETE /api/admins/<id> # 删除(带保护校验)
|
||
```
|
||
|
||
## 环境变量
|
||
|
||
| 变量 | 默认值 | 说明 |
|
||
|------|--------|------|
|
||
| `SM_ADMIN_USER` | `admin` | 管理员用户名 |
|
||
| `SM_ADMIN_PASSWORD` | `""` | 管理员密码(必须设置) |
|
||
| `SM_SECRET_KEY` | `sm-dev-key-change-in-prod` | Flask 会话密钥(生产环境务必修改,建议随机 64 位字符串) |
|
||
| `SM_SESSION_DOMAIN` | `None` | 会话 Cookie 域名(跨域访问时设为你的域名或 IP) |
|
||
| `SM_COOKIE_SECURE` | `false` | 是否启用 Cookie Secure 标志(HTTPS 时设为 `true`) |
|
||
| `SM_SESSION_NAME` | `sm_session` | 会话 Cookie 名称(多实例同域名时避免冲突) |
|
||
| `SM_DB_URI` | `sqlite:///socks_manager.db` | 数据库连接串 |
|
||
| `SM_PORT` | `5000` | Web 面板监听端口 |
|
||
| `SM_HOST` | `0.0.0.0` | Web 面板监听地址 |
|
||
| `SM_BACKUP_DIR` | `./backups/` | 备份文件存储目录 |
|
||
| `SM_LOG_LEVEL` | `INFO` | 日志级别:`DEBUG`/`INFO`/`WARN`/`ERROR` |
|
||
|
||
## 常见问题
|
||
|
||
### 1. 在其他服务器上无法登录
|
||
|
||
问题:浏览器访问面板,输入密码后提示错误或跳转回登录页。
|
||
|
||
**可能原因 & 解决方案:**
|
||
|
||
| 原因 | 解决 |
|
||
|------|------|
|
||
| 密码不一致 | 确认所有服务器 `.env` 文件中的 `SM_ADMIN_PASSWORD` 一致 |
|
||
| Cookie 被浏览器拒绝(HTTP + 非标准域名) | 通过 `curl -c /tmp/cookies.txt -X POST -d "username=admin&password=xxx" http://你的IP:5000/login` 测试 |
|
||
| 通过 SOCKS5 代理访问面板 | 直连(非代理模式)访问面板 |
|
||
| Session Cookie 域名不匹配 | 设置 `SM_SESSION_DOMAIN=你的IP` 并重启 |
|
||
| HTTPS 下未设置 Secure | 设置 `SM_COOKIE_SECURE=true` |
|
||
|
||
验证登录是否成功:
|
||
```bash
|
||
curl -c /tmp/sm_cookies.txt -b /tmp/sm_cookies.txt \
|
||
-X POST -d "username=admin&password=你的密码" \
|
||
http://你的IP:5000/login -w "%{http_code} %{redirect_url}"
|
||
```
|
||
返回 `302 /dashboard` 表示成功。
|
||
|
||
### 2. 仪表盘流量趋势图无数据
|
||
|
||
首次部署后需等待 1 小时,后台线程每小时记录一次流量快照。也可以手动记录一次:
|
||
```bash
|
||
python3 -c "from services.stats_service import record_traffic_snapshot; record_traffic_snapshot()"
|
||
```
|
||
|
||
### 3. SOCKS5 用户密码安全性
|
||
|
||
SOCKS5 协议(RFC 1929)本身采用明文传输密码。本项目服务端使用 **bcrypt** 哈希存储,兼容旧版明文存储的数据库(首次验证时自动迁移到哈希)。Web 面板中展示用户时不会泄露密码。
|
||
|
||
## 核心代码结构
|
||
|
||
```
|
||
├── app.py # Flask 应用工厂
|
||
├── config.py # 配置
|
||
├── auth.py # 登录认证 + 防爆破
|
||
├── models.py # SQLAlchemy 数据模型(含 bcrypt 密码方法)
|
||
├── database.py # 数据库初始化
|
||
├── run.py # 启动入口
|
||
│
|
||
├── engine/
|
||
│ ├── server.py # asyncio SOCKS5 服务器(核心引擎)
|
||
│ └── instances.py # 多实例管理器(线程安全)
|
||
│
|
||
├── services/
|
||
│ ├── user_service.py # 用户管理/认证/流量/防爆破
|
||
│ ├── stats_service.py# 监控/统计/趋势/流量快照
|
||
│ └── backup_service.py# 备份与恢复
|
||
│
|
||
├── api/
|
||
│ └── v1.py # RESTful API(实例/用户/日志/备份)
|
||
│
|
||
├── web/
|
||
│ └── routes.py # Web 管理面板路由
|
||
│
|
||
└── templates/ # Jinja2 模板(暗色 Bootstrap 5)
|
||
├── base.html # 布局(侧边栏+导航+全局样式)
|
||
├── dashboard.html # 仪表盘(实时图表 + 最近审计日志)
|
||
├── instances.html # 代理实例管理
|
||
├── users.html # 用户管理
|
||
├── stats.html # 流量统计
|
||
├── connections.html# 活跃连接
|
||
├── logs.html # 审计日志
|
||
└── system.html # 系统管理
|
||
```
|
||
|
||
## API 参考
|
||
|
||
| 方法 | 路径 | 说明 |
|
||
|------|------|------|
|
||
| GET | `/api/dashboard` | 仪表盘汇总 |
|
||
| GET | `/api/stats/system` | 实时系统指标(含最近 10 分钟历史) |
|
||
| GET | `/api/stats/connections` | 活跃连接列表 |
|
||
| GET | `/api/stats/traffic-trend?days=30` | 流量趋势 |
|
||
| GET | `/api/stats/users` | 用户流量排名 |
|
||
| GET | `/api/stats/instances` | 实例流量统计 |
|
||
| GET/POST | `/api/instances` | 实例列表/创建 |
|
||
| PUT/DELETE | `/api/instances/<id>` | 更新/删除实例 |
|
||
| POST | `/api/instances/<id>/start\|stop\|restart` | 实例启停 |
|
||
| POST | `/api/instances/sync` | 同步所有实例状态 |
|
||
| GET/POST | `/api/users` | 用户列表/创建 |
|
||
| PUT/DELETE | `/api/users/<id>` | 更新/删除用户 |
|
||
| POST | `/api/users/<id>/toggle\|ban` | 用户启停/封禁 |
|
||
| GET | `/api/logs?page=1&event=&user=&src_ip=` | 审计日志查询 |
|
||
| GET/POST | `/api/backups` | 备份列表/创建 |
|
||
| POST | `/api/backups/<id>/restore` | 恢复备份 |
|
||
| POST | `/api/backups/cleanup` | 清理旧备份 |
|
||
|
||
所有 API 需要登录认证(Session Cookie),未登录返回 401。
|
||
|
||
## 生产部署
|
||
|
||
### 1. WSGI 生产服务器(Gunicorn)
|
||
|
||
Flask 内置开发服务器不适合生产环境。使用 **Gunicorn**(生产级 WSGI 服务器):
|
||
|
||
```bash
|
||
# 安装 gunicorn
|
||
pip install gunicorn --break-system-packages
|
||
|
||
# 最小启动(不推荐生产,worker 数量 = CPU 核心数,单核机器用 -w 1)
|
||
gunicorn -w 1 -b 0.0.0.0:5000 run:app
|
||
|
||
# 推荐参数:30s 超时 + 优雅关闭 + 周期性回收 worker 防内存泄漏
|
||
gunicorn -w 1 -b 0.0.0.0:5000 \
|
||
--timeout 30 \
|
||
--graceful-timeout 30 \
|
||
--max-requests 1000 \
|
||
--max-requests-jitter 100 \
|
||
--limit-request-line 8190 \
|
||
--limit-request-fields 100 \
|
||
run:app
|
||
```
|
||
|
||
> **注意**:SOCKS5 代理实例运行在独立的 asyncio 线程中,不受 Gunicorn worker 数量影响。
|
||
> **生产请用 systemd 托管**,见下节;裸 gunicorn 没有开机自启和崩溃重启。
|
||
|
||
---
|
||
|
||
### 2. Systemd 服务配置(推荐)
|
||
|
||
服务单元文件的**唯一权威源**在仓库 `deploy/socks-manager.service`。
|
||
所有参数、调优注释、`MemoryMax` 限制都集中在那一份,生产机只放一份拷贝。
|
||
|
||
部署步骤:
|
||
|
||
```bash
|
||
# 1. 在本地修改 deploy/socks-manager.service
|
||
# 2. git commit + push
|
||
# 3. 在生产机 (/opt/socks-manager) 拉取并执行:
|
||
git pull
|
||
sudo bash deploy/install.sh
|
||
```
|
||
|
||
`install.sh` 做的事:复制 unit 到 `/etc/systemd/system/` → `daemon-reload` → `enable` (开机自启) → `restart` → 等 15s 验证 active。
|
||
|
||
完整 unit 见 [`deploy/socks-manager.service`](deploy/socks-manager.service),关键参数说明:
|
||
- `-w 1` / `--timeout 30` / `--graceful-timeout 30` — 1 核 + 1GB 内存机型的基线,按 `nproc` 调整 `-w`
|
||
- `--max-requests 1000` + jitter — 周期性回收 worker 防内存泄漏
|
||
- `MemoryMax=512M` — cgroup 硬上限,防整台 VPS 被拖死
|
||
- `LimitNOFILE=65535` — SOCKS5 大并发客户端连接需要
|
||
|
||
常用命令:
|
||
```bash
|
||
systemctl status socks-manager
|
||
journalctl -u socks-manager -f # 实时日志
|
||
systemctl restart socks-manager # 改完代码后重启
|
||
```
|
||
|
||
---
|
||
|
||
### 3. Nginx 反向代理 + SSL
|
||
|
||
```nginx
|
||
server {
|
||
listen 80;
|
||
server_name 你的域名;
|
||
return 301 https://$server_name$request_uri;
|
||
}
|
||
|
||
server {
|
||
listen 443 ssl http2;
|
||
server_name 你的域名;
|
||
|
||
ssl_certificate /etc/letsencrypt/live/你的域名/fullchain.pem;
|
||
ssl_certificate_key /etc/letsencrypt/live/你的域名/privkey.pem;
|
||
|
||
location / {
|
||
proxy_pass http://127.0.0.1:5000;
|
||
proxy_set_header Host $host;
|
||
proxy_set_header X-Real-IP $remote_addr;
|
||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||
proxy_set_header X-Forwarded-Proto $scheme;
|
||
proxy_buffering off;
|
||
proxy_request_buffering off;
|
||
proxy_http_version 1.1;
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### 4. 生产环境检查清单
|
||
|
||
✅ **强制修改默认密码**
|
||
```bash
|
||
# 生成强密钥
|
||
export SM_SECRET_KEY=$(openssl rand -hex 32)
|
||
```
|
||
|
||
✅ **数据库备份**
|
||
- 配置 crontab 每日备份 `socks_manager.db`
|
||
- 定期测试恢复流程
|
||
|
||
✅ **日志级别**
|
||
- 生产环境设置 `SM_LOG_LEVEL=WARN` 减少日志量
|
||
|
||
✅ **HTTPS**
|
||
- 启用 Let's Encrypt SSL 证书
|
||
- 设置 `SM_COOKIE_SECURE=true`
|
||
|
||
✅ **防火墙**
|
||
- 只开放需要的端口:Web 面板(5000) + SOCKS5 代理端口
|
||
- SOCKS5 端口建议限制源 IP
|
||
|
||
✅ **优雅关闭**
|
||
- v1.1+ 版本已修复 SOCKS5 实例的优雅关闭逻辑
|
||
- 停止服务时最多等待 5 秒让活跃连接正常关闭
|
||
- 避免 `GeneratorExit` 和 `Task was destroyed` 警告
|