nex_docus/docs/deploy/README.md

11 KiB
Raw Blame History

部署指南(Docker Compose)

本地开发请用 ./scripts/start.sh,不要用本文流程。 本文所有命令都在仓库根目录执行;部署脚本已迁到 scripts/,写法固定为 ./scripts/deploy.sh …。

1. 运行拓扑

docker-compose.yml 定义 4 个服务,容器名前缀 nex-docus-,基础镜像走华为云 SWR 镜像站(国内直连可用):

服务 容器 端口(宿主机→容器) 说明
mysql nex-docus-mysql ${MYSQL_PORT:-3306} → 3306 MySQL 8.0,utf8mb4 / utf8mb4_unicode_ci,数据在 ${STORAGE_PATH}/mysql
redis nex-docus-redis ${REDIS_PORT:-6379} → 6379 Redis 7,requirepass + AOF,数据在 ${STORAGE_PATH}/redis
backend nex-docus-backend ${BACKEND_PORT:-8000} → 8000 由 backend/Dockerfile 构建;启动命令 python scripts/init_db.py && uvicorn main:app …,即建表/迁移/种子全自动
frontend nex-docus-frontend ${FRONTEND_PORT:-8080} → 80 由 frontend/Dockerfile 构建(node 构建 + nginx 托管),nginx 反代 /api/、/mcp 到后端
  • 网络:nex-docus-network;后端在容器内的上游主机名是 backend,前端 nginx 依赖该名字。
  • 文件存储:宿主机 ${STORAGE_PATH} 挂到后端 /data/nex_docus_store(后端配置里的 STORAGE_ROOT)。文档正文、向量索引、搜索索引、PDF 缓存都在这里。
  • ⚠️ compose 里的相对路径按执行 compose 的当前目录解析,建议 .env 中把 STORAGE_PATH 写成绝对路径(如 /data/nexdocus/storage),避免换目录执行时数据"凭空消失"。

2. 前置要求

  • Docker 20.10+,Docker Compose v2(docker compose;脚本也兼容老 docker-compose)
  • 磁盘 ≥ 15 GB 空闲(后端镜像要装 PyTorch / weasyprint / zvec,镜像本身 + 向量索引 + 文档存储增长都吃磁盘)
  • 内存 ≥ 4 GB(若启用本地 Embedding sentence-transformers,建议 8 GB)
  • 出站网络可达所选 LLM / Embedding 服务

3. 配置 .env

cp .env.example .env
$EDITOR .env
键 默认值 说明
MYSQL_ROOT_PASSWORD root_password_change_me 必改
DB_NAME / DB_USER / DB_PASSWORD nex_docus / nexdocus / password_change_me 应用库与账号;必改密码
MYSQL_PORT 3306 宿主机端口;不需要外部访问时建议改成 127.0.0.1:3306 或干脆不映射
REDIS_PASSWORD / REDIS_PORT / REDIS_DB redis_password_change_me / 6379 / 8 必改密码
SECRET_KEY 占位串 必改:openssl rand -hex 32。改了会让已登录用户全部失效
DEBUG false 保持 false(true 会打印全量 SQL)
BACKEND_PORT / FRONTEND_PORT 8000 / 8080 对外端口;用户访问的是 FRONTEND_PORT
STORAGE_PATH ./storage 持久化根目录,建议绝对路径;MySQL/Redis 数据也放这里
CHUNK_SIZE / CHUNK_OVERLAP 800 / 150 RAG 分块策略,改动后需重新向量化才生效
ADMIN_USERNAME / ADMIN_PASSWORD / ADMIN_EMAIL / ADMIN_NICKNAME admin / Admin@123456 / admin@example.com / 系统管理员 只在第一次建库时生效,账号已存在则不会改密码
DEFAULT_USER_PASSWORD User@123456 管理员在「系统管理 → 用户管理」新建用户时的初始密码;建议改随机值,否则后端启动会打 [安全自检] 告警
DISABLE_SSL_VERIFY false 仅自签名证书的内部模型服务才开
ZVEC_DATA_DIR 空 留空即 ${STORAGE_ROOT}/vector_index
ZVEC_EMBEDDING_DIM 1536 必须与选定的 embedding 模型维度一致,换模型要重建索引

前端没有 API 地址配置项:容器内 nginx 固定把 /api/ 反代到 backend:8000。跨域直连后端需自行改 frontend/nginx.conf。 这套 .env(部署用)与 backend/.env(开发用,键名不同)是两套配置,容器里只认前者。

4. 首次部署

./scripts/deploy.sh init

依次执行:.env 检查(没有就从 .env.example 生成并中止,等你填)→ Docker 检查 → pull → build --no-cache → 起 mysql/redis → 等 15s → run --rm backend python scripts/init_db.py → up -d → 打印访问信息。

等价的手工流程:

docker compose pull
docker compose build
docker compose up -d mysql redis
until docker compose exec -T mysql mysqladmin ping -hlocalhost -uroot -p"$MYSQL_ROOT_PASSWORD" --silent; do sleep 2; done
docker compose run --rm backend python scripts/init_db.py
docker compose up -d
docker compose ps

验证:

curl -fsS http://127.0.0.1:8000/health            # {"status":"healthy"}
docker compose ps                                  # 4 个服务 healthy/running
open http://<服务器IP>:8080                        # 登录页;默认 admin / .env 里的 ADMIN_PASSWORD

5. 日常运维

命令 作用
./scripts/deploy.sh start / stop / restart 起停服务
./scripts/deploy.sh status 容器状态
./scripts/deploy.sh logs 跟踪全部日志
./scripts/deploy.sh logs backend 跟踪单个服务(mysql / redis / backend / frontend)
./scripts/deploy.sh upgrade 升级:交互确认 → git pull → 停前后端 → build --no-cache → 跑 init_db.py(自动补列/种子) → up -d → docker image prune -f
./scripts/deploy.sh backup mysqldump 应用库到 ./backups/nex_docus_<时间戳>.sql
./scripts/deploy.sh restore <文件> 覆盖式恢复数据库(需输入 yes)
./scripts/deploy.sh uninstall 删除容器/网络/本地构建镜像;不会删除 STORAGE_PATH 数据

upgrade 会执行 git pull:如果服务器上有本地改动或未切换分支,请先自行处理。

6. 备份与恢复

文档正文在文件系统、权限在数据库,两者必须一起备份,单独还原任何一侧都不算恢复。

# 备份
./scripts/deploy.sh backup                                   # 数据库
tar czf nexdocus_storage_$(date +%F).tar.gz -C "$STORAGE_PATH" .   # 文件 + 索引 + MySQL/Redis 数据

# 恢复(先起 mysql/redis,再灌数据,最后起应用)
docker compose up -d mysql redis
./scripts/deploy.sh restore backups/nex_docus_20260930_120000.sql
docker compose up -d backend frontend

迁移到新机器:拷贝 storage 目录 + SQL 备份 + .env,新机 STORAGE_PATH 指到新目录,恢复 SQL 后直接 up -d。项目的磁盘目录名是 projects.storage_key(UUID),与项目名解耦,可以整目录搬迁。

定期备份建议交给系统 cron 或备份软件,注意 backups/ 也在 .gitignore 内,别提交到仓库。

7. 反向代理与 HTTPS

前端容器只监听 80。生产建议前置一层网关做 TLS 与域名:

server {
    listen 443 ssl http2;
    server_name docs.example.com;

    ssl_certificate     /etc/ssl/fullchain.pem;
    ssl_certificate_key /etc/ssl/privkey.pem;

    client_max_body_size 100M;          # 附件上传

    location / {
        proxy_pass http://127.0.0.1:8080;
        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_http_version 1.1;
        proxy_set_header Upgrade $http_kind;
        proxy_set_header Connection "upgrade";
    }
}

要点:

  • 前端容器内的 nginx 已对 /api/v1/chat/send/stream(SSE)与 /mcp 关闭缓冲并放大超时;外层网关若另有 location 命中这两条路径,也要关闭 proxy_buffering,否则 AI 对话会"卡住不出字"。
  • map $http_upgrade $http_kind { default upgrade; '' close; } 放在 http {} 中(示例已简化)。
  • 上传大小限制要逐层一致(示例 100M)。

8. 上线前安全清单

  • MYSQL_ROOT_PASSWORD / DB_PASSWORD / REDIS_PASSWORD / SECRET_KEY 全部改掉默认值
  • ADMIN_PASSWORD / DEFAULT_USER_PASSWORD 改为随机值;启动后 docker compose logs backend | grep 安全自检 应无输出(有输出说明仍在用仓库默认值)
  • 首次登录后修改 admin 密码;删除或禁用演示账号
  • MySQL / Redis 端口不对公网开放(安全组或改绑 127.0.0.1)
  • DEBUG=false
  • TLS 前置,HTTP 跳转 HTTPS
  • STORAGE_PATH 与数据库备份纳入例行备份(数据库里含 Git Token、模型 API Key、分享密码明文)
  • 磁盘监控:Redis 落盘失败会让整站变只读(见下)

9. 常见问题

现象 原因 / 处理
前端 502 / 一直转圈 后端还没通过 /health(首次 init_db.py 需要时间)。./scripts/deploy.sh logs backend 观察
backend 反复重启,日志 MISCONF ... RDB snapshot Redis 服务端落盘失败并拒绝写入 → 磁盘满或目录权限问题。清磁盘后 redis-cli CONFIG SET stop-writes-on-bgsave-error no 只是临时解封,重启 Redis 会复原,必须根治磁盘
Access denied for user .env 与实际库账号不一致;改过 DB_PASSWORD 后已初始化的 MySQL 不会自动同步,需要进容器 ALTER USER 或删库重建
换机器后项目列表空了 STORAGE_PATH 用了相对路径,数据实际写在别的目录
改了 ADMIN_PASSWORD 但登录仍是旧密码 管理员已存在,init_db.py 不会重置密码;在「系统管理 → 用户管理」里改
AI 对话无引用 / 报维度不匹配 Embedding 模型或 ZVEC_EMBEDDING_DIM 变过 → 重新向量化项目(项目页触发全量)
PDF 导出中文乱码 后端镜像已内置 fonts-wqy-microhei;若自定义基础镜像请自带中文字体
docker compose 提示 version 已废弃 已从 docker-compose.yml 移除该字段;若用老 docker-compose v1,建议升级到 Compose v2

10. 本版验证边界

  • ✅ 已验证:./scripts/deploy.sh 的参数路由与脚本语法、Compose 文件解析、后端镜像构建步骤文本与启动命令。
  • ❌ 未在本轮做端到端 docker compose up 实测(缺少可用 Docker 环境)。首个正式部署请把它当作演练:init → status → /health → 登录 → 建项目 → 上传 → AI 问答 → 备份,并把结果登记到 sdd/releases/v1.0.0.md 的验证边界。
  • ⚠️ frontend/Dockerfile 目前 rm -rf package-lock.json && npm install(历史原因是 Alpine 下 rollup 可选依赖问题),构建不保证可重现;确认网络环境稳定后建议改回 npm ci。