RAGFlow生产部署实战:Docker Compose + systemd + 环境变量全解析

发布时间:2026/10/10 11:07:51
RAGFlow生产部署实战:Docker Compose + systemd + 环境变量全解析
简介这份PDF配置指南面向有一定Docker基础、希望快速部署或深度调优RAGFlow环境的研发与运维人员重点解决多容器编排、服务端口与密码设置、系统级参数调整等实际问题。文档围绕.env、service_conf.yaml.template、docker-compose.yml三个关键配置文件展开覆盖MySQL、MinIO、Elasticsearch、Redis等依赖组件的参数设置详细讲解端口、密码、内存限制、时区、Hugging Face镜像站点及macOS优化等环境变量同时说明如何修改默认HTTP服务端口、重启容器使配置生效并提示非官方Compose文件的使用风险。针对生产环境文档还介绍了配置文件中的数据库连接池、超时时间等调优参数以及OAuth接入与默认LLM的选择入口。压缩包内为1个PDF文件大小约121KB篇幅不大但要点密集适合作为部署时的速查手册。目前已有4465人学习下载对希望规避常见配置错误、提升RAGFlow上线效率的技术人员很有帮助。1. 为什么 RAGFlow 部署绕不开 Docker这套配置到底在解决什么把 RAGFlow 部署上生产真正费时间的不是拉镜像而是把环境变量和系统服务这两件事理顺。RAGFlow 作为开源 RAG 引擎把文档解析、知识库管理、检索增强生成放在同一套体系里后端同时依赖 MySQL、Elasticsearch、Redis、MinIO 多个中间件。直接在一台裸机上逐个安装这些组件版本组合和配置互相打架是家常便饭所以官方主推 Docker Compose 方式落地。也正因为所有组件都被容器化服务之间怎么互相找到、系统重启后怎么恢复就成了部署里最容易被忽略、也最容易翻车的两个环节。这篇笔记要做的事很具体先拆 RAGFlow 的 Docker 部署结构再把环境变量从 .env 文件到容器内生效的链路讲清楚最后用 systemd 把整套服务托管成系统级服务保证开机自启、日志可查、故障可排查。适合正在做企业大模型私有化部署的运维同学也适合想用 Docker 本地快速跑通 RAGFlow 的开发者。下文涉及的方案都基于常见生产部署做法命令可以直接抄但参数建议根据自己的目录和端口改。2. 用 Docker 把 RAGFlow 跑起来compose 服务拆解与镜像选型2.1 部署前要确认的三样东西宿主机资源、Docker 引擎、目录规划先别急着复制命令。RAGFlow 不是单一服务是一组服务联动资源给不够后面排查会非常痛苦。我一般按这个经验值来评估完整跑起来建议 CPU 16 核、内存 32 GB 起步。Elasticsearch 是内存大户默认堆内存分配不足会直接启动失败MySQL 和 MinIO 虽然单看不重但加上 RAGFlow 主服务和解析任务队列16 GB 内存会非常紧张。磁盘建议留 100 GB 以上因为文档解析后的分块数据、向量索引、对象存储文件都会持续增长。只是本地体验或技术验证16 GB 内存加 SSD 也可以跑但解析大 PDF 的时候页面会明显卡顿。Docker 引擎的选择分两条路。Linux 服务器上安装 docker-ce并确认 compose 插件可用用docker compose version验证。Windows 或 macOS 开发机则用 Docker Desktop重点确认 WSL2 后端已启用并给 Docker 分配足够的资源否则跨系统协作时容器日志刷起来没完。目录规划上我习惯把 RAGFlow 项目单独放一个目录所有配置文件和数据持久化目录都收敛在下面方便统一备份与回滚/opt/ragflow ├── docker-compose.yml ├── .env └── docker ├── elasticsearch ├── mysql └── minio这里把配置文件和持久化目录分开放.env只保存变量docker目录以下各中间件的数据卷都通过 compose 里的挂载指向各自子目录。这样做的好处是升级或迁移时只需要打包整个/opt/ragflow目录不会出现数据散落在系统各处、备份漏项的问题。如果后续想换磁盘直接改挂载路径即可。2.2 docker-compose 服务清单每个容器到底在干什么RAGFlow 的 docker-compose 服务清单大致包含这些角色部署前心里要有一张表服务名职责默认端口持久化需求ragflow主服务提供 API 与 Web UI并跑任务队列80数据目录挂载mysql存储知识库元数据与用户信息3306MySQL 数据目录elasticsearch全文检索与向量检索9200ES 数据目录minio对象存储保存解析后的文件9000存储数据目录redis缓存与消息队列6379可选持久化注意 Elasticsearch 在 RAGFlow 体系里不只是关键词检索还承担了向量索引的写入查询所以它的内存和磁盘配置直接影响知识库检索质量。MinIO 用于存放文件解析过程中的中间产物和最终入库文件如果这个容器不可用知识库上传与解析会直接失败。下面是一个最小化的 docker-compose.yml 框架服务名和挂载路径以官方模板为准这里给出可运行的骨架services: ragflow: image: ragflow/ragflow:latest container_name: ragflow-server depends_on: - mysql - elasticsearch - minio - redis env_file: - .env ports: - 80:80 volumes: - ./docker/ragflow:/ragflow/data restart: unless-stopped这段配置里env_file会把.env整个注入容器这个机制的细节下一章展开。depends_on只保证容器启动顺序不保证服务真正可用所以 RAGFlow 主服务内部一般自带等待逻辑但生产环境建议配合健康检查后面第 4 章会讲。restart: unless-stopped在这里是兜底策略它能保证容器异常退出后自动拉起但解决不了服务器重启后的编排问题。镜像选型上一个关键建议不用latest。docker compose pull拉下来的 latest 一旦变化重启可能引入不兼容行为。常见做法是锁定官方模板配套的 tagMySQL 用 8.0 系列Elasticsearch 用官方指定的版本系列这样数据和索引结构相对稳定。升级时再显式修改 tag 并测试而不是被动跟着 latest 漂移。2.3 第一次启动的命令顺序与镜像拉取策略配置文件写好后首次启动建议按下面的顺序执行每一步都观察输出cd /opt/ragflow docker compose up -d docker compose ps docker compose logs -f ragflowdocker compose up -d第一次执行时会把全部镜像拉下来网络状况不好时可能会卡很久这不是故障耐心等待即可。docker compose ps用来查看各容器状态正常情况下 STATUS 列应该是 Up 或 Up (healthy)。docker compose logs -f ragflow则直接看主服务日志RAGFlow 首次启动需要初始化数据库表结构和 Elasticsearch 索引这个阶段会持续一到三分钟日志里出现服务监听端口的提示后再打开浏览器访问。如果出现某个容器反复重启别急着全部 down 重来先看对应容器日志。后面第 5 章会专门罗列几种高频故障其中 Elasticsearch 启动失败是最常见的一种原因和处理方式都会给出。首次启动顺利的话浏览器访问http://服务器IP就能看到登录页。3. 环境变量设置详解从 .env 文件到容器内生效的完整链路3.1 RAGFlow 环境变量体系哪些变量决定服务能不能起来RAGFlow 的环境变量数量不算少但可以按组去理解每组解决一个固定问题。第一组是服务端口和对外配置比如 SVR_HTTP_PORT 这类变量决定了 Web 服务绑定在哪个端口。第二组是数据源连接信息围绕 MySQL、Redis、Elasticsearch、MinIO 的 host、port、账号、密码展开这些变量错了服务之间找不到对方页面往往能打开但功能全报错。第三组是安全与密钥涉及登录口令、密钥盐值等关系到用户体系能否正常初始化。第四组是运行行为包括时区 TZ、日志级别、文件上传大小限制。一个容易忽略的点是这些变量名不是随便起的它们必须和代码里读取的环境变量名完全一致。部署时不要自己发明变量名直接对照官方 compose 模板里的 .env 文件保留默认值再按需修改。我见过有人把 RAGFLOW_DB_HOST 改成 database_host结果容器起来后依然是默认的 mysql 主机名知识库功能全部连不上这类问题定位起来非常费时间。常见做法是官方模板中已经维护好了一份 .env 样例里面列了所有变量名和默认值。你只需要关注三类必改项数据库密码、MinIO 密钥、对外端口。其他变量默认值通常能跑通但建议逐行看一遍至少知道每个变量管什么后面出问题才不会像黑匣子一样瞎猜。3.2 .env 文件的编写示例与参数说明下面是一个典型的 .env 骨架变量名结构参考 RAGFlow 官方模板的常见命名实际以你下载的模板为准# 对外服务端口 SVR_HTTP_PORT80 # MySQL 相关 RAGFLOW_DB_HOSTmysql RAGFLOW_DB_PORT3306 RAGFLOW_DB_NAMEragflow RAGFLOW_DB_USERragflow RAGFLOW_DB_PASSWORDChange_Me_123 # Elasticsearch RAGFLOW_ES_HOSTelasticsearch RAGFLOW_ES_PORT9200 # MinIO RAGFLOW_MINIO_HOSTminio RAGFLOW_MINIO_PORT9000 RAGFLOW_MINIO_ACCESS_KEYminioadmin RAGFLOW_MINIO_SECRET_KEYChange_Me_456 # Redis RAGFLOW_REDIS_HOSTredis RAGFLOW_REDIS_PORT6379 # 通用 TZAsia/Shanghai注意这里的数据源 host 全部写的是服务名比如 mysql、elasticsearch而不是 localhost 或 127.0.0.1。原因在于 RAGFlow 容器和中间件容器处于同一个 Docker 网络容器之间通过服务名互相访问写 localhost 指向的是容器自己会直接导致连接拒绝。这一点是 RAGFlow 部署里最常见的环境变量误区很多第一次用 Docker 部署的人都在这里栽过。密码变量里的值尽量改成强密码尤其是 MySQL 和 MinIO它们会落盘到数据目录里。如果后面用 systemd 托管这套服务运维脚本里读取这些变量也要保持一致。TZ 设置成 Asia/Shanghai 不只是显示时间还影响日志文件的时间戳排查问题对不上时间线会很痛苦。3.3 Docker 环境变量优先级为什么改了没起作用环境变量配置不生效这个问题十次有八次不是玄学而是没有区分 Docker 读取 .env 的两种机制。第一种是env_file它把 .env 文件逐行读入并注入容器容器的环境变量在创建那一刻就被固化后续修改 .env 文件不会影响已存在的容器。第二种是 compose 文件里的${VAR}插值docker compose 解析 docker-compose.yml 时会读取项目目录下的 .env 文件替换变量它服务于配置模板不一定会注入容器环境。这两种机制叠加就容易出现改了半天没反应的情况修改了 .env 里的变量docker compose up -d 检测到容器配置没有变化于是直接复用旧容器新值根本没进容器。此时必须强制重建容器常见做法是执行docker compose up -d --force-recreate ragflow docker compose exec ragflow env | grep RAGFLOW_DB第一条命令强制按当前配置重建主服务容器第二条命令直接查看容器内实际生效的变量确认修改是否落进去。这个验证习惯比任何日志都直观改完环境变量后先看容器内 env再判断配置问题还是业务问题能省下大量排查时间。这里还有一个隐藏优先级问题如果 docker-compose.yml 里同时写了environment硬编码变量和env_file引用前者会覆盖后者。RAGFlow 官方模板一般不会这么做但你自己加环境变量时要注意不要和已存在的变量重名否则你配置的值会被静默忽略。3.4 WindowsDocker Desktop与 Linux 环境变量的差异同样一份 .env在 Linux 服务器和 Windows 开发机上表现可能不同这个问题在本地部署大语言模型相关工作流时经常出现。Windows 上用 Docker Desktop.env文件默认藏在项目目录里路径解析有时会被 PowerShell 的工作目录影响导致 compose 读不到变量。更典型的是换行符问题Windows 记事本保存的 .env 是 CRLF 行尾Linux 容器解析时行尾的\r会被当成变量值的一部分导致密码或 host 末尾多出不可见字符连接数据库时提示认证失败。解决的办法很朴素用 VS Code 等编辑器把 .env 统一保存为 LF 行尾或者在 Windows 上执行dos2unix .env后再启动容器。另外不要在 .env 里给值加引号Docker 解析环境变量不做 shell 展开RAGFLOW_DB_PASSWORDabc会把双引号也带到值里最终认证的还是带引号的字符串这一步没注意密码反复改都不生效。Linux 部署相对省心但要注意 .env 文件的权限里面有数据库密码等敏感信息建议chmod 600 .env。如果使用 systemd 托管服务以 root 身份读取该文件倒是没有权限障碍但多人在同一台服务器协作时避免其他账号直接看见明文密码是个基本习惯。4. systemd 管理 RAGFlow把容器变成系统级服务的几个关键配置4.1 为什么生产机器不能只靠 restart: unless-stopped很多同学在 docker-compose.yml 里写了restart: unless-stopped就觉得万事大吉。这个策略确实能在容器进程退出时自动重启但它解决不了编排层面的问题。服务器重启后Docker 守护进程会尝试恢复标记为自动重启的容器但恢复顺序不受控制MySQL 还没起来RAGFlow 主服务可能已经在尝试连接数据库并反复失败。另外一个问题是运维视角靠 docker ps 一眼看不出服务预期状态没有独立的服务状态查询入口监控报警接入也麻烦。用 systemd 把 docker compose 项目托管成系统级服务等于把你的 RAGFlow 变成一个有名字、有启停命令、有开机自启规则、有统一日志入口的正规服务。systemctl status 能直接看到服务状态journalctl 能查服务生命周期日志服务器重启后 systemd 会按依赖关系先拉起 docker.service再拉你的 compose 服务。这套组合拳对企业私有化部署特别合适因为你总能对老板说清楚服务现在是活着还是死了。还有一个现实原因compose 的restart策略只针对容器如果宿主机上 docker.service 本身异常退出过或者磁盘挂载顺序出问题容器恢复的时间点和行为就不受控。systemd unit 里可以声明Afterdocker.service network-online.target从系统层面保证网络和 Docker 都就绪后再启动服务这比任何容器内缠斗都靠谱。4.2 一个可用的 systemd unit 文件与启用步骤下面这个 unit 文件是生产环境常见的写法路径和账号根据自己的实际情况调整。我通常把服务名取为 ragflow便于记忆[Unit] DescriptionRAGFlow Docker Compose Service Requiresdocker.service Afterdocker.service network-online.target Wantsnetwork-online.target [Service] Typeoneshot RemainAfterExityes WorkingDirectory/opt/ragflow ExecStart/usr/bin/docker compose up -d ExecStop/usr/bin/docker compose down ExecReload/usr/bin/docker compose up -d --force-recreate TimeoutStartSec180 [Install] WantedBymulti-user.target这里Typeoneshot配合RemainAfterExityes是关键docker compose up -d 执行完就返回不会像常驻进程那样一直挂着oneshot 类型允许命令退出后被 systemd 判定为服务已完成启动RemainAfterExit 让 systemctl status 在命令退出后依然显示 active而不是变成 inactive。这样既不影响容器运行又让 systemd 能管理服务生命周期。ExecReload 里的--force-recreate要谨慎它会重建容器也就是把环境变量变更真正生效但这个过程会短暂中断服务。如果不想中断可以把 ExecReload 改成只执行docker compose up -d代价是环境变量改动不生效。我一般保留 force-recreate因为 reload 本身就是我要改配置的信号中断几秒钟可以接受。TimeoutStartSec180给首次启动留足拉镜像和初始化的时间避免 systemd 因为超时误判启动失败。启用这个服务的步骤如下sudo systemctl daemon-reload sudo systemctl enable ragflow.service sudo systemctl start ragflow.service systemctl status ragflow.servicedaemon-reload让 systemd 重新读取 unit 文件每次修改 unit 后都必须执行。enable会创建开机自启的软链服务器重启后服务自动拉起。start执行实际启动status 查看状态。如果 ExecStart 里的 docker 路径不对比如 Ubuntu 上是 /usr/bin/docker 而 CentOS 上可能在 /usr/bin/docker 或 /usr/local/bin/docker启动会直接报路径错误先执行which docker确认路径再改 unit 文件。4.3 日志管理与 journalctl 的使用托管进 systemd 之后日志入口从 docker logs 变成了双通道systemd 记录服务自身的启停状态容器内部日志仍由 Docker 维护。查服务起没起来、什么时候被拉起的用 journalctl查 RAGFlow 业务日志用 docker compose logs。常用的几条命令sudo journalctl -u ragflow.service -n 100 sudo journalctl -u ragflow.service -f docker compose logs -f ragflow第一条查最近 100 行服务日志能直观看到 systemd 视角下服务的启动和失败记录。第二条实时跟踪服务日志。第三条是看容器内业务日志第一条命令有一个重要作用是区分问题层次如果 journalctl 里显示服务已经 active 但页面打不开问题在容器或应用内部继续看 docker logs如果 journalctl 显示启动失败或 timeout问题在 systemd 编排层先检查 ExecStart 命令和依赖服务状态。这个排查层次的划分能帮你少走很多弯路。4.4 开机自启与健康检查的配合systemd 保证了进程层面的开机自启但服务真正可用还需要中间件就绪。RAGFlow 主服务启动时会等 MySQL 和 Elasticsearch这个逻辑一般写在应用启动脚本里但等待时间有限。如果系统负载高导致 Elasticsearch 初始化变慢主服务可能等待超时后退出这时候 systemd 不会自动把它拉起来因为服务单元本身处于 active 状态。常见做法是给 ragflow 服务加上健康检查compose 文件里可以这样写healthcheck: test: [CMD, curl, -f, http://localhost:80/] interval: 30s timeout: 5s retries: 3这个健康检查每 30 秒探测一次本机 80 端口连续 3 次失败就标记容器 unhealthy。注意它依赖容器内有 curl如果用的镜像精简到没有 curl可以改用 wget 或者直接探测 TCP 端口比如用nc -z localhost 80。健康检查的意义在于给 systemd 一个服务真正就绪的信号也可以配合监控脚本在容器 unhealthy 时自动重建相当于给服务上了双保险。5. RAGFlow 部署避坑环境变量与系统级服务的 5 个常见翻车现场5.1 改了 .env 文件容器里还是旧配置现象修改了 .env 里的密码或端口执行 docker compose up -d 后日志里连接的还是旧地址配置像被锁死了一样没有生效。原因容器的环境变量在创建时已经固化env_file 的内容不会因为文件变更而自动更新。docker compose up -d 对已存在的容器不会重建自然就把新变量挡在了外面。解决执行docker compose up -d --force-recreate强制重建容器。重建后一定要用docker compose exec ragflow env | grep RAGFLOW_DB这种命令确认容器内的变量已更新不要只看文件内容就以为生效了。这个验证习惯能帮你避免 90% 的改了不生效问题。5.2 Elasticsearch 容器启动几秒就退出现象elasticsearch 容器反复重启docker compose logs 里报出内核参数相关错误提示最大虚拟内存区域数量过低启动初始化还没有完成就直接退出。原因Elasticsearch 要求宿主机内核参数 vm.max_map_count 至少为 262144而很多 Linux 发行版默认值只有 65530。这是内核层限制容器内无法修改必须在宿主机上调整。解决执行sudo sysctl -w vm.max_map_count262144临时生效再写入/etc/sysctl.d/99-elasticsearch.conf让重启后保持。改完后需要重启 elasticsearch 容器docker compose restart elasticsearch。这个坑在 RAGFlow 部署中出现频率极高尤其是新装的 CentOS 和 Ubuntu 服务器概率几乎是百分之百。5.3 服务器重启后 RAGFlow 没有跟着起来现象宿主机重启后docker ps 显示 mysql、redis 等容器处于 Up 状态但 ragflow 主服务容器反复 restarting页面一直打不开。原因restart: unless-stopped 会恢复容器但恢复顺序不受控。Elasticsearch 或 MySQL 还在初始化RAGFlow 主服务已经抢先启动并连接超时应用进程退出后触发 restart 策略形成反复重启的死循环。解决用 systemd 单元托管服务让 docker 网络就绪后再启动 compose 项目同时给主服务增加健康检查和启动等待。依赖顺序上现代 docker compose 支持在 depends_on 里声明 condition: service_healthy把仅仅按顺序启动升级为等健康后再启动这是解决此类问题的根本办法。5.4 自定义端口后界面开了但 API 连不上现象把 SVR_HTTP_PORT 改成 8088浏览器访问 8088 端口能看到登录页但创建知识库或调用接口时提示连接失败或超时。原因端口映射和容器内端口不一致。compose 里的 ports 写成 8088:80而 RAGFlow 应用配置里读取 SVR_HTTP_PORT 后可能用它生成内部回跳地址两边对不上导致前端请求发到了错误的端口。解决保持端口映射和设备变量一致确认 ports 左侧宿主机端口与 SVR_HTTP_PORT 数值一致。同时排查防火墙云服务器还需要检查安全组是否放行了对应端口。这类问题一旦发生最容易忽视的是防火墙因为页面能打开容易让人误以为所有端口都已放行实际上 API 走的具体路径可能是另一个端口。5.5 中文文件名在知识库里显示乱码现象上传带中文文件名的文档后知识库列表里显示乱码或者文件解析后内容为空日志里出现编码相关的告警。原因容器内默认 locale 不支持中文同时 .env 里没有设置 TZ 和语言编码相关变量文件在临时目录写入时发生编码转换异常。解决.env 中设置 TZAsia/Shanghai并在 compose 文件里为 ragflow 服务增加语言环境变量比如 LANGC.UTF-8。同时检查挂载目录的属主和权限容器需要能写入临时文件如果宿主目录权限是 root 而容器内进程是普通用户文件写入会失败。挂载目录权限和数据编码问题最近在 Docker Desktop 的跨磁盘共享场景里也频繁出现Windows 用户尤其要留意。6. 部署完成后的验证与升级技巧从重启到换版本都少折腾服务跑起来后我习惯按一套固定清单验证而不是直接点页面看有没有反应。第一步看进程层docker compose ps确认所有容器都是 Up 状态没有反复重启的容器。第二步看服务响应浏览器访问登录页能正常返回或者用后台方式探测 HTTP 状态码sudo journalctl -u ragflow.service -n 50 curl -s -o /dev/null -w %{http_code} http://localhost:80/第一条命令确认 systemd 层服务状态正常第二条命令直接看 HTTP 响应码200 表示应用层已就绪。如果响应码是 502 或连接拒绝说明容器活着但应用还没初始化完成多等一会儿再探测。第三步做功能验证登录后台创建一个小知识库上传一个几页的 PDF确认解析任务走到完成状态。这三步走完才敢说这次部署真正落地了。升级版本时最大的教训是备份先行。RAGFlow 的数据分布在 MySQL 和 MinIO 两个数据源里升级前先备份 .env 文件再对数据目录做一次快照比如直接复制/opt/ragflow/docker目录也可以docker compose exec mysql导出一次数据库。容器版本升级本质是镜像 tag 替换加容器重建数据库结构如果跨大版本恢复难度会指数级上升。我习惯在升级前把当前 .env 完整复制一份到 backup 目录这个动作已经救过我两次比任何后悔药都管用。最后回到环境变量这件事上。我经历过的最曲折一次排障是改完 RAGFLOW 的数据库密码后反复确认 .env 无误页面依然报错最后发现是第二种机制在作怪compose 文件里的 ${VAR} 插值和 env_file 指向的不是同一个来源改了文件但插值用的变量没有被替换。从那次之后我给自己定了一个死规矩每次改完环境变量必须用 docker compose exec 进容器内确认 env 实际值再往下排查业务逻辑。这个习惯能砍掉大半的玄学问题。配置这种东西最怕的就是你以为改了而系统读的还是旧值。希望这篇笔记能帮你把 RAGFlow 的部署链路理清楚少踩我踩过的坑让这套 Docker 加 systemd 的方案在生产环境里稳稳跑起来。本文还有配套的精品资源点击获取