Files
frps-manager/README.md
T
Your Name 13b38ec60b docs: systemd units are auto-generated by deploy.sh
- Update deploy section to explain dynamic generation
- Update client guide: scp from server or manual creation
- Note: project can be installed to any directory
2026-08-10 14:29:58 +08:00

357 lines
13 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# frps-manager
基于 frps 0.70.1 的内网穿透 Web 管理系统,多租户 + Web 端代理规则 CRUD。
## 功能
| 模块 | 说明 |
|------|------|
| 仪表盘 | frps 状态、监听端口、在线客户端/代理数、Server Token 显示、实时在线列表 |
| 租户 | 多租户隔离,每个租户独立带宽/连接配额 |
| 客户端 (frpc) | 注册 frpc 客户端(user 字段 + token),归属租户,启停、旋转 token |
| 代理规则 | 支持 tcp / udp / http / https,配置远端端口、域名、加密压缩、健康检查 |
| frpc.ini 生成 | 点客户端的「frpc.ini」按钮下载一份含所有代理 + 共享 server token + admin API 的配置 |
| 热重载支持 | 生成的 frpc.ini 默认带 `admin_addr`/`admin_port`,修改代理后用户在 frpc 主机执行 `frpc reload -c /etc/frpc.ini` 即可生效(无需 SSH 重启) |
| 用户 | admin / tenant_admin / user 三级 RBAC,每个用户绑定到租户 |
| 审计日志 | 全部管理操作(创建/删除/旋转 token/重载 frps…)写入日志 |
| frps 控制 | 通过 Web 重写 frps.ini 并重启 frps、旋转 server token、查看生成的 frps.ini |
## 关键设计:frps 0.70 的特殊性
**fatedier/frp 0.70.1 的 TOML 配置和 auth 流程有问题**
- TOML 解析器**不接受** `auth.method = "token"` / `auth.token = "..."` 这种点路径键(尽管官方 example 文件这么写)
- `--token` CLI flag 设的值会被 TOML 加载流程覆盖为**空值**
- **唯一真正可用的格式**`legacy INI``[common]` + `token = xxx`),frp 在加载时会打印 `WARNING: ini format is deprecated`
所以本系统:
- 生成 `frps.ini`legacy INI)而不是 frps.toml
- 生成 `frpc.ini`legacy INI)给用户
- 会在 frps 日志看到 deprecation warning — 这是 frp 项目已知问题,未来升级到 0.71+(修复 TOML auth 后)只需把 `render_frps_ini` 改成 TOML 渲染
**另一个特殊性**frps 0.70+ **没有 server-side `[[proxies]]` 段** — 所有代理规则都在 frpc 端 `[[xxx]]` 配置里,启动时通过 control message 推给 frps。所以 Web 系统**所有代理数据都在 frpc.ini 里**frps.ini 只管 bind/dashboard/auth/log。
## 技术栈
- **后端**: Flask 3.0 + Flask-SQLAlchemy + SQLite
- **WSGI**: Gunicorn (2 workers)
- **前端**: Jinja2 模板 + 原生 CSS(无前端框架依赖)
- **被管理**: frps 0.70.1GitHub: fatedier/frp+ frpc 0.70.1
- **认证**: Werkzeug password hashing + Flask session
## 目录结构
```
frps-manager/
├── app.py # Flask 应用主文件(模型、路由、INI 渲染逻辑)
├── wsgi.py # Gunicorn 入口(DB 初始化)
├── init_db.py # 独立 DB 初始化脚本
├── requirements.txt
├── README.md
├── _smoke_test.py # 端到端测试(起 frps + frpc + reload 验证)
├── scripts/
│ ├── deploy.sh # 一键部署脚本(systemd
│ └── dev.sh # 本地开发启动
├── templates/ # Jinja2 模板
│ ├── base.html # 布局 + 导航
│ ├── login.html
│ ├── dashboard.html
│ ├── tenants.html / tenant_form.html
│ ├── clients.html / client_form.html
│ ├── proxies.html / proxy_form.html
│ ├── users.html / user_form.html
│ ├── logs.html
│ ├── change_password.html
│ └── error.html
├── static/
│ └── style.css # 全部样式
├── instance/ # SQLite DB + server token(运行时生成)
│ ├── frps_manager.db
│ └── server_token # 0600 权限,仅 root 可读
└── runtime/ # 运行时数据
├── bin/frps # frps 二进制(deploy.sh 自动下载)
├── conf/frps.ini # 由 app.py 生成的 frps 配置
├── logs/ # gunicorn / frps 日志
├── frps.service # frps systemd 单元
├── frps-manager.service # web systemd 单元
└── frpc@.service # 用户给 frpc 主机用的模板
```
## 安装
### 一键部署(推荐)
```bash
git clone <repo-url> /opt/frps-manager
cd /opt/frps-manager
sudo bash scripts/deploy.sh
```
部署脚本会自动:
1. 安装系统依赖(python3, pip, venv, curl
2. 下载 frp 0.70.1 二进制到 `runtime/bin/frps`
3. 创建 venv 并安装依赖
4. 初始化 SQLite(默认管理员 `admin / admin`,默认租户 `default`
5. 生成 `frps.ini`(含自动生成的 server token
6. **动态生成** systemd 服务文件并启动:
- `frps.service` — 监听 0.0.0.0:7000dashboard 在 127.0.0.1:7500
- `frps-manager.service` — Web UI 在 0.0.0.0:5390
- `frpc@.service` — 客户端模板(客户端主机部署用)
> systemd unit 文件由 `deploy.sh` 根据项目实际路径自动生成到 `/etc/systemd/system/`
> 所以项目装到任意目录都能正常工作。
启动后访问 `http://<host>:5390`,用 `admin / admin` 登录,**立刻去「改密」改掉默认密码**。
### 本地开发
```bash
cd frps-manager
bash scripts/dev.sh
# 浏览器打开 http://localhost:5390
```
## 多租户使用流程
1. **管理员**登录 → 创建 **租户**(带带宽/连接配额元数据,文档用)
2. 创建 **普通用户**(绑定到该租户,role = user
3. 租户用户登录 → 创建 **frpc 客户端**(分配名称 + 租户)
4. 在该客户端下添加 **代理规则**(类型、远端端口/域名、本地端口、加密/压缩/健康检查…)
5. 点客户端列表的「frpc.ini」下载配置(包含所有代理 + 共享 server token + admin API
6.`frpc.ini` 拷贝到 frpc 主机,启动 frpc
7. **改代理后**:用户拉到新 frpc.ini 后在 frpc 主机执行 `frpc reload -c /etc/frpc.ini`frpc 自动应用新配置(dashboard 立刻显示新代理在线)
## frpc 配置示例
Web 生成的 frpc.ini
```ini
# Generated by frps-manager for client: laptop-jdoe
[common]
server_addr = your.frps.host
server_port = 7000
authentication_method = token
token = AbCdEf123456... # 与所有 frpc 共用的 server token
admin_addr = 127.0.0.1
admin_port = 7400
admin_user = admin
admin_pwd = admin # 用于 `frpc reload` 命令
[laptop-jdoe_ssh]
type = tcp
local_ip = 127.0.0.1
local_port = 22
remote_port = 6001
use_encryption = true
[laptop-jdoe_web]
type = http
local_ip = 127.0.0.1
local_port = 8080
custom_domains = web.example.com
```
存到 frpc 主机 `/etc/frpc/laptop-jdoe.ini`,然后用模板 unit
```bash
sudo cp /path/to/frps-manager/runtime/frpc@.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable --now frpc@laptop-jdoe
```
改代理后:
```bash
# 在 frpc 主机执行
sudo frpc reload -c /etc/frpc/laptop-jdoe.ini
# 或者 frpc reload -c /etc/frpc.ini(按你保存的路径)
```
## 客户端(frpc)部署教程
### 1. 下载 frpc 二进制
frpc 和 frps 来自同一个 frp 发行包。在 frpc 主机上执行:
```bash
# 查看架构
uname -m
# x86_64 → amd64
# aarch64 → arm64
# armv7l → arm
# 下载(以 amd64 为例,版本与服务器 frps 保持一致:0.70.1
cd /tmp
curl -fSL -o frp.tar.gz \
https://github.com/fatedier/frp/releases/download/v0.70.1/frp_0.70.1_linux_amd64.tar.gz
tar xzf frp.tar.gz
sudo cp frp_0.70.1_linux_amd64/frpc /usr/local/bin/
sudo chmod +x /usr/local/bin/frpc
frpc --version
# 应输出 0.70.1
```
其他架构替换 `amd64``arm64``arm` 等。
### 2. 从 Web 管理界面下载 frpc.ini
1. 登录 http://frps-manager-host:5390
2. 进入「客户端」页面 → 找到你的客户端 → 点「frpc.ini」按钮下载
3. 如果需要额外添加代理规则:在 Web 端「代理」页添加 → 再次下载 frpc.ini
### 3. 安装配置文件
```bash
sudo mkdir -p /etc/frpc
sudo cp ~/Downloads/frpc-laptop-jdoe.ini /etc/frpc/laptop-jdoe.ini
sudo chmod 600 /etc/frpc/laptop-jdoe.ini
```
配置文件包含:
- `server_addr` / `server_port` — frps 服务器地址
- `token` — 共享认证 token(由管理员提供,不要外泄)
- `admin_addr` / `admin_port` — 本地管理 API(用于 `frpc reload`
-`[[proxies]]` 段 — 代理规则
> 如果不想用 systemd,也可以直接运行测试:
> ```bash
> frpc -c /etc/frpc/laptop-jdoe.ini
> # 看到 "login to server success" 表示连接成功
> # Ctrl+C 停止
> ```
### 4. 安装 systemd 服务
方法一:从 frps-manager 主机拷贝(`deploy.sh` 已自动生成):
```bash
scp root@frps-host:/etc/systemd/system/frpc@.service /etc/systemd/system/
```
方法二:手动创建 `/etc/systemd/system/frpc@.service`(内容如下):
```ini
[Unit]
Description=frpc — fatedier/frp client (%i)
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
ExecStart=/usr/local/bin/frpc -c /etc/frpc/%i.ini
Restart=on-failure
RestartSec=5
LimitNOFILE=65536
[Install]
WantedBy=multi-user.target
```
安装并启动(`%i` 对应 `/etc/frpc/` 下的文件名,不含 `.ini`):
```bash
sudo systemctl daemon-reload
sudo systemctl enable --now frpc@laptop-jdoe
```
### 5. 验证连接
```bash
# 查看服务状态
sudo systemctl status frpc@laptop-jdoe
# 看到以下关键日志表示成功:
# login to server success, get run id [xxxxx]
# proxy added: [ssh web]
# start proxy success
# 查看实时日志
sudo journalctl -u frpc@laptop-jdoe -f
```
回到 frps-manager Web 仪表盘 → 客户端列表里应显示「在线」状态,代理列表里对应代理应为绿色「在线」。
### 6. 修改代理后热重载
在 Web 端添加/修改/删除代理规则后:
1. 回到「客户端」页 → 重新下载最新的 `frpc.ini`
2. 在 frpc 主机上替换配置文件并 reload:
```bash
sudo cp ~/Downloads/frpc-laptop-jdoe.ini /etc/frpc/laptop-jdoe.ini
sudo frpc reload -c /etc/frpc/laptop-jdoe.ini
# 看到 "reload success" 表示生效
# 无需重启 frpc 进程,已有的连接不受影响
```
> frpc.ini 中的 `admin_addr` / `admin_port` 段就是为 reload 准备的。
> 如果你的 frpc 主机上运行了多个 frpc 实例,每个实例的 `admin_port` 必须不同。
### 7. 多实例场景
同一台主机跑多个 frpc 客户端(例如多个用户共享一台服务器):
```bash
# 用户 A 的配置
sudo cp frpc-alice.ini /etc/frpc/alice.ini
# 用户 B 的配置(注意 admin_port 不同)
sudo cp frpc-bob.ini /etc/frpc/bob.ini
sudo systemctl enable --now frpc@alice
sudo systemctl enable --now frpc@bob
# 分别 reload
sudo frpc reload -c /etc/frpc/alice.ini
sudo frpc reload -c /etc/frpc/bob.ini
```
### 8. 故障排查
| 现象 | 原因 | 解决 |
|------|------|------|
| `token in login doesn't match` | token 错误或过期 | 重新从 Web 下载 frpc.ini |
| `type [http] not supported when vhost http port is not set` | frps 未配 vhost 端口 | 联系管理员设置 `FRPS_VHOST_HTTP_PORT` |
| `listen tcp :7400: bind: address already in use` | admin 端口冲突 | 改 frpc.ini 里的 `admin_port` |
| `connection refused` | frps 未启动或防火墙 | 检查 `telnet frps-host 7000` |
| Web 显示「离线」但 frpc 在跑 | frps dashboard 未同步 | 检查 frps dashboard (`:7500`) 是否可达 |
| `reload success` 但代理没生效 | frpc.ini 里没写对应 proxy 段 | 重新从 Web 下载最新 frpc.ini |
## 配置(环境变量)
| 变量 | 默认值 | 说明 |
|------|--------|------|
| `FLASK_SECRET` | 随机 | Flask session 密钥(生产必须设置一个长随机串) |
| `FRPS_BIN` | `runtime/bin/frps` | frps 可执行文件路径 |
| `FRPS_CONFIG` | `runtime/conf/frps.ini` | frps.ini 路径 |
| `FRPS_SERVICE` | `frps` | systemd 单元名(不含 .service |
| `FRPS_DASHBOARD_URL` | `http://127.0.0.1:7500` | frps dashboard URL |
| `FRPS_DASHBOARD_USER` | `admin` | dashboard 用户名 |
| `FRPS_DASHBOARD_PASS` | `admin123` | dashboard 密码 |
| `FRPS_BIND_PORT` | `7000` | frps 监听端口 |
| `FRPS_WEB_ADDR` | `127.0.0.1` | dashboard 监听地址 |
| `FRPS_WEB_PORT` | `7500` | dashboard 端口 |
| `FRPS_VHOST_HTTP_PORT` | `80` | http 虚拟主机端口 |
| `FRPS_VHOST_HTTPS_PORT` | `443` | https 虚拟主机端口 |
| `FRPC_ADMIN_ADDR` | `127.0.0.1` | 写入 frpc.ini 的 admin API 地址 |
| `FRPC_ADMIN_PORT` | `7400` | 写入 frpc.ini 的 admin API 端口(每台 frpc 主机必须唯一) |
| `FRPC_ADMIN_USER` | `admin` | 写入 frpc.ini 的 admin 用户名 |
| `FRPC_ADMIN_PWD` | `admin` | 写入 frpc.ini 的 admin 密码 |
## 安全建议
- 改默认 admin 密码
- dashboard7500)只在 127.0.0.1 监听 — 如果要让远程看 dashboard,把它放到 nginx 反向代理后面 + HTTPS
- Web UI5390)同理,建议放到 nginx + HTTPS 后
- 不要把 frps 暴露到公网 0.0.0.0:7000 而不设防火墙 — **每个 frpc 用同一个 server token**,谁拿到 token 都能连
- 如果需要更强的隔离,部署多个 frps 实例在不同端口,每个 frps 一个 server token
- `instance/server_token` 包含所有 frpc 的共享密钥,备份时加密
## 已知限制
- frps 0.70.1 INI 格式被官方 deprecation warning — 升级到 0.71+ 后只需把 `render_frps_ini` 改为 TOML
- frpc 0.70.1 也用 INIfrpc 端 INI 一直支持到最新版本,不受影响)
- Web UI 不支持批量操作(一次性添加多个代理)
- 没有内嵌 traffic chart;如需图表请用 Prometheus + frps 自带的 `/metrics` 端点
## License
MIT