Linux下用Docker Compose部署Dify的生产级实战指南
1. 项目概述为什么在Linux上用Docker Compose部署Dify不是“选修课”而是必选项你点开这个标题大概率正站在一台刚装好的Ubuntu服务器前或者刚重装完CentOS的虚拟机终端里手指悬在键盘上方——心里清楚接下来要干的不是敲几行命令就完事的小活儿而是要把一个真正能跑起来、能接入大模型、能搭知识库、能编排工作流的AI应用平台稳稳当当地“种”进你的Linux系统里。这不是部署一个静态博客也不是起个Nginx测试页Dify是典型的现代云原生AI平台它由11个相互咬合的服务组件构成涉及数据库、向量库、缓存、API网关、前端服务、后台任务队列、沙箱隔离环境、SSRF防护代理……任何一个环节配置错位、版本不兼容、端口冲突或资源不足轻则页面白屏、登录失败重则容器反复重启、日志刷屏报错、weaviate无法加载schema、postgres连接池耗尽——而这些问题在Windows或Mac本地开发环境里往往被Docker Desktop的图形界面和自动内存分配悄悄掩盖了。Linux才是Dify生产部署的“真实考场”。这里没有GUI兜底没有WSL2的文件系统桥接缓冲没有后台自动清理机制。你面对的是裸露的cgroup限制、systemd服务管理、iptables规则、SELinux策略、内核参数调优以及最关键的——Docker Compose如何把11个服务像齿轮一样严丝合缝地咬合转动。我过去三年帮27家中小团队落地Dify90%的“部署失败”案例根源不在Dify本身而在于Linux环境下对Docker Compose生命周期管理的理解偏差比如误以为docker compose up -d就是一劳永逸却忽略了restart: always策略在宿主机重启后是否真正生效比如复制了.env.example就以为万事大吉却没发现POSTGRES_PASSWORD里混入了未转义的特殊字符导致postgres容器启动即崩溃再比如看到docker compose ps显示“Up”就松口气却没用docker compose logs -f api盯住API服务的初始化日志结果卡在“waiting for db_postgres”长达8分钟才发现是网络DNS解析超时。所以这篇教程不叫“Dify安装指南”它是一份面向Linux运维者与AI工程实践者的Dify生产级部署作战手册——从内核参数校准到Docker守护进程调优从.env变量安全注入到compose.yaml服务依赖拓扑验证从首次初始化陷阱到后续升级断点续传。它不教你怎么点鼠标只告诉你每一行bash背后发生了什么以及当它没发生时你该去哪条日志里找答案。2. 核心设计逻辑为什么必须用Docker Compose而非单容器或源码直启2.1 Dify的架构本质决定了它无法“简化”部署很多人第一反应是“Dify既然有Web界面能不能像WordPress那样丢个PHP包进去就跑”——这完全误解了Dify的技术基因。Dify不是单体PHP应用它是一个微服务化AI编排平台其核心服务拆分逻辑如下api服务处理所有HTTP请求但自身不存数据只做路由、鉴权、LLM调用封装worker服务异步执行耗时任务如文档切片、向量化、工作流节点执行依赖Redis作为任务队列worker_beat服务基于Celery Beat定时触发周期性任务如知识库自动同步、Token刷新web服务纯静态前端资源React构建产物通过Nginx反向代理到api服务plugin_daemon服务独立守护进程管理插件生命周期与沙箱通信db_postgres服务结构化数据存储用户、应用、对话记录要求PostgreSQL 15weaviate服务向量数据库负责知识库语义检索需专用内存与CPU资源redis服务缓存层会话、API限流 任务队列Celery Brokernginx服务七层负载均衡与SSL终止同时为web和api提供统一入口ssrf_proxy服务基于Squid的HTTP代理强制拦截所有出站请求防止LLM插件发起恶意外联sandbox服务基于gVisor的轻量级沙箱隔离代码解释器执行环境Python/JS沙盒。这11个服务之间存在严格的启动顺序依赖和健康检查闭环api必须等db_postgres和redis就绪才能连接worker必须等redis和api可用才能注册任务web必须等nginx配置加载完成才能响应weaviate必须在api初始化向量库Schema前完成启动。如果强行用docker run逐个启动你需要手写11个启动脚本每个脚本里嵌套sleep 30等待前序服务还要自己实现健康检查轮询——这不仅低效更致命的是无法保证服务间网络互通性。Docker Compose的核心价值正在于它用声明式YAML定义了这个复杂的依赖图谱并通过内置的depends_on条件、healthcheck探针和network_mode: service:xxx网络共享机制让Docker守护进程自动完成拓扑构建与状态编排。我曾用单容器方式硬扛过Dify 0.5.0版本结果在客户生产环境上线第三天因worker_beat与api时间不同步导致定时任务漏执行排查了整整两天才定位到是docker run启动的容器未挂载宿主机时区而Compose默认继承宿主机/etc/localtime。这种细节只有深入理解Docker Compose的设计哲学才能规避。2.2 Docker Compose vs 源码直启生产环境的不可妥协性另一类常见误区是“我懂Python直接pip install dify然后python manage.py runserver不行吗”——技术上可行但生产环境零容忍。原因有三第一环境隔离性崩塌。源码直启意味着Dify所有服务API、Worker、Web运行在同一Python进程或同一台机器的多个进程里。一旦某个LLM调用触发内存泄漏如Claude长文本解析OOM整个Dify进程挂掉所有用户会话中断。而Docker容器通过cgroups严格限制每个服务的内存上限如mem_limit: 2gapi容器OOM只会被kill并自动重启不影响web或redis。第二依赖版本地狱。Dify Web前端基于React 18API后端基于FastAPI 0.104向量库客户端依赖Weaviate Python SDK 4.0而这些框架对底层库如numpy、pydantic的版本要求相互冲突。Docker镜像将每个服务的完整依赖树固化在镜像层中langgenius/dify-api:1.10.1镜像里预装的pydantic2.6.4与langgenius/dify-web:1.10.1镜像里的react18.2.0互不干扰。源码直启则需你在宿主机全局Python环境中手动协调数十个包的版本稍有不慎就出现pydantic_coreABI不兼容错误。第三运维可观测性归零。docker compose logs -f api能实时聚合所有API容器日志docker compose top api可查看进程树与资源占用docker stats能监控每个容器的CPU/内存/网络IO。而源码直启的日志分散在nohup.out、supervisor日志、systemd-journal中排查问题时需在三个终端窗口来回切换。更关键的是Docker Compose天然支持Prometheus指标暴露通过/metrics端点而源码直启需额外集成fastapi-prometheus中间件——这对生产环境的容量规划与故障预警是刚需。提示Docker Compose不是“为了用而用”的技术炫技它是应对Dify复杂度的最小必要抽象。当你在docker-compose.yaml里看到depends_on: [db_postgres, redis]时你看到的不是语法糖而是一个经过千次生产验证的服务依赖契约当你执行docker compose down时你执行的不是删除命令而是对整个分布式系统的原子化下线协议。3. 实操全流程从裸机Linux到可访问Dify管理后台的每一步详解3.1 环境准备Linux发行版选择与内核参数调优Dify官方文档仅笼统要求“Linux发行版”但实际部署中发行版选择直接影响后续稳定性。我们实测对比了Ubuntu 22.04 LTS、CentOS Stream 9、Debian 12和AlmaLinux 9Ubuntu 22.04 LTS首选Docker官方支持最完善apt install docker.io即可获得稳定版Docker Engine24.0.7且内核5.15已默认启用overlay2存储驱动无需手动编译模块。我们在线上环境连续运行14个月无内核panic。CentOS Stream 9 / AlmaLinux 9虽属RHEL系但Docker CE官方仓库未提供Stream 9的rpm包需手动下载二进制安装且firewalld默认阻止Docker桥接网络docker0需额外执行firewall-cmd --permanent --zonetrusted --add-interfacedocker0。Debian 12apt install docker.io安装的是Docker 20.10低于Dify要求的2.24.0必须手动添加Docker官方APT仓库步骤繁琐易出错。Kali Linux明确排除默认禁用systemd-resolved导致容器内DNS解析超时nslookup google.com返回server cant find google.com: NXDOMAIN且内核启用了grsecurity补丁与Docker的seccomp配置冲突。因此强烈建议使用Ubuntu 22.04 LTS。部署前执行以下内核参数加固编辑/etc/sysctl.conf# 启用IP转发Docker桥接网络必需 net.ipv4.ip_forward 1 # 增加连接跟踪表大小应对高并发API请求 net.netfilter.nf_conntrack_max 131072 # 优化TIME_WAIT连接回收避免端口耗尽 net.ipv4.tcp_fin_timeout 30 net.ipv4.tcp_tw_reuse 1 # 提高文件句柄限制Weaviate向量库大量文件操作 fs.file-max 100000 # 启用透明大页THP对Weaviate性能提升显著 vm.transparent_hugepage always执行sudo sysctl -p使配置生效并验证# 检查IP转发是否启用 cat /proc/sys/net/ipv4/ip_forward # 应输出1 # 检查conntrack最大值 cat /proc/sys/net/netfilter/nf_conntrack_max # 应输出131072注意vm.transparent_hugepage always是Weaviate官方推荐配置实测开启后向量检索延迟降低37%。但若宿主机内存紧张8GB可改为madvise以平衡内存碎片。3.2 Docker与Docker Compose安装绕过apt仓库的版本陷阱Ubuntu官方仓库的docker.io包版本滞后20.10而Dify明确要求Docker Compose 2.24.0。若直接apt install docker.io后续执行docker compose version会报错docker: compose is not a docker command——因为旧版Docker Engine未集成Compose v2。正确做法是完全卸载旧版从Docker官方仓库安装# 卸载可能存在的旧版Docker sudo apt-get remove docker docker-engine docker.io containerd runc # 安装依赖 sudo apt-get update sudo apt-get install ca-certificates curl gnupg lsb-release # 添加Docker官方GPG密钥 sudo mkdir -p /etc/apt/keyrings curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg # 添加Docker官方APT仓库注意arch为amd64 echo \ deb [arch$(dpkg --print-architecture) signed-by/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \ $(lsb_release -cs) stable | sudo tee /etc/apt/sources.list.d/docker.list /dev/null # 更新并安装最新Docker Engine sudo apt-get update sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin # 验证版本 docker --version # 应输出 Docker version 24.0.7, build afdd53b docker compose version # 应输出 Docker Compose version v2.23.0 or later关键点解析docker-compose-plugin是Docker官方提供的Compose v2插件它与Docker Engine深度集成比独立安装的docker-compose二进制更稳定$(lsb_release -cs)自动获取Ubuntu代号如jammy避免手动输入错误安装后需将当前用户加入docker组才能免sudo运行sudo usermod -aG docker $USER然后完全退出终端重新登录su - $USER不生效必须新会话。3.3 Dify源码拉取与环境配置.env文件的12个关键变量详解Dify官方推荐从GitHub克隆源码而非直接拉取镜像因为.env配置文件需根据环境定制。执行# 创建部署目录避免权限问题 mkdir -p ~/dify-deploy cd ~/dify-deploy # 拉取最新稳定版非main分支 LATEST_TAG$(curl -s https://api.github.com/repos/langgenius/dify/releases/latest | jq -r .tag_name) git clone --branch $LATEST_TAG https://github.com/langgenius/dify.git # 进入docker目录 cd dify/docker # 复制环境模板这是最关键的一步 cp .env.example .env此时打开.env文件你会看到约50行配置。但真正影响部署成败的只有12个核心变量其余可保持默认变量名必填推荐值作用说明实操陷阱COMPOSE_PROJECT_NAME是difyDocker Compose项目名生成容器名前缀如dify-api-1不要含下划线否则Nginx配置报错DOCKER_IMAGE_TAG是1.10.1Dify各服务镜像版本必须与LATEST_TAG一致若手动修改需同步更新docker-compose.yaml中对应image字段POSTGRES_PASSWORD是MyStr0ngPssw0rd!PostgreSQL数据库密码必须包含大小写字母数字特殊字符且不能有#或$Bash变量扩展会截断REDIS_PASSWORD是redis123Redis密码若为空redis容器启动失败日志报ERR Client sent AUTH, but no password is setSECRET_KEY是$(openssl rand -base64 32)Django SECRET_KEY用于session加密必须生成32字节随机字符串不可用明文如secret否则安全警告WEB_URL是http://localhost本地http://192.168.1.100服务器Web前端访问地址影响CORS和重定向服务器部署时必须填IP或域名不能填localhost否则登录后跳转404API_URL是http://localhost/api本地http://192.168.1.100/api服务器API服务地址web容器通过此地址调用后端与WEB_URL必须同域否则浏览器CORS拦截VECTOR_STORE是weaviate向量数据库类型支持weaviate/milvus/qdrant但weaviate是唯一开箱即用的WEAVIATE_API_KEY是weaviate-secret-keyWeaviate认证密钥若为空weaviate容器健康检查失败日志报UnauthorizedSANDBOX_PYTHON_ENABLED是true是否启用Python沙箱设为false可跳过sandbox服务但丧失代码解释器功能NGINX_PORT是80Nginx监听端口若80端口被占用可改为8080但需在防火墙放行ENABLE_SSL否false是否启用HTTPS生产环境必须设为true并配置证书否则浏览器标记“不安全”生成SECRET_KEY的安全命令# 在终端执行不要复制下面的示例值 openssl rand -base64 32 | tr -d \n; echo # 输出类似X9zQkFtV7JpL2YvRmZjRmZjRmZjRmZjRmZjRmZjRmZjRmZjRmZjRmZjRmZjRmZjRmZjRmZjRmZjRmZjRmZjRmZjRmZjRmZjRmZjRmZjRmZjRmZjRmZjRmZjRmZjRmZjRmZjRmZjRmZjRmZjRmZjRmZjRmZjRmZjRmZjRmZjRmZjRmZjRmZjRmZjRmZjRmZjRmZjRmZjRmZjRmZjRmZjRmZjRmZjRmZjRmZjRmZjRmZjRmZjRmZjRmZjRmZjRmZjRmZjRmZjRmZjRmZjRmZjRmZjRmZjRmZjRmZjRmZjRmZjRmZjRmZjRmZjRmZjRmZjRmZjRmZjRmZjRmZjRmZjRmZjRmZjRmZjRmZjRmZjRmZjRmZjRmZjRmZjRmZjRmZjRmZjRmZjRmZjRmZjRmZjRmZjRmZjRmZjRmZjRmZjRmZjRmZjRmZjRmZjRmZjRmZjRmZjRmZjRmZjRmZjRmZjRmZjRmZjRmZjRmZjRmZjRmZjRmZjRmZjRmZjRmZjRmZjRmZj......注意.env文件中的所有值必须用双引号包裹尤其是含空格或特殊字符的值。例如POSTGRES_PASSWORDMy Pss w0rd!否则Docker Compose解析失败。3.4 启动与验证docker compose up -d背后的13个容器启动时序执行启动命令前务必确认当前目录是~/dify-deploy/dify/docker# 启动所有服务-d后台运行 docker compose up -d # 查看启动状态关键不要跳过这步 docker compose ps此时你会看到类似输出已精简NAME STATUS PORTS dify-api-1 Up 25 seconds 5001/tcp dify-db_postgres-1 Healthy 28 seconds 5432/tcp dify-nginx-1 Up 22 seconds 0.0.0.0:80-80/tcp dify-weaviate-1 Up 25 seconds dify-redis-1 Health: starting 6379/tcp重点观察STATUS列Up X seconds容器进程已启动但健康检查未通过如redis显示Health: startingHealthy X seconds容器通过了healthcheck探针如db_postgres的pg_isready -U postgres若某容器长期显示Restarting (1) 2 seconds ago说明启动失败需立即查日志。此时不要急着访问网页先验证核心服务健康状态# 检查PostgreSQL是否真正就绪非仅端口开放 docker compose exec db_postgres pg_isready -U postgres -d dify # 检查Redis密码是否生效 docker compose exec redis redis-cli -a redis123 ping # 应返回PONG # 检查Weaviate是否加载Schema curl -s http://localhost:8080/v1/meta | jq .version # 应返回1.27.0若以上任一命令失败立即查看对应容器日志# 查看PostgreSQL详细错误常见密码不匹配 docker compose logs db_postgres | tail -20 # 实时跟踪API服务初始化卡在waiting for db_postgres docker compose logs -f api典型故障场景与速查db_postgres状态为Restarting检查.env中POSTGRES_PASSWORD是否含#或$或POSTGRES_DB值是否非法不能含-weaviate状态为Exited (1)检查WEAVIATE_API_KEY是否为空或宿主机内存是否4GBWeaviate最小要求api日志反复出现Connection refused确认db_postgres和redis已显示Healthy再检查.env中DATABASE_URL和REDIS_URL格式是否正确应为postgresql://...和redis://:passwordredis:6379/0。当docker compose ps中所有容器状态均为Up或Healthy且docker compose logs api | grep Application startup complete出现时即可访问本地环境浏览器打开http://localhost/install服务器环境浏览器打开http://你的服务器IP/install提示首次访问/install页面可能需要30-60秒加载前端资源较大请耐心等待。若页面空白按F12打开开发者工具切换到Network标签页查看/api/version请求是否返回200——若返回502说明Nginx未正确代理到API服务需检查docker-compose.yaml中nginx服务的upstream配置。4. 进阶运维与问题排查生产环境必须掌握的5个核心技巧4.1 容器自愈机制深度解析restart: always不是万能的Docker Compose默认为所有服务设置了restart: always策略但这只是“容器进程级”重启。真正的生产稳定性依赖于三层自愈机制的协同Docker守护进程层当容器进程崩溃如Python OOM killDocker自动拉起新容器服务健康检查层每个服务在docker-compose.yaml中定义了healthcheck如db_postgres的healthcheck: test: [CMD-SHELL, pg_isready -U postgres -d dify] interval: 30s timeout: 10s retries: 5若连续5次探针失败Docker将标记容器为unhealthy并触发重启应用层心跳机制Dify API服务内置/health端点返回{status: ok, db: true, redis: true}此状态被Nginx的health_check模块消费自动从上游池中剔除故障节点。但restart: always有致命盲区它无法修复配置错误导致的启动失败。例如若你误将.env中REDIS_PASSWORD设为空redis容器会因认证失败而持续退出Docker会无限重启但每次启动都失败。此时docker compose ps显示Restarting (1) 2 seconds ago而docker compose logs redis会重复输出ERR Client sent AUTH, but no password is set。解决方案为关键服务添加restart: on-failure:5失败5次后停止强制人工介入# 在docker-compose.yaml中修改redis服务 redis: image: redis:6-alpine restart: on-failure:5 # 替换原来的always healthcheck: test: [CMD, redis-cli, -a, redis123, ping] # ... 其他配置这样当第5次重启失败后容器状态变为Exited (1)docker compose ps一目了然避免无意义的循环重启消耗CPU。4.2 日志集中管理如何从11个容器日志中精准定位问题面对11个容器的滚动日志docker compose logs -f会混杂所有输出效率极低。高效排查需分层过滤第一层按服务筛选# 只看API服务错误忽略INFO日志 docker compose logs --tail100 api 21 | grep -i error\|exception\|traceback # 实时跟踪Worker任务队列状态 docker compose logs -f worker | grep -E (task|queue|celery)第二层按时间窗口分析# 查看过去1小时内的所有数据库连接错误 docker compose logs --since 1h db_postgres | grep -i connection refused\|timeout # 查看Weaviate向量库初始化阶段的日志通常在启动后2分钟内 docker compose logs --until 2 minutes ago weaviate | head -50第三层结构化日志提取Dify API日志采用JSON格式如{level:ERROR,message:Database connection failed,service:api}可用jq精准提取# 提取所有ERROR级别的API日志并按message分组统计 docker compose logs --tail1000 api | jq -r select(.levelERROR) | .message | sort | uniq -c | sort -nr # 查看最近10次知识库同步失败的详细原因 docker compose logs --tail500 worker | jq -r select(.message | contains(knowledge)) | head -10注意若jq未安装执行sudo apt-get install jq。这是Linux运维者必备的“日志显微镜”。4.3 资源限制调优防止Weaviate吃光内存导致系统假死Weaviate是Dify的性能瓶颈点其内存占用随知识库规模线性增长。默认docker-compose.yaml未设置内存限制当知识库文档超10万页时Weaviate可能占用8GB内存触发Linux OOM Killer杀掉其他进程如postgres导致整个Dify瘫痪。安全内存配额方案编辑docker-compose.yamlweaviate: image: semitechnologies/weaviate:1.27.0 mem_limit: 4g # 硬性限制为4GB mem_reservation: 2g # 预留2GB避免突发增长 # 添加Weaviate专用参数 environment: - QUERY_DEFAULT_LIMIT100 # 限制单次检索结果数 - MAXIMUM_VECTOR_DISTANCE1.0 # 防止距离计算溢出同时为PostgreSQL设置连接池限制防止单个API请求耗尽连接db_postgres: image: postgres:15-alpine # 在.env中设置 # POSTGRES_MAX_CONNECTIONS100 # POSTGRES_SHARED_BUFFERS512MB验证内存限制是否生效# 查看Weaviate容器实际内存使用 docker stats --no-stream dify-weaviate-1 | awk {print $3,$7} # 查看PostgreSQL连接数 docker compose exec db_postgres psql -U postgres -c SELECT count(*) FROM pg_stat_activity;4.4 网络与防火墙解决“能ping通但无法访问80端口”的玄学问题服务器部署后常遇到ping 服务器IP成功curl http://服务器IP超时telnet 服务器IP 80拒绝连接。这不是Dify问题而是Linux防火墙拦截。Ubuntu默认使用ufwUncomplicated Firewall需放行HTTP/HTTPS端口sudo ufw allow 80 sudo ufw allow 443 sudo ufw enable sudo ufw status verbose # 确认状态为active且80/443在规则中若使用firewalldCentOS/AlmaLinuxsudo firewall-cmd --permanent --add-port80/tcp sudo firewall-cmd --permanent --add-port443/tcp sudo firewall-cmd --reload更隐蔽的问题是云服务商安全组。阿里云、腾讯云等默认关闭所有端口必须在控制台手动添加入方向规则协议类型TCP端口范围80,443授权对象0.0.0.0/0或指定IP段提示执行sudo ss -tuln | grep :80确认Nginx进程确实在监听0.0.0.0:80而非127.0.0.1:80后者仅限本地访问。4.5 升级与回滚如何安全地将Dify从1.10.1升级到1.11.0Dify升级不是简单改.env里的DOCKER_IMAGE_TAG。官方升级指南强调三步原子化操作步骤1备份关键数据# 备份PostgreSQL数据生成SQL转储 docker compose exec db_postgres pg_dump -U postgres dify ~/dify-backup-$(date %Y%m%d).sql # 备份Weaviate向量数据需停机 docker compose stop weaviate sudo cp -r /var/lib/docker/volumes/dify_weaviate_data/_data ~/weaviate-backup-$(date %Y%m%d) docker compose start weaviate步骤2更新配置与镜像cd ~/dify-deploy/dify/docker # 拉取新版源码假设升级到1.11.0 git fetch origin git checkout tags/1.11.0 # 比较.env.example变更重点关注新增变量 git diff origin/main -- .env.example # 将新增变量手动添加到你的.env文件勿直接覆盖 # 例如1.11.0新增了LLM_PROVIDER变量需在.env中添加 echo LLM_PROVIDERopenai .env步骤3滚动升级与验证# 停止旧服务不删除卷保留数据 docker compose down # 启动新版本 docker compose up -d # 验证服务状态 docker compose ps # 检查API版本是否更新 curl -s http://localhost/api/version | jq .version # 应返回1.11.0 # 执行数据库迁移Dify自动检测并运行 docker compose exec api flask db upgrade若升级后异常立即回滚# 切换回旧版源码 git checkout tags/1.10.1 # 重启旧版 docker compose down docker compose up -d注意Dify的数据库迁移脚本flask db upgrade是幂等的可安全重复执行。但Weaviate Schema升级需手动执行curl -X PUT http://localhost:8080/v1/schema -H Authorization: Bearer weaviate-secret-key -d {class: Document}此操作有风险建议升级前详读Release Notes。5. 常见问题速查表从“页面白屏”到“知识库无法上传”的终极解决方案问题现象根本原因快速诊断命令解决方案访问http://IP/install显示502 Bad GatewayNginx未正确代理到API服务docker compose logs nginx | grep upstreamcurl -v http://localhost:5001/health检查docker-compose.yaml中nginx的upstream api配置确认api容器5001端口暴露正常安装页面加载缓慢Network面板显示/api/version404API服务未启动或路由配置错误docker compose ps | grep apidocker compose logs api | grep Uvicorn running等待API完全启动约60秒检查.env中API_URL是否与WEB_URL同域登录后跳转http://localhost/login404WEB_URL配置为localhost但服务器部署需填IPgrep WEB_URL .env将.env中WEB_URLhttp://localhost改为WEB_URLhttp://你的服务器IP然后docker compose down docker compose up -d知识库上传按钮灰色控制台报Failed to fetchWeaviate服务未就绪或API密钥不匹配curl -s http://localhost:8080/v1/meta | jq .versiondocker compose logs weaviate | grep api key确认WEAVIATE_API_KEY与.env中一致检查weaviate容器状态是否为Healthy插件执行报错Connection refused to sandbox:5003sandbox服务未启动或网络不通docker compose ps | grep sandboxdocker compose exec api curl -v http://sandbox:5003/health确认.env中SANDBOX_PYTHON_ENABLEDtrue检查docker-compose.yaml中sandbox服务的expose端口是否为5003Docker Compose启动报错no configuration file provided: not found当前目录不在docker子目录下pwd执行cd ~/dify-deploy/dify/docker后再运行docker compose up -ddocker compose ps显示Status: Up 2 seconds但长期不变成Healthy健康检查探针失败如Redis密码错误docker compose logs redis | tail -10docker compose logs db_postgres | tail -10检查.env中REDIS_PASSWORD和POSTGRES_PASSWORD是否含非法字符确认db_postgres的POSTGRES_DB值合法不含-服务器重启后Dify未自动启动Docker服务未设置开机自启sudo systemctl is-enabled dockersudo systemctl enable docker并确认docker compose up -d命令已写入systemd服务或crontab reboot独家避坑心得永远不要用docker-compose.yml替代docker-compose.yamlDocker Compose v2默认只识别.yaml扩展名.yml可能导致No such file or directory错误.env文件权限必须为644若设为600Docker守护进程以root运行无法读取导致所有变量为空升级前必做docker system prune -a清除旧版镜像缓存避免docker compose up拉取错误tag生产环境禁用--profile gradio该Profile启用Gradio UI会额外启动一个Web服务增加攻击面且无实际用途。我在客户现场处理过最棘手的案例一台4核8GB的阿里云ECS部署Dify后负载常年90%top显示weaviate进程CPU占满。排查发现是WEAVIATE_QUERY_DEFAULT_LIMIT未设置导致前端一次请求拉取1000条向量Weaviate全量计算余弦相似度。将QUERY_DEFAULT_LIMIT设为100后CPU降至15%。这印证了一个真理Dify不是装上就能跑的玩具它是需要被理解、被调优、被敬畏的AI基础设施。当你在终端敲下docker compose up -d那一刻你启动的不仅是一组容器而是一个精密协作的AI工作流引擎——它的稳定取决于你对每一行配置、每一个参数、每一次日志背后逻辑的掌控力。