Jw
首页
技术
英语
首页
技术
英语
  • 本站部署

    • 本地构建 + 同步到服务器
  • 知微(知识库 Agent)

    • 生产部署记录
    • HTTPS 证书基础
    • SSE 流式响应

知微(知识库 Agent)生产部署记录

一个「Vue 前端 + Node 服务 + DeepSeek」的知识库问答应用从零上线:Nginx 反向代理、systemd 守护、Let's Encrypt HTTPS,以及让 SSE 流式回答正常工作的代理配置。

  • 部署域名:https://kb.example.com
  • 项目仓库:liujw123/knowledge_agent

一、最终架构

Internet
  │ HTTPS / 443
  ▼
Nginx 1.22.1
  ├─ kb.example.com -> HTTP 301 -> HTTPS
  └─ 反向代理 -> 127.0.0.1:3001
                    │
                    ▼
              Node.js 24.12.0
              ├─ /api/*
              ├─ frontend/dist
              └─ /var/lib/knowledge-agent
  • 不依赖 Docker
  • 前端静态文件由 Node 服务托管
  • SSE 流式回答由 Nginx 反向代理
  • 服务由 systemd 守护,异常退出自动重启
  • HTTPS 使用 Let's Encrypt + Certbot 自动续期

二、服务器环境

组件版本 / 路径
Nginx1.22.1
Node.jsv24.12.0
Node 路径/usr/local/nvm/versions/node/v24.12.0/bin/node
pnpm11.24.0
Git2.39.5
域名kb.example.com
应用目录/opt/knowledge-agent
数据目录/var/lib/knowledge-agent
服务用户kb
Node 服务端口127.0.0.1:3001

服务器公网 IP 在文档中省略,配置 DNS 时使用实际服务器 IP。

三、DNS 配置

在阿里云 DNS 添加子域名:

记录类型:A
主机记录:kb
记录值:<服务器公网 IP>
TTL:600

验证:

ping kb.example.com

不直接覆盖 example.com 或 www.example.com,避免影响现有站点。

四、安装运行环境

sudo apt update
sudo apt install -y git nginx curl

Node.js 已在服务器上通过 NVM 安装:

/usr/local/nvm/versions/node/v24.12.0

安装 pnpm:

npm install -g pnpm@11.24.0
pnpm -v

五、创建运行用户与目录

不要使用 root 直接运行 Node 服务。

sudo useradd --system --create-home --shell /usr/sbin/nologin kb || true

sudo mkdir -p /opt/knowledge-agent /var/lib/knowledge-agent

授权:

sudo chown -R kb:kb /opt/knowledge-agent /var/lib/knowledge-agent

六、拉取代码并构建

cd /opt
sudo -u kb git clone https://github.com/liujw123/knowledge_agent.git knowledge-agent

cd /opt/knowledge-agent
sudo -u kb pnpm install --frozen-lockfile
sudo -u kb pnpm build

构建产物:

frontend/dist

Node 服务启动时会自动托管该目录。

七、配置生产环境变量

sudo -u kb cp /opt/knowledge-agent/server/.env.example /opt/knowledge-agent/server/.env
sudo nano /opt/knowledge-agent/server/.env

生产配置:

PORT=3001
HOST=127.0.0.1

DATA_DIR=/var/lib/knowledge-agent
CORS_ORIGIN=https://kb.example.com

MAX_UPLOAD_MB=100

# 可选:服务端兜底模型
# DEEPSEEK_API_KEY=sk-xxx
DEEPSEEK_BASE_URL=https://api.deepseek.com
DEEPSEEK_MODEL=deepseek-chat

权限:

sudo chown kb:kb /opt/knowledge-agent/server/.env
sudo chmod 600 /opt/knowledge-agent/server/.env

说明:

  • HOST=127.0.0.1:只允许本机 Nginx 访问,3001 不对公网开放
  • DATA_DIR:文档和知识库状态的持久化目录
  • MAX_UPLOAD_MB:公网部署建议限制上传大小,避免内存被打满
  • DEEPSEEK_API_KEY:可选;如果填写,服务端会保留兜底模型能力

八、systemd 服务

创建:

sudo nano /etc/systemd/system/knowledge-agent.service

内容:

# 服务描述与启动顺序:网络就绪后再启动
[Unit]
Description=Knowledge Agent
After=network.target

# 服务运行参数
[Service]
# simple:ExecStart 进程即为主进程
Type=simple
# 以低权限用户 kb 运行,不使用 root
User=kb
Group=kb
# 工作目录:server 目录,相对路径以此为基准
WorkingDirectory=/opt/knowledge-agent/server
# 生产环境标记
Environment=NODE_ENV=production
# 加载环境变量文件(端口、DATA_DIR、MAX_UPLOAD_MB 等)
EnvironmentFile=/opt/knowledge-agent/server/.env
# 启动命令:使用 NVM 中的 Node 绝对路径 + 后端入口
ExecStart=/usr/local/nvm/versions/node/v24.12.0/bin/node /opt/knowledge-agent/server/src/index.js
# 进程异常退出后自动重启
Restart=always
# 重启前等待 3 秒
RestartSec=3
# 最大打开文件数,避免并发上传/SSE 连接不足
LimitNOFILE=65535

# 安装配置:开机时进入多用户模式即自动启动
[Install]
WantedBy=multi-user.target

启用:

# 重新加载 systemd 配置(修改 .service 文件后必须执行)
sudo systemctl daemon-reload
# 设置开机自启,并立即启动服务
sudo systemctl enable --now knowledge-agent
# 查看服务运行状态(--no-pager 避免进入分页模式)
sudo systemctl status knowledge-agent --no-pager

验证:

curl http://127.0.0.1:3001/api/health

预期:

{
  "ok": true,
  "model": "deepseek-chat",
  "envModelConfigured": true,
  "documentCount": 0,
  "chunks": 0
}

九、Nginx 反向代理

创建:

sudo nano /etc/nginx/sites-available/kb.example.com

初始 HTTP 配置:

# 虚拟主机:监听 80 端口(HTTP),HTTPS 由 Certbot 后续添加
server {
    listen 80;
    # IPv6 同样监听 80 端口
    listen [::]:80;
    # 匹配域名:只有请求头 Host 为该域名时才使用此配置
    server_name kb.example.com;

    # 允许的最大请求体大小,需与 .env 中 MAX_UPLOAD_MB 保持一致
    client_max_body_size 100m;

    # 所有路径都转发到后端
    location / {
        # 反向代理到本机 Node 服务(仅本机可访问)
        proxy_pass http://127.0.0.1:3001;

        # 使用 HTTP/1.1,保持与后端的长连接
        proxy_http_version 1.1;
        # 保留原始 Host 头
        proxy_set_header Host $host;
        # 传递客户端真实 IP
        proxy_set_header X-Real-IP $remote_addr;
        # 传递代理链 IP 列表
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        # 告诉后端原始协议(http / https)
        proxy_set_header X-Forwarded-Proto $scheme;
        # 清空 Connection 头,避免代理断开长连接
        proxy_set_header Connection "";

        # SSE 流式响应不能缓冲,否则回答会一次性输出
        # 关闭响应缓冲
        proxy_buffering off;
        # 关闭缓存
        proxy_cache off;
        # 关闭请求体缓冲(上传文件时直接转发)
        proxy_request_buffering off;
        # 后端读取超时:流式回答较长时不被提前断开
        proxy_read_timeout 300s;
        # 向后端发送超时
        proxy_send_timeout 300s;
    }
}

启用:

# 创建软链接,让 Nginx 加载该站点配置
sudo ln -s /etc/nginx/sites-available/kb.example.com /etc/nginx/sites-enabled/
# 检查配置语法是否正确
sudo nginx -t
# 重新加载配置,不中断现有连接
sudo systemctl reload nginx

本机验证:

curl -H "Host: kb.example.com" http://127.0.0.1/api/health

十、HTTPS 配置

现有阿里云免费证书只覆盖:

example.com
www.example.com

不包含 kb.example.com,因此为子域名单独签发 Let's Encrypt 证书:

sudo apt install -y certbot python3-certbot-nginx
sudo certbot --nginx -d kb.example.com

选择自动跳转 HTTPS。

证书位置:

/etc/letsencrypt/live/kb.example.com/fullchain.pem
/etc/letsencrypt/live/kb.example.com/privkey.pem

验证:

curl -I http://kb.example.com
curl -I https://kb.example.com
sudo certbot renew --dry-run

预期:

http  -> 301 Location: https://kb.example.com/
https -> 200 OK

可选:添加 HSTS,让浏览器以后优先使用 HTTPS。

在 HTTPS 的 server 块中加入:

add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;

然后:

sudo nginx -t
sudo systemctl reload nginx

证书类型、SAN、ACME 与 HTTP-01 / DNS-01 的原理,见 HTTPS 证书基础。

十一、页面首次使用

打开:

https://kb.example.com

点击右上角「未配置模型」,填写:

Base URL: https://api.deepseek.com
模型 ID: deepseek-chat
API Key: 你的 DeepSeek Key

点击「测试连接」,成功后「保存并启用」。

然后:

  1. 打开左侧「知识库」
  2. 上传 PDF / DOCX / Markdown
  3. 等待解析和索引完成
  4. 在聊天框提问
  5. 点击回答里的引用角标查看原文片段

十二、常见问题与解决

12.1 pnpm: command not found

现象:

sudo -u kb pnpm install --frozen-lockfile
sudo: pnpm: command not found

原因:

Node 和 pnpm 安装在 root 的 NVM 路径:

/usr/local/nvm/versions/node/v24.12.0/bin

kb 用户的 PATH 没有这个目录。

解决:

sudo ln -sf /usr/local/nvm/versions/node/v24.12.0/bin/node /usr/local/bin/node
sudo ln -sf /usr/local/nvm/versions/node/v24.12.0/bin/npm  /usr/local/bin/npm
sudo ln -sf /usr/local/nvm/versions/node/v24.12.0/bin/npx  /usr/local/bin/npx
sudo ln -sf /usr/local/nvm/versions/node/v24.12.0/bin/pnpm /usr/local/bin/pnpm

验证:

sudo -u kb node -v
sudo -u kb pnpm -v

12.2 systemd 报 203/EXEC

现象:

status=203/EXEC
ExecStart=/usr/bin/node ...

原因:

/usr/bin/node 不存在,Node 实际在 NVM 路径。

解决:

ExecStart=/usr/local/nvm/versions/node/v24.12.0/bin/node /opt/knowledge-agent/server/src/index.js

然后:

sudo systemctl daemon-reload
sudo systemctl restart knowledge-agent
sudo systemctl status knowledge-agent --no-pager

12.3 阿里云免费证书不能复用到子域名

原因:

  • 阿里云免费证书是单域名 DV 证书
  • 不包含 kb.example.com
  • 不能给已有证书追加子域名

解决:

  • 为 kb.example.com 单独申请证书
  • 或使用 Let's Encrypt + Certbot
  • 多个子域名需要通配符证书

最终使用 Certbot:

sudo certbot --nginx -d kb.example.com

12.4 SSE 流式回答变成一次性输出

原因:

Nginx 默认会缓冲代理响应。

解决:

proxy_buffering off;
proxy_cache off;
proxy_request_buffering off;
proxy_read_timeout 300s;
proxy_send_timeout 300s;

完整排查顺序与前端解析方式,见 SSE 流式响应。

十三、常用运维命令

# 查看服务状态
sudo systemctl status knowledge-agent --no-pager

# 实时日志
sudo journalctl -u knowledge-agent -f

# 最近 50 行日志
sudo journalctl -u knowledge-agent -n 50 --no-pager

# 重启服务
sudo systemctl restart knowledge-agent

# 检查 Nginx 配置
sudo nginx -t

# 重载 Nginx
sudo systemctl reload nginx

# 查看 Nginx 配置
sudo nginx -T | grep -n "kb.example.com"

# 检查本机 API
curl http://127.0.0.1:3001/api/health

# 检查公网 API
curl https://kb.example.com/api/health

# 检查证书续期
sudo certbot renew --dry-run

十四、更新部署

cd /opt/knowledge-agent
sudo -u kb git pull
sudo -u kb pnpm install --frozen-lockfile
sudo -u kb pnpm build
sudo systemctl restart knowledge-agent

十五、上线检查清单

  • [x] DNS 解析 kb.example.com
  • [x] Node 服务 127.0.0.1:3001
  • [x] systemd 守护
  • [x] Nginx 反向代理
  • [x] HTTP 自动跳转 HTTPS
  • [x] Let's Encrypt 证书
  • [x] Certbot 自动续期
  • [x] 前端页面可访问
  • [x] 后端 health 接口正常
  • [ ] 页面模型配置
  • [ ] 上传文档测试
  • [ ] 访问控制 / 服务端 Key 安全处理

速查

# 服务状态 / 实时日志 / 最近 50 行日志
sudo systemctl status knowledge-agent --no-pager
sudo journalctl -u knowledge-agent -f
sudo journalctl -u knowledge-agent -n 50 --no-pager

# 重启服务 / 设置开机自启
sudo systemctl restart knowledge-agent
sudo systemctl enable --now knowledge-agent

# 修改 systemd 配置后重新加载
sudo systemctl daemon-reload

# 检查并重载 Nginx
sudo nginx -t
sudo systemctl reload nginx

# 本机 / 公网健康检查
curl http://127.0.0.1:3001/api/health
curl https://kb.example.com/api/health

# 更新部署:拉代码 → 装依赖 → 构建 → 重启
cd /opt/knowledge-agent
sudo -u kb git pull
sudo -u kb pnpm install --frozen-lockfile
sudo -u kb pnpm build
sudo systemctl restart knowledge-agent

# 检查证书能否自动续期
sudo certbot renew --dry-run
场景关键点
服务起不来先看 systemctl status 与 journalctl -u knowledge-agent -n 50
改完 .env / .service 不生效分别执行 daemon-reload、restart
公网 502确认 Node 监听 127.0.0.1:3001,且 Nginx proxy_pass 指向它
回答一次性输出Nginx 关缓冲,详见 SSE 流式响应

相关

  • HTTPS 证书基础:SAN、DV / OV / EV、ACME、Certbot 与续期
  • SSE 流式响应:协议格式、前后端实现与 Nginx 缓冲排查
  • 本地构建 + 同步部署到服务器:本站静态站点的发布方式
  • 技术笔记总览:全部技术栈入口
最近更新: 2026/10/25 10:17
Contributors: liujw
Next
HTTPS 证书基础