PDF 用户侧 UI 改由 zMainPage 的 zPDF_package 组件提供(构建期 import,非 iframe), zTools2 仅保留 /api/pdf/* REST API 与 /api/pdf-admin 管理页。cookie 认证不受影响: zk_pdf 仍在首次 POST /api/pdf/jobs 时种下,与已删的 /api/pdf 页面路由无关。 - app/main.py:删除 GET /api/pdf 页面路由(pdf_page) - static/pdf.html、static/pdf.js、static/pdf.css:删除用户页 HTML/JS/CSS (功能已被 zPDF_package 的 App.vue/Uploader.vue/JobList.vue 取代) - static/pdf_admin.css:合并原 pdf.css 中管理页依赖的样式,成为自包含样式表 - static/pdf_admin.html:移除指向已删 /api/pdf 的页脚死链与 pdf.css 引用 - README.md:功能一览/访问入口表去 /api/pdf 用户页条目,路由约定去 iframe 表述
zikai file service
基于 FastAPI 的个人 Web 服务,提供文件上传/浏览/下载、共享记事本(实时协作)、 主机监控、SFTP 暂存、反向隧道、PDF 转换。采用 Spring 风格分层架构,自带 API 文档。
功能一览
| 模块 | 页面 / 接口 | 鉴权 |
|---|---|---|
| 文件上传 | POST /api/files/upload(流式)/ POST /api/files/chunk-uploads/*(分片+断点续传) |
公开 |
| 上传页 | GET /api/upload(拖拽/多文件/分片/去重) |
公开 |
| 文件浏览 | GET /api/files-page(多选/批量下载删除/分页) |
Basic Auth |
| 文件管理 API | GET /api/admin/files、GET/DELETE /api/admin/files/{id}、GET /api/admin/files/{id}/download |
Basic Auth |
| 共享记事本 | GET /api/wb-page/{id}(公开,不存在则新建) |
公开 |
| 记事本实时同步 | WS /api/ws/wb/{id}(心跳 3s,5 次失活移除) |
公开 |
| 记事本管理 | GET /api/wb-admin(查看/删除) |
Basic Auth |
| 记事本管理 API | GET /api/admin/wb、DELETE /api/admin/wb/{id} |
Basic Auth |
| PDF 转换 API | POST /api/pdf/jobs、GET /api/pdf/jobs[/{id}]、GET /api/pdf/jobs/{id}/download、DELETE /api/pdf/jobs/{id} |
公开(cookie) |
| PDF 转换管理 | GET /api/pdf-admin(全部任务,含已软删标记,硬删) |
Basic Auth |
| PDF 转换管理 API | GET /api/admin/pdf/jobs、DELETE /api/admin/pdf/jobs/{id} |
Basic Auth |
| 主机监控 | GET /api/system/status(CPU/内存/磁盘,HTML+JSON 内容协商) |
公开 |
| 反向隧道反代 | ALL /api/userPort/{userName}(经 SSH 隧道转发到 user 本地服务) |
公开 |
| SFTP/SSH | 端口 2022(密码+公钥,chroot 到上传目录,承载隧道转发) | SSH |
| API 文档 | GET /docs(Swagger)/ GET /redoc |
Basic Auth |
路由约定
所有 zTools2 托管的入口(页面 / 静态资源 / 健康探针 / WebSocket / REST API)统一挂在 /api/ 前缀下,只有元信息/文档例外(/、/docs、/redoc、/openapi.json)。这样反向代理与 vite dev proxy 都只需一条 /api/ 规则即可把请求转给当前环境的 zTools2,前端用同源相对路径(如 /api/pdf/jobs、/api/health)即可,与运行环境(本地 / 测试 / 生产)无关,无需区分 dev/prod 指向。
PDF 转换的用户侧 UI 由 zMainPage 的 zPDF_package 组件提供(构建期 import,非 iframe);zTools2 仅提供
/api/pdf/jobs等 REST API 与/api/pdf-admin管理页。
页面类入口为避免与同名 REST API 冲突,统一加 -page 后缀:
| 类型 | 页面入口 | REST API(同名不加后缀) |
|---|---|---|
| 文件浏览 | GET /api/files-page |
GET /api/files、/api/files/{id} 等 |
| 记事本 | GET /api/wb-page/{id} |
GET /api/wb/{id} |
其余入口:/api/health(探针)、/api/static/*(JS/CSS)、/api/ws/wb/{id}(WebSocket)、/api/upload、/api/pdf-admin、/api/wb-admin。
项目结构
server/
├── app/
│ ├── main.py # FastAPI 应用工厂、路由注册、生命周期(reaper)
│ ├── config.py # 从 config.yaml 加载的类型化 Settings(pydantic-settings)
│ ├── database.py # SQLAlchemy 引擎/Session/Base/get_db 依赖
│ ├── security.py # Basic Auth(require_docs_auth,常量时间比较)
│ ├── controllers/ # 路由层(@RestController):file/system/chunk/tunnel/whiteboard/pdf/admin
│ ├── services/ # 业务层:UploadService/ChunkUploadService/SystemService/
│ │ # WhiteboardService/WhiteboardHub/TunnelService/sftp_server
│ │ # PdfService(转换编排)+ pdf_converter(epub->pdf 纯 Python)
│ ├── dao/ # 数据访问层:唯一发 SQL 的层(SQLAlchemy ORM 参数化)
│ ├── models/ # ORM 实体:UploadedFile/UploadSession/Whiteboard/TunnelSession/PdfJob
│ ├── schemas/ # pydantic 请求/响应 DTO
│ ├── views/ # 服务端渲染 HTML(系统状态页、上传页)
│ ├── static/ # 前端静态资源(common + file_browser + whiteboard + pdf + pdf_admin)
│ └── scripts/init_db.py # 数据库初始化(建库建账、随机密码写回 config.yaml)
├── sql/schema.sql # 建表 DDL(参考;实际由 ORM 自动建表)
├── config.example.yaml # 配置模板(含注释)
├── config.yaml # 实际配置(git-ignored,含密码)
├── requirements.txt
├── setup.sh # 一次性初始化:venv + 依赖 + 建库 + SFTP 密钥
├── start.sh / stop.sh # 启停 HTTP(6867)+ SFTP(2022)
└── logs/ # app.log / sftp.log
请求流程:controller → service → dao → ORM model → MySQL。
DB Session 由 get_db 依赖注入。前端页面走「StaticFiles 挂载 + 具名 HTML 路由」前后端分离,JS 调同源 /api/...。
从零安装(Ubuntu 22.04+)
1. 安装系统依赖
apt update
apt install -y python3-venv python3-pip mysql-server apache2 \
libssl-dev build-essential # build-essential 给 bcrypt/asyncssh 编译
# PDF 转换依赖 weasyprint,需 pango/cairo 系统库(Ubuntu 通常已随桌面环境安装,缺则补装):
apt install -y libpango-1.0-0 libpangoft2-1.0-0 libcairo2 libgdk-pixbuf-2.0-0
2. 获取代码
git clone <repo> /root/zikai
cd /root/zikai/server
3. 初始化(venv + 依赖 + 建库 + SFTP 密钥)
./setup.sh
setup.sh 会:
- 创建
.venv并安装requirements.txt - 复制
config.example.yaml → config.yaml(若不存在) - 通过本机 root socket 建独立 MySQL 库
zikai_filesvc+ 应用账户,随机密码写回config.yaml - 生成 SFTP 主机密钥(
keys/ssh_host_*)
4. 配置凭据
编辑 config.yaml(见下方配置说明):
docs.username/docs.password:管理页与 API 文档的 Basic Auth 凭据sftp.users[].password_hash:SFTP 用户(bcrypt,生成方式见下)tunnel.users[]:反向隧道用户(可选)
# 生成 bcrypt hash
.venv/bin/python -c "import bcrypt;print(bcrypt.hashpw(b'yourpass',bcrypt.gensalt()).decode())"
5. 启动
./start.sh # 启动 HTTP(127.0.0.1:6867) + SFTP(0.0.0.0:2022)
./stop.sh # 停止
6. 配置 Apache 反向代理
服务只绑 127.0.0.1:6867,通过 Apache 对外提供 HTTPS。安装模块并配置 vhost:
a2enmod ssl proxy proxy_http proxy_wstunnel rewrite headers
创建 /etc/apache2/sites-available/f.zikai.wang.conf(关键部分):
<VirtualHost *:443>
ServerName f.zikai.wang
SSLEngine on
SSLCertificateFile /etc/letsencrypt/live/f.zikai.wang/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/f.zikai.wang/privkey.pem
ProxyPreserveHost On
ProxyPass /fdata !
# 所有 zTools2 入口(页面/静态/探针/WS/API)统一在 /api/ 下,一条规则即可;
# WebSocket 走 /api/ws/wb/{id},靠 proxy_wstunnel 透传 Upgrade 头
ProxyPass /api/ http://127.0.0.1:6867/api/
ProxyPassReverse /api/ http://127.0.0.1:6867/api/
ProxyTimeout 300
</VirtualHost>
a2ensite f.zikai.wang
systemctl reload apache2
防火墙:放开 443(HTTPS)与 2022(SFTP)。6867 不对外(仅 loopback)。 大文件上传:Apache 全局
Timeout 300,慢链路建议走分片上传(/api/upload)或 SFTP。
配置说明
所有运行时配置在 config.yaml(git-ignored)。完整 schema 见 config.example.yaml。
| 段 | 关键项 | 说明 |
|---|---|---|
server |
host/port |
绑定地址,保持 127.0.0.1:6867(Apache 反代) |
database |
host/port/user/password/database |
MySQL 连接;密码由 setup.sh 自动生成写回 |
storage |
upload_dir |
文件存储根目录(默认 uploads) |
chunk_bytes |
流式上传分片大小(默认 1 MiB) | |
chunk_session_dir |
分片会话暂存目录(默认 uploads/.work) |
|
chunk_session_ttl_seconds |
被放弃会话存活秒数(默认 300) | |
docs |
username/password |
/docs、/api/files-page、/api/wb-admin、/api/pdf-admin 及 /api/admin/* 的 Basic Auth(明文,常量时间比较) |
sftp |
enabled/host/port |
SFTP 服务,默认 0.0.0.0:2022 |
users[].username/password_hash |
SFTP 用户(bcrypt) | |
host_key_path/authorized_keys_path |
主机密钥与公钥白名单路径 | |
tunnel |
enabled/users[] |
反向隧道:username/password_hash/tunnel_port/local_port |
whiteboard |
heartbeat_interval_seconds |
心跳间隔(默认 3s) |
heartbeat_miss_threshold |
失活阈值(默认 5 次 = 15s) | |
max_board_id_length |
board_id 长度上限(默认 64) | |
max_connections_per_board |
单白板并发连接上限(默认 50) | |
list_limit |
管理页单次列表上限(默认 100) |
访问入口
| 入口 | URL |
|---|---|
| API 文档 | https://f.zikai.wang/docs(Basic Auth) |
| 上传页 | https://f.zikai.wang/api/upload |
| 文件浏览 | https://f.zikai.wang/api/files-page(Basic Auth) |
| 共享记事本 | https://f.zikai.wang/api/wb-page/{id}(公开,{id} 为 [a-zA-Z0-9_-]{1,64}) |
| 记事本管理 | https://f.zikai.wang/api/wb-admin(Basic Auth) |
| PDF 转换 | 经 zMainPage 的 PDF 页签(zPDF_package 组件)调用 /api/pdf/jobs 等 REST API(公开,凭 cookie) |
| 系统状态 | https://f.zikai.wang/api/system/status(HTML,?format=json 切 JSON) |
| curl 上传 | curl -F file=@big.iso https://f.zikai.wang/api/files/upload |
| SFTP | sftp -P 2022 uploader@f.zikai.wang |
运维
- 日志:
logs/app.log(HTTP)、logs/sftp.log(SFTP);pidfile:app.pid、sftp.pid。 - 临时文件清理:分片上传完成后立即删
.work/<id>/;被放弃会话(pending超 5 分钟)由后台 reaper 每 60s 清理;start.sh启动时兜底清残留。 - 重新生成 DB 密码:
.venv/bin/python -m app.scripts.init_db(保留现有:KEEP_DB_PASSWORD=1)。 - 多 worker 限制:记事本 hub 是进程内存,多 uvicorn worker 下不互通,保持
workers: 1。 - 数据库表:ORM 启动时自动建表(
init_db_schema);sql/schema.sql供参考/手动初始化。
持久化部署(systemd)
./start.sh 适合手动运维;生产推荐用 systemd 管理实现开机自启 + 崩溃自动重启:
./deploy/install-systemd.sh # 安装并启动 ztools2 服务(开机自启)
systemctl status ztools2 # 状态
journalctl -u ztools2 -f # 日志
sudo systemctl restart ztools2 # 重启(更新代码后)
脚本自动检测 .venv/bin/uvicorn 或系统 uvicorn,用实际路径填充 deploy/ztools2.service 模板。卸载:systemctl disable --now ztools2 && rm /etc/systemd/system/ztools2.service && systemctl daemon-reload。
与 zMainPage 整体部署配合:systemd 管后端,
zMainPage/deploy.sh --no-restart部署前端。详见 zMainPage 的docs/deployment.md。