# Linux 单机手动部署参考 现行灰度环境使用 [Jenkins 部署流程](deployment.md)。本页保留独立主机的安装方法,不用于覆盖已有灰度服务。 适用场景:Ubuntu / Debian、已有域名。使用系统 Python 3.10+,无需前端构建或 GPU。入口为 HTTPS → Nginx(客户白名单公开,客服及其他路径需密码)→ 本机 Waitress → Flask / SQLite。 游客历史、人工会话和附件已按访客归属隔离;客户账号登录和订单关联尚未接入,匿名不能查询真实订单。必须沿用示例中的精确公开白名单,保护其余全部路径,包括客服、搜索、导出和原人工接口,不能只保护 `/admin`。上游端口不可对公网开放。 ## 1. 域名与网络 - 将验收子域名的 A 记录解析到服务器公网 IPv4;只有正确配置服务器 IPv6 后才添加 AAAA。 - 服务器安全组和防火墙允许 TCP 80、443,保留实际使用的 SSH 管理端口。不要开放应用端口 5000。 - 服务器需要能够出站访问 Python 包源及 `https://api.deepseek.com`。 - 下文的 `chat.example.com` 均需替换成真实域名,包括 Nginx 配置内的证书路径。 ## 2. 上传源码并安装依赖 首次部署使用 `baiyue-logistics-chat-linux-acceptance.tar.gz`。部署包包含本次工作区的部署文件和缺表修复,不含 `.git`、`.env`、虚拟环境、日志、数据库或本机附件。之前 Git 推送因认证失败未完成;若改用 Git 拉取,须先确认远端版本包含这些变更。 将部署包上传到服务器 `/tmp/`,以下命令均在服务器执行。首次部署假设 `/opt/baiyue-logistics-chat` 尚不存在;已有安装请使用文末更新流程。 ```bash sudo apt update sudo apt install -y python3 python3-venv python3-pip nginx apache2-utils certbot python3 --version sudo tar --no-same-owner -xzf /tmp/baiyue-logistics-chat-linux-acceptance.tar.gz -C /opt sudo adduser --system --group --home /nonexistent --no-create-home baiyue sudo chown root:baiyue /opt/baiyue-logistics-chat sudo chmod 750 /opt/baiyue-logistics-chat cd /opt/baiyue-logistics-chat sudo python3 -m venv .venv sudo .venv/bin/python -m pip install -r requirements.txt ``` 若系统已有专用 `baiyue` 用户,跳过 `adduser`。代码与虚拟环境归 root 所有;服务数据另存到 `/var/lib/`,无需让 Web 进程修改源码。 ## 3. 配置 DS 密钥 仅首次复制配置,已有 `.env` 时跳过复制;不要把本机配置打进部署包。 ```bash sudo install -o root -g baiyue -m 640 .env.example .env sudoedit /opt/baiyue-logistics-chat/.env ``` 在编辑器内填写 `DEEPSEEK_API_KEY=你的密钥`,无需加 `export`,不要在终端命令或日志中输出密钥。文件由应用工厂读取;本方案的 systemd 单元不再注入同名环境变量。更换密钥后重启服务。 ## 4. 启动应用服务 ```bash sudo install -m 644 deploy/baiyue-logistics-chat.service /etc/systemd/system/baiyue-logistics-chat.service sudo systemd-analyze verify /etc/systemd/system/baiyue-logistics-chat.service sudo systemctl daemon-reload sudo systemctl enable --now baiyue-logistics-chat sudo systemctl status baiyue-logistics-chat --no-pager curl -I http://127.0.0.1:5000/ ``` 本机检查应返回 HTTP 200。服务使用独立系统用户、单进程 8 线程并仅监听 `127.0.0.1:5000`,不走 `am.py` 的 Flask 开发服务器回退。单进程保留当前应用的内存输入状态和限流行为;暂不配置多进程或多个副本。 systemd 自动创建并授权以下目录,重启与更新源码不会替换其中的数据: | 内容 | 服务器路径 | |---|---| | SQLite | `/var/lib/baiyue-logistics-chat/history.db` | | 上传附件 | `/var/lib/baiyue-logistics-chat/uploads/` | | 启动备份 | `/var/lib/baiyue-logistics-chat/backups/` | | 应用日志 | `/var/log/baiyue-logistics-chat/app.log` | | 密钥配置 | `/opt/baiyue-logistics-chat/.env` | 首次启动创建八张业务表,不插入演示数据、默认客服账号或密码。已有表和记录保持兼容。应用当前仍会在启动时清理超过 7 天的上传文件,并执行启动备份;启动备份不能替代定时备份。 ## 5. 申请 HTTPS 证书 先安装只提供证书验证路径的 HTTP 配置,此时不会转发到应用: ```bash sudo install -d -m 755 /var/www/letsencrypt sudo install -m 644 deploy/nginx-bootstrap.conf.example /etc/nginx/sites-available/baiyue-logistics-chat sudoedit /etc/nginx/sites-available/baiyue-logistics-chat sudo ln -s /etc/nginx/sites-available/baiyue-logistics-chat /etc/nginx/sites-enabled/baiyue-logistics-chat sudo nginx -t sudo systemctl enable --now nginx sudo systemctl reload nginx sudo certbot certonly --webroot -w /var/www/letsencrypt --cert-name chat.example.com -d chat.example.com ``` 编辑配置时替换域名,申请证书时也替换两处域名;按 Certbot 提示填写邮箱和确认条款。若申请失败,先核对 DNS 和外网 80 端口,保留引导配置排查,暂不安装下一步需要证书的 TLS 配置。 ## 6. 设置访问密码并开放 HTTPS 验收 创建验收账号 `preview`,密码由命令交互输入,不写入项目配置。`-c` 仅首次创建密码文件时使用;以后修改密码应去掉 `-c`。 ```bash sudo htpasswd -cB /etc/nginx/.baiyue-preview.htpasswd preview sudo chown root:www-data /etc/nginx/.baiyue-preview.htpasswd sudo chmod 640 /etc/nginx/.baiyue-preview.htpasswd sudo install -m 644 deploy/nginx.conf.example /etc/nginx/sites-available/baiyue-logistics-chat sudoedit /etc/nginx/sites-available/baiyue-logistics-chat sudo nginx -t sudo systemctl reload nginx ``` 替换 TLS 配置中所有域名及证书路径;`nginx -t` 失败时先修正,不要继续 reload。模板的访问密码覆盖页面、附件、静态资源和全部 API,后端 5000 端口继续只对本机开放。不能只在导航层隐藏后台页面。 Nginx 已关闭代理响应缓冲及压缩,并将等待上游数据的超时设为 300 秒,供 AI SSE 分段输出;上传入口允许 12 MiB 请求体以容纳应用 10 MiB 文件上限外的表单开销。 ## 7. 验收和证书续期 ```bash curl -I https://chat.example.com/ curl -I https://chat.example.com/api/export_chat curl -u preview -I https://chat.example.com/ ``` 前两条应返回 401,证明页面和数据接口都受保护;第三条交互输入访问密码后应返回 200。浏览器也会先弹出访问密码: - 客户页:`https://chat.example.com/`,发送消息检查 DS 实际回复及流式显示。 - 验收工作台:`https://chat.example.com/admin/dashboard`,从客户页申请人工,再检查接待和双向消息。 - 当前未预置应用内客服登录账号;Nginx 的 `preview` 是客服及受保护接口的访问账号,不是 `/admin` 页里的客服账号,客户首页无需此账号。 安装证书续期后的 Nginx 重载钩子,并检查续期定时器: ```bash sudo install -d -m 755 /etc/letsencrypt/renewal-hooks/deploy sudo install -m 755 deploy/reload-nginx.sh /etc/letsencrypt/renewal-hooks/deploy/baiyue-reload-nginx sudo systemctl enable --now certbot.timer sudo certbot renew --dry-run --run-deploy-hooks ``` 最终配置保留 HTTP 的 `/.well-known/acme-challenge/` 路径,供 webroot 续期使用;其他 HTTP 请求跳转到 HTTPS。不要删除验证路径或只对自己的 IP 开放证书验证端口,否则后续续期会失败。 ## 维护、更新和问题定位 ```bash sudo journalctl -u baiyue-logistics-chat -n 100 --no-pager sudo tail -n 100 /var/log/baiyue-logistics-chat/app.log sudo systemctl restart baiyue-logistics-chat sudo nginx -t ``` - **502**:先查应用状态、journal 日志、依赖安装及 5000 端口本机检查。 - **一直弹访问密码**:检查 Nginx 密码文件和 `www-data` 读权限;不要用应用内客服密码替代验收密码。 - **AI 无回复**:确认服务器 `.env` 已填写并重启,检查服务器能否访问 DS;本机验收成功不代表服务器网络已验证。 - **输出集中到最后**:检查实际生效的 Nginx 配置和 CDN 是否重新启用了缓冲。 - **429**:目前反向代理后的请求共享应用默认限流桶,适合单人验收;多人开放前需正确配置可信代理和业务限流。 更新前停止应用并备份 `/var/lib/baiyue-logistics-chat/`,另行保护 `.env`。源码更新只替换项目文件,不复制本机数据库或 `work/`,不覆盖服务器 `.env`;按需重新安装依赖后重启。若修改 systemd 单元,重新安装单元并执行 `daemon-reload`;若修改 Nginx,先检查再 reload。回退源码时仍保留数据副本,本项目尚无数据库降级迁移工具。 本地已通过应用工厂和全新数据库回归;目标服务器的 `systemd-analyze verify`、`nginx -t`、DNS、证书签发及真实 DS 请求仍需在部署时验证。 ## 参考 工厂调用与监听参数依据 [Waitress 官方文档](https://docs.pylonsproject.org/projects/waitress/en/stable/runner.html)。流式转发配置依据 [Nginx 代理模块](https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_buffering),客服后台密码依据 [Nginx Basic Auth 模块](https://nginx.org/en/docs/http/ngx_http_auth_basic_module.html)。证书和续期使用 [Certbot webroot](https://eff-certbot.readthedocs.io/en/stable/using.html#webroot);服务目录与只读保护依据 [systemd.exec](https://www.freedesktop.org/software/systemd/man/latest/systemd.exec.html)。