发布时间:2026/8/25 22:54:26
Agent + Wiki + RAG 三件套公网部署实录:Docker 化的 21 个坑,第 8 个直接让我裂开 Agent Wiki RAG 三件套公网部署实录Docker 化的 21 个坑第 8 个直接让我裂开关键词Agent 部署 · Docker 多阶段构建 · pgvector · zhparser 中文分词 · 数据迁移 · 韩国服务器 · Windows 环境前言背景交代一下我手上有个叫navigate的个人 Agent 项目技术栈是LangChain LangGraph带三块核心能力Agent—— 基于 LLM 的工具调用循环能操作文件、执行命令、检索知识Wiki—— 集成 zyplayer-doc 知识库Java MySQL做文档沉淀RAG—— PostgreSQL pgvector 向量检索配合 zhparser 中文分词实现混合检索向量 BM25 关键词兜底本地跑得好好的今年终于下定决心把它部署到公网。买了一台阿里云韩国节点轻量服务器2核2G79元/年免备案——对免备案真香然后就是长达两天的渡劫之旅。这篇文章把整个过程中踩过的坑全部复盘一遍按类别整理成 6 组 21 个坑。特别是 Windows 本地环境那组第 8 个坑我直接被整不会了。部署架构先看最终长什么样这是踩完所有坑之后的目标形态公网用户 ──HTTPS── Caddy 反向代理(:443) ── navigate-app(:3001, 仅内网) │ ├── postgres pgvector zhparser(:5432, 仅内网) └── zyplayer-doc(:8083, 可选)核心原则一切端口收进内网公网只留 80/443密钥全部走环境变量注入数据全部进 Docker volume。踩坑目录分组坑一句话镜像与构建1. 项目根本没有应用 Dockerfile只有个 pg 的基础镜像2. tsc 不复制静态资源登录页/简历页 404 的元凶3. .dockerignore 误伤 resume.mdCOPY resume.md报 not found4. zhparser 中文分词装不上Debian 没包只能源码编译5. 服务器 2G 内存构建 OOM必须加 swap6. 多阶段构建镜像从 1.5G 瘦到 400M安全7. 数据库密码是公开默认值navigate/navigate8. Express 默认 0.0.0.0裸奔公网必须收进内网9. 密钥打进镜像env_file 注入才对Windows10. PowerShell 跑 Linux 命令head/grep/cd /d 全是坑11. PowerShell 重定向损坏二进制pg_dump 导出一坨乱码12. Git Bash 的 MSYS 路径转换/backup变成了C:/Program Files/Git/backup访问13. 没有域名SSH 隧道先跑起来14. Caddy 自动 HTTPS必须要有域名 解析zyplayer15. 登录后跳回登录页SPA 的 localStorage 残留16. zyplayer 数据迁移MySQL dump 文件卷数据迁移17. RAG 数据在 pgpg_dump 直接搬向量不用重算18. SQLite 和上传文件navigate.db rag_uploads 卷迁移19. 迁移顺序先扩展、后数据、再起服务20. 个人镜像拉不到liuwenbo/pg_vector_fts 是个雷21. 服务器构建太慢一次 10-20 分钟靠 layer 缓存续命下面挑重点展开讲。第一组镜像与构建坑 1-6坑 2tsc 不复制静态资源登录页 404现象本地npm run build编译通过npm start也能跑但部署到 Docker 里一访问/login就是 404。原因项目的前端页面login.html、resume.html等放在src/server/public/而tsc只编译.ts文件根本不会把.html复制到dist/。本地开发用 tsx 直接跑源码所以没事一上生产就原形毕露。解决Dockerfile 里手动补一步# tsc 不复制静态资源必须手动补上否则登录页/简历页 404 COPY --frombuilder /app/src/server/public dist/server/public/教训本地能跑 ≠ 生产能跑。开发用的是 tsx源码直跑生产是编译产物两类环境差异要提前盘清楚。坑 3.dockerignore的*.md误伤resume.md现象构建跑到COPY resume.md ./报错failed to compute cache key: /resume.md: not found。原因为了精简构建上下文我在.dockerignore里写了*.md排除所有文档。结果resume.md简历数据应用运行时要读也被排除了。文件在磁盘上明明存在但被排除在构建上下文之外COPY 自然找不到。解决dockerignore 和 gitignore 一样后面的规则覆盖前面的用!重新包含*.md !resume.md !skills/*.md教训.dockerignore排除规则要先粗后细排除所有之后记得用!把运行期必需的文件捞回来。这是最容易阴沟翻船的一步。坑 4zhparser 中文分词装不上数据库起不来现象postgres 容器构建失败apt 报E: Unable to locate package libscws-dev。原因这个项目的数据库迁移脚本硬依赖zhparser中文全文检索分词插件创建chinese_zh文本搜索配置。但本地 compose 用的liuwenbo/pg_vector_fts:pg17是个人镜像服务器上大概率拉不到坑 20官方pgvector/pgvector:pg17镜像没有 zhparserDebian bookworm 仓库里没有libscws-dev包SCWS 是 zhparser 的底层分词库三层叠加直接把数据库堵死。解决写一个 fallback 构建脚本源码编译 SCWS → 再编译 zhparserFROM pgvector/pgvector:pg17 RUN apt-get update \ apt-get install -y --no-install-recommends \ build-essential postgresql-server-dev-17 git ca-certificates wget \ autoconf automake libtool pkg-config \ rm -rf /var/lib/apt/lists/* # SCWS 源码编译GitHub 源码包不含 configure用自带 acprep 生成 RUN wget -q https://github.com/hightman/scws/archive/refs/tags/1.2.3.tar.gz -O /tmp/scws.tar.gz \ mkdir -p /tmp/scws \ tar xzf /tmp/scws.tar.gz -C /tmp/scws --strip-components1 \ cd /tmp/scws \ ./acprep \ ./configure --prefix/usr/local \ make -j$(nproc) make install ldconfig \ rm -rf /tmp/scws /tmp/scws.tar.gz # zhparser 编译指定 PG17 的 pg_config 和 SCWS 路径 RUN git clone --depth 1 https://github.com/amutu/zhparser.git /tmp/zhparser \ cd /tmp/zhparser \ make PG_CONFIG/usr/lib/postgresql/17/bin/pg_config SCWS_HOME/usr/local \ make install PG_CONFIG/usr/lib/postgresql/17/bin/pg_config SCWS_HOME/usr/local \ rm -rf /tmp/zhparser教训CREATE EXTENSION这类硬依赖部署前就要在目标环境验证好。个人镜像、第三方扩展、官方镜像缺组件三座大山提前搬。坑 5服务器 2G 内存构建 OOM现象npm citsc编译过程中内存被打爆构建直接失败或卡死。解决服务器上先建 4G swapfallocate-l4G /swapfilechmod600/swapfilemkswap/swapfileswapon/swapfileecho/swapfile none swap sw 0 0/etc/fstab教训买服务器别只看价格内存决定你能不能构建。2G 内存跑 Node 编译必须配 swap这是部署 Agent/RAG 这类依赖重的项目的第一课。第二组安全坑 7-9坑 7数据库密码是公开默认值现象本地docker-compose.yml里POSTGRES_PASSWORD: navigate——这密码等于没有。解决生产编排文件里密码走环境变量部署时用docker compose --env-file .env.prod注入environment:POSTGRES_PASSWORD:${POSTGRES_PASSWORD}# 从 .env.prod 读不写死在文件里注意compose 的${}变量替换读的是--env-file指定的文件不是env_file:那是注入容器的这俩别搞混。坑 8Express 默认监听 0.0.0.0现象app.listen(port)没指定 host默认绑定所有网卡——公网裸奔。解决端口只绑本机公网流量全部走 Caddyports:-127.0.0.1:3001:3001# 只绑本机运维 SSH 内调试用postgres 干脆不映射端口只在 compose 内网可达。坑 9密钥千万别打进镜像.env.prod里有OPENAI_API_KEY、数据库密码、登录密码。做法是Dockerfile不 COPY 任何.env*运行配置用 compose 的env_file: .env.prod注入.env.prod加进.gitignore原 gitignore 居然没忽略它差点提交上去第三组Windows 本地环境的噩梦坑 10-12——最折磨人的一组这组坑全是因为本地是 Windows服务器是 Linux两个环境的 shell 行为差异导致的。每个都让我在凌晨对着报错发呆。坑 10PowerShell 跑 Linux 风格命令现象head : 无法将head项识别为 cmdlet、函数、脚本文件或可运行程序的名称tar.exe: Must specify one of -c, -r, -t, -u, -x原因我把 Linux 命令cd /d、head、grep、反斜杠续行直接粘到 PowerShell 里跑。PowerShell 里没有head/grepcd /d是错误语法\也不是续行符。解决分清环境——PowerShellhead→Select-Object -Firstgrep→Select-String路径D:\xxGit Bash原汁原味 Linux 命令路径/d/xx最佳实践VS Code 终端右上角下拉切到Git Bash之后本地全部用 bash和服务器一致少一半问题。坑 11PowerShell 重定向损坏二进制现象pg_dump -Fc navigate.dump导出的文件在服务器上pg_restore报格式错误mysqldump x.sql导入后中文全乱。原因PowerShell 的重定向默认按UTF-16 文本处理二进制流-Fc自定义格式 dump直接被写坏UTF-8 文本也会被转码。解决在容器内重定向再用docker cp把文件拷出来dockerexeczyplayer-mysqlsh-cmysqldump -uroot -p... --databases zyplayer_doc /tmp/zyplayer_doc.sqldockercpzyplayer-mysql:/tmp/zyplayer_doc.sql ./或者用 Git Bash字节流无此问题。教训Windows 上任何输出重定向到文件的操作涉及二进制或编码时都要警惕。容器内重定向 docker cp 是最稳的。坑 12Git Bash 的 MSYS 路径自动转换现象tar: cant open C:/Program Files/Git/backup/zyplayer-files.tar.gz: No such file or directory原因Git BashMSYS调用原生 Windows 程序时会自动把命令里以/开头的参数容器内路径/backup、/backup/xxx.tar.gz转换成 Windows 路径。于是容器内路径变成了C:/Program Files/Git/backup容器里当然找不到。解决命令前加MSYS_NO_PATHCONV1禁用转换MSYS_NO_PATHCONV1dockerrun--rm-vnavigate_zyplayer-files:/data-v$(pwd):/backup alpinetarczf /backup/x.tar.gz-C/data.或者干脆切到 PowerShell 执行 docker 命令PowerShell 没有 MSYS 转换。教训在 Windows 上任何带容器内路径的 docker 命令都是高危操作。要么统一 PowerShell要么统一 Git Bash MSYS_NO_PATHCONV1别混着来。第四组无域名的访问方案坑 13-14坑 13没有域名怎么办——SSH 隧道服务器没绑域名备案也不用备韩国节点公网暂时只给自用。最优雅的方案是 SSH 隧道把服务器端口映射到本地# 本地执行转发 app(3001) wiki 代理(3003)ssh-L3001:127.0.0.1:3001-L3003:127.0.0.1:3003 root服务器IP然后浏览器访问http://localhost:3001/login。隧道想常驻就加-N -f关闭用ssh -O exit。坑 14Caddy 自动 HTTPS 必须有域名Caddy 是最省心的反代——两行配置自动申请/续期 Let’s Encrypt 证书。但前提是有域名且 A 记录解析到服务器{$DOMAIN:localhost} { reverse_proxy app:3001 }没域名时 Caddy 只能内部跑先用 SSH 隧道顶着域名下来再切 HTTPS。第五组zyplayer 的坑坑 15-16坑 15改了密码登录后马上跳回登录页现象给 zyplayer-doc 重新设了密码重登后立刻被踢回登录页无限循环。原因zyplayer-doc 是前端 SPA登录态存在浏览器 localStorage不是 cookie。改密码后浏览器里残留旧的登录态 token → 打开页面带着旧 token 请求 → 401 → 跳登录重新登录写入新 token但残留数据没清干净循环往复另外如果走 navigate 的 wiki 反向代理访问代理内部还有会话缓存默认 TTL 600 秒改完密码必须重启 navigate 或等缓存过期。解决F12 → Application → Local Storage / Cookies → 找到 zyplayer 域 → Clear。或者直接无痕窗口测试能登录就是残留问题。坑 16zyplayer 数据迁移 MySQL dump 文件卷zyplayer-doc 的数据分两块MySQL 库zyplayer_doc文档/目录/权限文件卷zyplayer-files上传的附件。迁移时两个都要搬# 导出容器内重定向防编码坑dockerexeczyplayer-mysqlsh-cmysqldump -uroot -p... --databases zyplayer_doc /tmp/z.sqldockercpzyplayer-mysql:/tmp/z.sql ./# 文件卷打包dockerrun--rm-vnavigate_zyplayer-files:/data-v$(pwd):/backup alpinetarczf /backup/files.tar.gz-C/data.服务器恢复时顺序很重要先只起 MySQL → 导入数据 → 恢复文件卷 → 再起 zyplayer-doc避免它抢先初始化建表冲突。第六组数据迁移坑 17-21坑 17RAG 数据在 pg 里pg_dump 直接搬RAG 的文档、分块、向量全在 PostgreSQL。关键结论向量不用重算。只要两边 embedding 模型一致都是text-embedding-3-small、pg 版本一致都是 17、扩展一致pg_dump导出导入就是完整的# 本地Git Bashdockercomposeexec-Tpostgres pg_dump-Unavigate-dnavigate-Fcnavigate.dump# 服务器catnavigate.dump|dockercompose...exec-Tpostgres pg_restore-Unavigate-dnavigate--clean--if-exists坑 18-19SQLite、上传文件、迁移顺序除了 pg还有三个尾巴navigate.dbSQLite简历向量索引rag_uploads/上传的源文档不迁移的话删除/重建文档功能会找不到源文件会话数据也在 pg 里随 dump 一起走了迁移顺序铁律先让服务器把扩展建好init-pg.sql→ 导入数据 → 替换 SQLite/文件卷先停 app→ 再起服务 → 验证 count 一致。坑 20个人镜像拉不到liuwenbo/pg_vector_fts:pg17这种个人镜像本地能用可能很久以前 pull 过服务器上docker pull直接失败。生产环境所有镜像必须来自官方仓库或自己能构建这是我这次最深的体会之一。坑 21服务器构建慢一次完整构建 postgres 编译 zhparser5-15 分钟 app 的 npm ci tsc3-8 分钟。缓解手段Docker layer 缓存先build postgres成功后再 build app互不影响多阶段构建让 runner 层尽量小.dockerignore把node_modules/wiki-js4.7 万个文件排除build context 从几百 MB 压到几 MB总结给后来者的建议Windows 用户先统一终端环境Git Bash 一把梭记住MSYS_NO_PATHCONV1二进制导出用容器内重定向 docker cpDockerfile 从本地能跑推演生产怎么跑静态资源、相对路径、只读文件、数据卷逐项盘第三方扩展和镜像提前在目标环境验证zhparser 这类硬依赖别等到部署才炸安全三件套弱密码必改、端口收内网、密钥不进镜像数据迁移先列清单pg 库 / SQLite / 文件卷 / 源文档缺一个功能就残一个内存不够就 swap2G 机器构建 Node 项目必须做没有域名就用 SSH 隧道别为 HTTPS 硬着头皮等备案部署不是把代码跑起来而是把代码 数据 依赖 安全一起搬过去。希望这篇踩坑实录能帮你少走一半弯路。如果这篇文章对你有帮助欢迎点赞收藏。有任何部署问题欢迎评论区交流我会第一时间回复。

相关新闻

2026/8/25 22:54:26

鼠标灵敏度在哪里设置?6种方法教你鼠标灵敏度怎么调

鼠标灵敏度(又称指针速度)由硬件DPI、系统指针速度、应用程序内灵敏度三个层级共同决定。本文提供6种调节方法,覆盖从系统设置到驱动修复的完整路径。很多用户拿到新鼠标或重装系统后发现手感不对,根源往往是这三个层级没有匹配好…

2026/8/25 22:54:26

国产大模型免费战升级,Grok和ChatGPT却在拼收费

一个信号,两个市场同一个八月,中美两边的 AI 公司做出了截然相反的决定:一边把旗舰模型白送开源,一边把订阅价格越定越高。我刷到一条消息——月之暗面把 Kimi K3 正式开源,总参数 2.8 万亿,号称"目前…

2026/8/26 3:44:42

Kruskal算法实战:最小生成树解决“繁忙的都市”图论问题

1. 项目概述与问题核心“繁忙的都市”这道题,是信息学奥赛和洛谷平台上非常经典的一道图论入门题,题号分别是《信息学奥赛一本通》的1392和洛谷的P2330。我第一次接触它的时候,觉得这名字起得挺有意思,明明是个图论问题&#xff0…

2026/8/26 3:44:42

MATLAB与SPSSAU协同数模实战:算法逻辑与工具分工

1. 这不是“软件教程”,而是一套数模实战的底层工作流设计你手头正压着一个校级数学建模选拔赛的选题——某城市地铁客流预测与运力优化。数据已经拿到:3个月的刷卡记录、天气、节假日标记、线路拓扑图。但打开MATLAB,满屏的命令行让你犹豫要…

2026/8/26 3:44:42

软件测试面试题库构建与实战技巧全解析

1. 软件测试面试全攻略:从题库构建到实战技巧从事软件测试行业十余年,我整理过不下20个版本的面试题库。最近帮团队筛选候选人时,发现市面上流传的"1000道面试题"资料质量参差不齐,很多答案存在技术硬伤。今天就把我压箱…

2026/8/26 3:44:42

Creo新手必看:从config.pro配置到工程图与批量转STL全攻略

这不是制造焦虑的标题,而是很多 Creo 初学者真实遇到的情况:软件装好了,教程也刷了不少,但一到实际建模、工程图、装配体管理、批量转换这些环节,就开始踩坑。网上资料非常零散,要么只讲命令位置&#xff0…

2026/8/26 3:44:42

虚拟机安装Win10全攻略:从工具选择到性能优化

1. 项目概述:为什么要在虚拟机里装Win10?如果你是一个开发者、测试工程师,或者只是一个喜欢折腾电脑的爱好者,那么“在虚拟机里安装一个Windows 10系统”这个念头,大概率已经在你脑海里出现过不止一次了。这听起来像是…

2026/8/26 3:39:42

Android 11无线调试实战指南:从原理到高效开发应用

1. 无线调试:从“线”的束缚中解放双手作为一名在移动开发一线摸爬滚打多年的老码农,我经历过无数次这样的场景:测试机插着数据线放在桌角,每次想拿起来看看UI效果或者操作一下,都得小心翼翼,生怕扯到线把手…

2026/8/25 1:04:19

[光学原理与应用-521]:对光的错误理解与纠偏

首先光是一种能量的载体和形态,宏观上观察到的光是由无数个微观的光量子组成的,每个光子在产生的瞬间,其在真空的空间中以确定不变的速度沿着一个初始的方向一直向前,在微观层面,每个光量子的运动轨迹是以波函数所展现…

2026/8/25 11:48:27

SIP通话转接原理与REFER方法实战解析

1. 通话转接不是“挂断再拨号”,而是SIP会话的动态重定向你有没有遇到过这样的场景:客服坐席A正在和客户通电话,突然需要把这通对话无缝转给专家坐席B,客户完全感知不到中间的断连——既没听到忙音,也没被要求重新拨号…

2026/8/25 16:56:43

Kolla-ansible单节点OpenStack部署实战:从环境准备到排坑指南

1. 为什么选择Kolla-ansible来部署单节点OpenStack?如果你正在寻找一种能把OpenStack从“概念”快速变成“可用的实验环境”的方法,那么Kolla-ansible几乎是当前最主流、最省心的选择。我见过太多人卡在手动编译依赖、配置服务、处理版本冲突的泥潭里&am…

2026/8/26 0:04:32

Python random 模块常用函数详解:从入门到实战

目录 1. 引言2. 准备工作3. 基础随机函数4. 序列相关函数5. 随机种子与复现6. 实战案例7. 注意事项8. 常见问题与排查9. 总结 1. 引言 摘要: 本文系统介绍 Python 标准库 random 模块中最常用的随机数生成函数。内容涵盖基础随机函数(random()、unifor…

2026/8/26 1:19:35

JSON总结

JSON概念 JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式,主要用于跟服务器进行交换数据。它基于ECMAScript的一个子集。 JSON采用完全独立于语言的文本格式,但是也使用了类似于C语言家族的习惯(包括C、C、C#、Java、JavaScr…

2026/8/26 1:19:35

保存连接sse 是什么原理,为什么不会一直请求

“保持连接”用的是 SSE(Server-Sent Events),本质是一个没有马上结束的 HTTP 请求。 过程是: 拷贝机发送一次请求: GET /api/code-sync/events服务器返回: Content-Type: text/event-stream但不关闭响应&…

2026/8/24 13:42:17

实测才敢推 AI论文网站 2026最新测评与推荐

2026年真正好用的AI论文网站,核心看生成的论文质量、低AI味、格式正确、学术适配四大指标。综合实测,千笔AI、ThouPen、豆包、DeepSeek、Grammarly 是当前最值得推荐的梯队,覆盖从免费到付费、从中文到英文、从文科到理工的全场景需求。一、综…

2026/8/24 18:13:48

2026必备!AI论文网站测评:最新推荐与深度对比

2026年真正好用的AI论文网站,核心看生成的论文质量、低AI味、格式正确、学术适配四大指标。综合实测,千笔AI、ThouPen、豆包、DeepSeek、Grammarly 是当前最值得推荐的梯队,覆盖从免费到付费、从中文到英文、从文科到理工的全场景需求。 一、…

2026/8/25 1:08:14

摆脱论文困扰!盘点2026年全网爆红的的AI论文写作工具

一天写完毕业论文在2026年已不再是天方夜谭。2026年最炸裂、实测能大幅提速的AI论文写作工具,覆盖选题构思、文献整理、内容生成、格式排版等核心场景,真正帮你高效搞定论文难题。 一、全流程王者:一站式搞定论文全链路(一天定稿首…