DOCAT Ubuntu 22.04 安装部署指南(nginx + systemd 实测)

在 Ubuntu 22.04 上按官方源码路径部署 DOCAT 1.6.1:Python venv 后端 + Node 构建前端 + systemd 服务化 + nginx 反代(端口 8143),含 MkDocs 文档上传全链路验证、4 个排障实录与 k8s 路径说明,全部命令与回显真机实测。

DOCAT文档托管Ubuntu22.042026/10/28

DOCAT Ubuntu 22.04 安装部署指南(nginx + systemd 实测)

本文在 Ubuntu 22.04 服务器上按官方源码路径完整部署 DOCAT 1.6.1(官方最新稳定版,发布标签提交于 2026-09-10,查询日期 2026-10-28),部署形态为生产推荐形态:nginx 托管前端与文档静态文件 + uvicorn 常驻 API 服务(systemd 托管),Web 服务端口使用 8143。文中所有命令与回显均为真实服务器上的实测记录,可直接照抄执行。

环境基线与最终状态:

项值
操作系统Ubuntu 22.04(Python 3.10.12 系统自带)
DOCAT 版本1.6.1(源码标签安装,pip 包版本号显示 0.0.0 为上游 pyproject 占位,属正常现象)
关键依赖fastapi 0.162.0 / uvicorn 0.54.0 / tinydb 4.9.0 / python-magic 0.4.27 / python-multipart 0.0.32
前端构建Node v24.22.1 + yarn 1.22.22(仅构建期需要)
Web 端口8143(nginx 对外),127.0.0.1:5000(uvicorn,仅本机监听)
存储根目录/var/docat(属主 www-data)

相关阅读:《DOCAT 介绍与选型指南》、《DOCAT 配置参数详解》、《DOCAT 常用 CLI 命令详解》。

一、部署架构

DOCAT 官方源码自带 nginx 配置模板(仓库内 docat/nginx/default),其预期部署形态是:

浏览器 ──> nginx :8143
            ├── /            → /var/www/html        (前端 SPA 静态文件)
            ├── /doc/...     → /var/docat/doc/...   (上传的文档,静态文件直出)
            └── /api/...     → 127.0.0.1:5000       (uvicorn 运行的 FastAPI 后端)

需要提前准备的组件清单:

  1. nginx:托管前端产物、文档静态文件,并把 /api 反代到后端;
  2. Python 3.10+ 与 venv:运行后端 API;
  3. libmagic1:python-magic 的系统库依赖(项目图标上传时的文件类型识别依赖它,缺装会导致图标接口 500);
  4. Node.js 20.19+ 与 yarn:仅在构建前端阶段需要,构建完成后可卸载;
  5. unzip/zip:后端解包上传的 zip 需要(unzip 属 libmagic 之外的常规工具,zip 用于制作上传测试包)。

二、安装系统依赖

# apt-get update
# export DEBIAN_FRONTEND=noninteractive
# apt-get install -y python3.10 python3.10-venv python3-pip nginx libmagic1 git curl unzip zip

实测回显(节选):

Setting up python3.10-venv ...
Setting up nginx ...
Processing triggers for man-db ...

安装完成后验证:

# python3 --version
Python 3.10.12
# nginx -v
nginx version: nginx/1.18.0 (Ubuntu)

三、获取 DOCAT 1.6.1 源码

从官方仓库拉取 1.6.1 标签(服务器需可访问 github.com,国内网络可自行配置代理环境变量后执行):

# export https_proxy=http://<代理地址>:<端口>
# git clone --depth 1 --branch 1.6.1 https://github.com/docat-org/docat.git /opt/docat-src
# ls /opt/docat-src
CONTRIBUTING.md  Dockerfile  LICENSE  README.md  doc  docat  web

目录说明:docat/ 是 Python 后端(FastAPI 应用包),web/ 是 React 前端源码,doc/ 内含前端构建时需要嵌入的帮助页素材。

四、安装后端 API

用 venv 隔离安装后端(pip 会按官方 docat/pyproject.toml 自动解析依赖):

# python3 -m venv /opt/docat-venv
# /opt/docat-venv/bin/pip install /opt/docat-src/docat

安装完成后验证应用可导入:

# /opt/docat-venv/bin/python -c 'from docat.app import app; print("docat.app import OK")'
docat.app import OK
# /opt/docat-venv/bin/pip show docat | grep -E '^(Name|Version)'
Name: docat
Version: 0.0.0

版本号显示 0.0.0 是上游 pyproject.toml 中的占位写法(官方以 git 标签管理版本),不影响功能。

五、构建前端

前端是 React + Vite 工程,构建产物是纯静态文件。官方构建约定有两个必须遵守的细节(都在官方 Dockerfile 构建脚本中体现):

  1. 构建时注入环境变量 VITE_DOCAT_VERSION,前端页面底部会显示该版本号;
  2. 把仓库 doc/getting-started.md 拷贝到 web/src/assets/,前端帮助页直接引用该文件。
# apt-get install -y nodejs yarn    # 需 Node.js >= 20.19(本文实测 v24.22.1)
# cp -r /opt/docat-src/web /opt/web-build
# cp /opt/docat-src/doc/getting-started.md /opt/web-build/src/assets/
# cd /opt/web-build
# export VITE_DOCAT_VERSION=1.6.1
# yarn install --frozen-lockfile
# yarn build

yarn build 实测回显(节选):

yarn run v1.22.22
$ tsc && vite build
vite v8.2.2 building client environment for production...
transforming...
✓ 11752 modules transformed.
dist/assets/index-Bs-JyvES.css            32.12 kB │ gzip:   6.38 kB
dist/assets/index-BmH91sRv.js            771.38 kB │ gzip: 242.14 kB
✓ built in 519ms
Done in 2.15s.

把构建产物部署到 nginx 根目录:

# rm -rf /var/www/html/*
# cp -r /opt/web-build/dist/* /var/www/html/
# ls /var/www/html/
assets  favicon.ico  index.html

六、初始化存储目录

存储根目录默认约定为 /var/docat(可通过环境变量 DOCAT_STORAGE_PATH 调整,见 C 篇),API 进程以 www-data 身份运行,因此属主要提前设定:

# mkdir -p /var/docat
# chown -R www-data:www-data /var/docat

API 启动后会自动创建 doc/ 子目录(文档)与 db.json(元数据),无需手工建。

七、systemd 服务化 API 进程

创建单元文件 /etc/systemd/system/docat-api.service(全文如下,可直接照抄):

[Unit]
Description=docat API server (FastAPI/uvicorn)
After=network.target

[Service]
Type=simple
User=www-data
Group=www-data
WorkingDirectory=/opt/docat-src
Environment=DOCAT_STORAGE_PATH=/var/docat
ExecStart=/opt/docat-venv/bin/python -m uvicorn --host 127.0.0.1 --port 5000 docat.app:app
Restart=on-failure
RestartSec=3

[Install]
WantedBy=multi-user.target

要点说明:

  • --host 127.0.0.1:API 只监听本机回环,外部流量一律经 nginx,避免后端直接暴露;
  • DOCAT_STORAGE_PATH=/var/docat:显式声明存储根,与 nginx 的 /doc 静态目录指向一致;
  • WorkingDirectory 指向源码目录即可,应用通过 site-packages 导入,不依赖运行目录内的文件。

启用并启动:

# systemctl daemon-reload
# systemctl enable --now docat-api.service
Created symlink /etc/systemd/system/multi-user.target.wants/docat-api.service → /etc/systemd/system/docat-api.service.
# systemctl status docat-api --no-pager -n 3

实测回显:

● docat-api.service - docat API server (FastAPI/uvicorn)
     Loaded: loaded (/etc/systemd/system/docat-api.service; enabled; vendor preset: enabled)
     Active: active (running) since Wed 2026-10-28 05:12:34 UTC; 11min ago
   Main PID: 1076 (python)
      Tasks: 6 (limit: 2932)
     Memory: 42.0M
        CPU: 1.526s
     CGroup: /system.slice/docat-api.service
             └─1076 /opt/docat-venv/bin/python -m uvicorn --host 127.0.0.1 --port 5000 docat.app:app

Oct 28 05:23:43 docat-lab python[1076]: INFO:     127.0.0.1:38806 - "POST /api/getting-started/1.1.0 HTTP/1.0" 201 Created
Oct 28 05:23:43 docat-lab python[1076]: INFO:     127.0.0.1:38814 - "PUT /api/getting-started/1.1.0/tags/latest HTTP/1.0" 201 Created
Oct 28 05:23:43 docat-lab python[1076]: INFO:     127.0.0.1:38820 - "GET /api/projects/getting-started HTTP/1.0" 200 OK

API 进程常驻内存约 42 MB(上传若干文档后),资源占用非常轻。此时先做一次后端自检:

# curl -s http://127.0.0.1:5000/api/stats
{"n_projects":0,"n_versions":0,"storage":"0 bytes"}

八、nginx 站点配置

写入 /etc/nginx/sites-available/docat(内容基于官方模板 docat/nginx/default,把监听端口改为 8143,上传上限写为 100M):

upstream python_backend {
    server 127.0.0.1:5000;
}

server {
    listen 8143 default_server;
    listen [::]:8143 default_server;

    root /var/www/html;

    add_header Content-Security-Policy "frame-ancestors 'self';";
    index index.html index.htm index.pdf /index.html;

    server_name _;

    location /doc {
        root /var/docat;
        absolute_redirect off;
    }

    location /api {
        client_max_body_size 100M;
        proxy_pass http://python_backend;
    }

    location / {
        try_files $uri $uri/ /index.html =404;
    }
}

启用站点并启动 nginx(Debian/Ubuntu 系统自带默认站点需要移除,否则 8143 之外的默认监听会与之冲突):

# rm -f /etc/nginx/sites-enabled/default
# ln -sf /etc/nginx/sites-available/docat /etc/nginx/sites-enabled/docat
# nginx -t
nginx: the configuration file /etc/nginx/sites-enabled/docat syntax is ok
nginx: configuration file /etc/nginx/sites-enabled/docat test is successful
# systemctl restart nginx

验证端口监听:

# ss -ltn | grep -E '8143|5000'
LISTEN 0      2048       127.0.0.1:5000       0.0.0.0:*
LISTEN 0      511          0.0.0.0:8143       0.0.0.0:*
LISTEN 0      511             [::]:8143          [::]:*

排障实录 1:改完 nginx 配置后 /api 一直 404

现象:首页 200 正常,但 curl http://127.0.0.1:8143/api/stats 返回 nginx 的 HTML 404 页面,而不是后端 JSON。

定位过程:先排除后端问题——直连 uvicorn 正常:

# curl -s http://127.0.0.1:5000/api/stats
{"n_projects":0,"n_versions":0,"storage":"0 bytes"}

再核对磁盘上的站点配置与生效配置(nginx -T),两者完全一致、location /api 存在,说明不是配置文件写错。真正原因:apt 安装 nginx 时服务已自动启动(加载的是安装时的默认配置),随后用 systemctl enable --now nginx 启用时,服务已在运行、配置不会重新加载——enable --now 对已运行的服务不执行 restart/reload。

解决:

# systemctl restart nginx

重启后 /api 立即恢复正常。经验法则:修改站点配置后必须 restart 或 reload,enable --now 只保证"启动",不等于"重载"。

九、上传文档验证(全链路)

用 MkDocs 构建一份真实文档做端到端验证(MkDocs 只是文档生成器示例,任何能产出 index.html 的静态文档都可以):

# /opt/docat-venv/bin/pip install mkdocs
# mkdir -p /opt/demo-docs/docs
# cat > /opt/demo-docs/mkdocs.yml <<'EOF'
site_name: getting-started
theme: mkdocs
EOF
# cat > /opt/demo-docs/docs/index.md <<'EOF'
# Getting Started

Welcome to the demo documentation.

## Usage

This page is hosted by docat.
EOF
# cd /opt/demo-docs && /opt/docat-venv/bin/mkdocs build -d /tmp/site-v2
INFO    -  Documentation built in 0.03 seconds
# cd /tmp/site-v2 && zip -qr /tmp/getting-started-1.0.0.zip .
# ls -la /tmp/getting-started-1.0.0.zip
-rw-r--r-- 1 root root 856495 Oct 28 05:23 /tmp/getting-started-1.0.0.zip

9.1 上传两个版本并打 latest 标签

# curl -s -X POST -F 'file=@/tmp/getting-started-1.0.0.zip' http://127.0.0.1:8143/api/getting-started/1.0.0
{"message":"Documentation uploaded successfully"}
# curl -s -X POST -F 'file=@/tmp/getting-started-1.0.0.zip' http://127.0.0.1:8143/api/getting-started/1.1.0
{"message":"Documentation uploaded successfully"}
# curl -s -X PUT http://127.0.0.1:8143/api/getting-started/1.1.0/tags/latest
{"message":"Tag latest -> 1.1.0 successfully created"}

9.2 查询项目详情

# curl -s http://127.0.0.1:8143/api/projects/getting-started
{"name":"getting-started","storage":"3 MB","versions":[{"name":"1.1.0","timestamp":"2026-10-28T05:23:43.595218","tags":["latest"],"hidden":false},{"name":"1.0.0","timestamp":"2026-10-28T05:23:43.578687","tags":[],"hidden":false}]}

9.3 浏览器访问验证

  • 首页(项目列表):http://<服务器IP>:8143/ → 实测返回 HTTP 200;
  • 文档页:http://<服务器IP>:8143/doc/getting-started/latest/ → 实测返回 HTTP 200:
# curl -s -o /dev/null -w 'GET /doc/getting-started/latest/ => %{http_code}\n' http://127.0.0.1:8143/doc/getting-started/latest/
GET /doc/getting-started/latest/ => 200

9.4 磁盘布局(理解存储模型)

# ls -la /var/docat/doc/getting-started/
total 16
drwxr-xr-x 4 www-data www-data 4096 Oct 28 05:23 .
drwxr-xr-x 3 www-data www-data 4096 Oct 28 05:23 ..
drwxr-xr-x 8 www-data www-data 4096 Oct 28 05:23 1.0.0
drwxr-xr-x 8 www-data www-data 4096 Oct 28 05:23 1.1.0
lrwxrwxrwx 1 www-data www-data    5 Oct 28 05:23 latest -> 1.1.0

每个版本是一个真实目录,latest 标签是指向版本目录的符号链接——这就是"标签切换零成本"的底层实现,也是备份时必须保留符号链接属性的原因(tar 打包时注意不要加 --dereference)。

十、k8s / Helm 部署路径说明(未实测)

截至 2026-10-28 查询官方仓库 1.6.1 标签:DOCAT 官方未提供 Kubernetes manifests 或 Helm Chart,官方发行物只有源码仓库与预构建应用包(ghcr.io 上的官方成品包)两种形态,均无配套的编排描述文件。社区如有 k8s 需求,需自行编写 Deployment/Service/PVC 描述(存储根 /var/docat 与 nginx 静态目录需要持久卷),本专栏未对该路径做实测,此节仅作事实说明以免误导选型。

十一、排障实录汇总

#现象根因解决
1yarn build 报 Could not resolve './../assets/getting-started.md' in src/pages/Help.tsx源码中 web/src/assets/getting-started.md 是指向仓库 doc/getting-started.md 的符号链接,把 web 目录单独拷出后链接目标丢失(悬空链接)删除悬空链接后,把真实文件拷入:cp /opt/docat-src/doc/getting-started.md /opt/web-build/src/assets/,重新 yarn build
2pip install /opt/docat-src/docat 报 could not create 'docat.egg-info': Read-only file systempip 构建时要在源码目录写 egg-info,源码目录为只读挂载时构建失败把源码拷贝到可写路径再安装:cp -r /opt/docat-src/docat /opt/docat-build && pip install /opt/docat-build
3首页 200 但 /api/* 全部 404(nginx HTML 404 页)nginx 随 apt 安装已自启,之后 systemctl enable --now nginx 不会重载新站点配置systemctl restart nginx 后恢复;见第八节排障实录 1
4上传 zip 后返回 Documentation uploaded successfully, but no index.html found at root of archive.打包时把外层目录打进去了(zip 根是 site/ 而不是 index.html),服务端解包后找不到入口在站点目录内打包(cd site && zip -r ../x.zip .),保证 index.html 位于 zip 根

十二、部署检查清单

  • python3 -c 'from docat.app import app' 无报错
  • systemctl is-active docat-api 返回 active,/opt/docat-venv/bin/python -m uvicorn ... 进程常驻(内存 ~42 MB)
  • ss -ltn 可见 8143(对外)与 127.0.0.1:5000(对内)
  • curl http://127.0.0.1:8143/api/stats 返回 JSON 统计
  • 首页 / 与文档页 /doc/<项目>/<版本>/ 均 200
  • /var/docat 属主为 www-data,版本目录与 latest 符号链接结构正确

完成部署后,建议继续阅读 《DOCAT 配置参数详解》 了解环境变量、反代与认证的逐项调优,以及 《DOCAT 常用 CLI 命令详解》 掌握日常发布操作。