Dify本地部署全解析:Docker Compose安装原理与排错实战
2026/7/16 3:43:12 网站建设 项目流程

1. 项目概述:这不是一次普通安装,而是一场与现代AI应用架构的初次交锋

“Dify学习笔记——从0开始到发疯-1 安装”,光看标题就带着一股真实得让人头皮发麻的烟火气。它不是教科书里温吞水式的“第一步、第二步”,而是记录了一个普通人把Dify这个智能体平台从GitHub仓库拖进自己电脑、再亲手把它从一堆容器里“点火启动”的全过程。我本人就是那个“发疯”的人——在Windows上折腾WSL2,在Mac上重装三次Docker Desktop,在Ubuntu服务器上反复核对docker compose ps输出里那行刺眼的health: starting到底卡在哪儿。Dify本身是个开箱即用的低代码AI应用开发平台,但它的“开箱”过程,恰恰暴露了当前AI基础设施部署最真实的毛边:它不挑你用Python还是Node.js,但它死死咬住Docker Compose这个生态枢纽;它承诺“本地部署”,却默认要求你对容器网络、环境变量覆盖链、健康检查超时阈值这些底层逻辑有基本直觉。所以,这篇笔记的核心价值,从来不是教会你敲几行命令,而是帮你建立一套“诊断式安装思维”——当docker compose up -d跑完后页面打不开,你知道该先查nginx容器的日志,而不是立刻怀疑是不是自己手抖按错了回车;当你看到weaviate容器状态是Up 15 seconds但没标healthy,你能立刻意识到这和向量数据库的初始化耗时有关,而不是慌忙去重装PostgreSQL。Dify安装的本质,是一次微型DevOps实战沙盘:你既是开发者,也是运维,还是第一个用户。它要求你理解docker/.envdocker/envs/vectorstores/weaviate.env之间的优先级覆盖关系,就像理解公司里部门主管和CEO的签字权限;它逼你搞懂restart: alwaysdocker-compose.yml里的实际含义——不是“永远重启”,而是“只要进程退出就重启”,哪怕是因为内存溢出被Linux OOM Killer干掉。如果你正站在Dify门口,手里攥着一台刚清空的笔记本,或者一台阿里云新购的ECS实例,那么请记住:安装失败90%的原因,和Dify代码本身无关,而在于你本地Docker引擎的版本是否真的≥2.24.0(别信docker --version,要敲docker compose version)、你的.env文件里POSTGRES_PASSWORD有没有不小心多敲了一个空格、你的WSL2分配的内存是不是被Docker Desktop偷偷吃掉了大半。这不是玄学,是工程实践里最朴素的因果律。

2. 核心设计思路拆解:为什么必须用Docker Compose,而不是直接pip install?

2.1 Dify的架构基因决定了它无法“单体化”运行

很多人第一次接触Dify时会本能地想:“既然它是Python写的,能不能像Flask项目一样,pip install dify然后python app.py就跑起来?” 这个想法非常合理,但完全行不通。原因在于Dify从诞生第一天起,就不是一个单进程Web应用,而是一个典型的微服务协同体。我们来拆解一下docker compose up -d启动后实际跑起来的11个容器:

  • 5个核心服务api(处理所有HTTP请求和LLM调用)、worker(异步执行知识库索引、工作流任务)、worker_beat(Celery定时任务调度器)、web(React前端静态资源)、plugin_daemon(插件沙箱管理器);
  • 6个依赖组件db_postgres(结构化数据存储)、redis(缓存与任务队列中间件)、weaviate(向量数据库,专用于知识库语义检索)、nginx(反向代理与HTTPS终止)、ssrf_proxy(安全网关,防止大模型插件发起恶意内网请求)、sandbox(代码解释器沙箱,隔离执行用户提交的Python代码)。

这11个组件之间存在严格的依赖顺序和通信协议。比如api服务启动时,必须能连上db_postgres的5432端口并完成数据库迁移,否则直接崩溃退出;worker必须能从redis的6379端口消费任务队列;而web前端通过nginx反向代理,将/api/路径的请求转发给api容器的5001端口。这种强耦合、多进程、跨网络的架构,天然排斥“单体式”部署。你不可能用pip install把Weaviate向量数据库、PostgreSQL、Redis全打包进一个Python包里——它们是不同语言(Go、C、Rust)编译的独立二进制程序,需要各自的操作系统资源(内存、CPU、文件句柄)。Docker Compose在这里扮演的角色,远不止是“启动多个容器”这么简单。它本质上是一个声明式编排引擎:你用docker-compose.yml文件描述“我需要哪些服务、它们之间如何连接、各自的环境变量是什么、健康检查怎么定义”,然后docker compose up就自动帮你解决所有底层细节——创建专用网络docker_default让容器间用服务名互通(api可以直接ping db_postgres),挂载卷volumes确保PostgreSQL数据不随容器销毁而丢失,设置depends_onhealthcheck保证api只在db_postgres真正ready后才启动。这就像一个经验丰富的建筑队长,他不需要你懂钢筋怎么轧制、水泥怎么配比,你只需要告诉他“我要一栋三层楼,一楼是厨房(DB),二楼是客厅(API),三楼是卧室(WEB)”,他就能协调所有工种按时完工。而pip install,充其量只是给你递了一把螺丝刀,让你自己去拧紧每一颗螺栓。

2.2 Docker Compose vs. 手动Docker run:效率与可维护性的生死线

有人会问:“我手动写11条docker run命令,不也能达到同样效果吗?” 理论上可以,但实操中等于自断双臂。我们来对比一下两种方式的维护成本:

维护场景Docker Compose 方案手动 docker run 方案
启动全部服务docker compose up -d(1条命令)需要精确记忆并按依赖顺序执行11条命令,漏一条或顺序错,整个系统瘫痪
修改一个环境变量编辑docker/.env文件,docker compose down && docker compose up -d(2步)需要找到对应容器的docker run命令,修改-e KEY=VALUE参数,docker stop旧容器,再docker run新容器(至少5步,且极易遗漏)
查看所有服务状态docker compose ps(清晰表格,含状态、端口、健康度)docker ps(混杂所有容器,需grep dify过滤),再逐个docker inspect <container>查健康状态(11次操作)
日志排查docker compose logs -f api(实时跟踪API服务日志)docker logs -f <api_container_id>(需先`docker ps
升级到新版本git pull更新代码,docker compose downdocker compose up -d(3步)需手动拉取11个镜像(docker pull langgenius/dify-api:1.10.1等),再逐个docker stop+docker run(至少22步)

更致命的是,Dify官方发布的docker-compose.yml文件里,藏着大量精妙的工程设计。比如nginx服务的配置:

services: nginx: image: nginx:latest volumes: - ./nginx.conf:/etc/nginx/nginx.conf:ro - ./ssl:/etc/nginx/ssl:ro ports: - "80:80" - "443:443" depends_on: - web - api healthcheck: test: ["CMD", "curl", "-f", "http://localhost/healthz"] interval: 30s timeout: 10s retries: 3

这里depends_on只保证nginxwebapi容器创建后才启动,但不保证它们已就绪;真正的“就绪”由healthcheck兜底——curl http://localhost/healthz成功才算nginx健康。而这个/healthz端点,是由nginx.conf里定义的,它又反向代理到web容器的3000端口。这一整套环环相扣的依赖链,如果用手动docker run,你得自己写脚本去轮询每个容器的健康状态,再决定下一步启动谁,复杂度指数级上升。Docker Compose把这些都封装成了声明式语法,你只需关注“我要什么”,不用管“怎么实现”。这就是为什么所有主流AI基础设施(LangChain DevKit、LlamaIndex Playground、甚至OpenWebUI)都选择Docker Compose作为首选部署方案——它把分布式系统的混沌,压缩成了一份人类可读、可维护、可版本控制的YAML文件。

2.3 为什么Docker Desktop是Mac/Windows用户的唯一现实选择?

Linux用户很幸运,他们可以直接在宿主机上安装Docker Engine和Docker Compose,全程命令行搞定。但Mac和Windows用户面临一个根本性问题:Docker引擎本身是一个Linux内核程序,它无法直接在macOS(XNU内核)或Windows(NT内核)上原生运行。因此,Docker官方为这两个平台提供了Docker Desktop——一个集成了Linux虚拟机(HyperKit on Mac, WSL2 on Windows)、Docker Engine、Docker CLI、Docker Compose、Kubernetes集群的完整桌面套件。很多新手踩的第一个大坑,就是以为“安装了Docker Desktop就等于有了Docker Compose”,结果一敲docker compose version报错command not found。这是因为Docker Desktop有两个关键配置项:

  1. 启用Docker Compose V2:在Docker Desktop设置里,必须勾选“Use the new Docker Compose V2”(新版Docker Compose V2)。老版本的docker-compose(带横杠)已被废弃,Dify文档明确要求2.24.0+,而只有V2才支持docker compose(无横杠)这个子命令。
  2. WSL2集成(仅Windows):Windows用户必须启用WSL2,并在Docker Desktop设置中勾选“Use the WSL 2 based engine”。这是为了性能——Docker Desktop的Linux VM如果直接运行在Windows NT内核上,I/O性能极差,尤其是Dify启动时需要加载大量Node.js前端依赖和Python包,会慢到令人绝望。WSL2提供了一个轻量级的Linux内核,让Docker容器直接运行在Linux环境下,速度提升3倍以上。

我曾经在一台未启用WSL2的Windows 10机器上部署Dify,docker compose up -d后等了整整17分钟,weaviate容器还在health: startingdocker logs docker-weaviate-1显示它卡在向量索引初始化。切换到WSL2后,整个过程缩短到2分18秒。这不是玄学,是操作系统抽象层带来的真实性能鸿沟。所以,当你看到Dify文档里写着“Windows(启用WSL2)”,请务必把它当作一条硬性法规,而不是可选项。Docker Desktop不是Dify的“可选依赖”,而是Mac/Windows用户通向Dify世界的唯一合法签证。

3. 核心细节解析与实操要点:从克隆代码到第一个管理员账户

3.1 环境准备:硬件、软件、网络的三重校验清单

在敲下第一条命令前,请拿出一张纸,逐项核对以下清单。这不是形式主义,而是避免后续数小时无效调试的唯一捷径。

硬件层面(最容易被忽视的“隐形杀手”)

  • 内存(RAM):Dify官方文档写的是“>=4 GiB”,但这只是理论最小值。实测下来,weaviate向量数据库在初始化知识库时,峰值内存占用轻松突破6 GiB;postgres在处理大量工作流历史时,也会吃掉2 GiB以上。如果你的机器只有4 GiB物理内存,Docker Desktop会疯狂使用Swap(虚拟内存),导致整个系统卡死。强烈建议:最低8 GiB,推荐16 GiB。我在一台8 GiB内存的MacBook Pro上部署,Docker Desktop设置里将VM内存上限调到了6 GiB,留2 GiB给macOS系统,运行非常平稳。
  • CPU核心数:官方要求“>=2 Core”,但worker_beatworker两个服务都是CPU密集型。worker_beat要持续扫描Celery队列,worker要执行LLM推理(即使你用的是本地Ollama模型,也需CPU计算)。实测在2核机器上,docker compose ps会显示worker容器CPU占用率长期95%+,响应迟钝。建议:4核起步,8核更佳。
  • 磁盘空间:Dify镜像本身不大(langgenius/dify-api:1.10.1约800MB),但weaviate向量数据库和postgres数据卷会随使用时间指数级增长。一个中等规模的知识库(1000页PDF),向量索引可能占用5-10GB空间。建议:预留至少50GB空闲磁盘。

软件层面(版本陷阱无处不在)

  • Docker Desktop版本:必须≥4.27.0(此版本内置Docker Compose V2.24.0)。检查方法:打开Docker Desktop → Settings → General → 查看右下角版本号。如果低于此版本,请立即升级。旧版本的Compose V2存在一个致命Bug:在docker-compose.yml中定义的healthcheck超时时间会被忽略,导致weaviate等服务永远卡在health: starting。我曾为此浪费一整个下午,最后发现升级Docker Desktop后问题瞬间消失。
  • Git客户端:Dify安装的第一步是git clone,所以必须有Git。Windows用户推荐Git for Windows(官网下载),Mac用户用brew install git,Ubuntu用sudo apt install git关键点:克隆命令中包含--branch "$(curl -s https://api.github.com/repos/langgenius/dify/releases/latest | jq -r .tag_name)",这需要系统里同时有curljq。Ubuntu/Debian用户:sudo apt install curl jq;Mac用户:brew install curl jq;Windows用户:在Git Bash里,curl自带,jq需单独下载jq-win64.exe并加入PATH。
  • Python环境(仅用于本地开发,非部署必需):Dify的后端是Python(FastAPI),但生产部署完全走Docker镜像,你本地无需安装Python。网上很多教程误导人先装Python、再pip install dify,这是完全错误的路径。Dify的docker/.env文件里有一行PYTHONUNBUFFERED=1,这只是告诉容器内的Python进程不要缓冲日志,方便docker compose logs实时查看,和你宿主机的Python无关。请彻底忘记“Python安装”这个念头,除非你打算贡献代码。

网络层面(国内用户的心头之痛)

  • Docker Hub镜像拉取:Dify的docker-compose.yml里引用的镜像(如langgenius/dify-api:1.10.1postgres:15-alpine)都托管在Docker Hub上。国内直连Docker Hub,拉取速度可能低于10KB/s,甚至超时失败。解决方案只有两个:
    1. 配置Docker镜像加速器:这是最稳妥的方法。在Docker Desktop设置里(Mac/Windows)或/etc/docker/daemon.json(Linux),添加国内镜像源。我长期使用中科大的https://docker.mirrors.ustc.edu.cn,稳定可靠。配置后,docker pull postgres:15-alpine速度可达10MB/s。
    2. 使用代理(不推荐):虽然技术上可行,但Docker Desktop的代理设置极其繁琐,且容易和宿主机代理冲突,导致curl命令失效。对于安装阶段,镜像加速器是唯一值得投入时间的方案。

提示:在开始克隆前,先执行docker info,确认输出里有Server Version: 24.x.x(代表Docker Engine版本),再执行docker compose version,确认输出是Docker Compose version v2.24.7(或更高)。这两条命令都成功,才是真正的“万事俱备”。

3.2 克隆与配置:.env文件里的每一个字符都关乎成败

现在,让我们进入真正的实操环节。打开终端(Mac/Linux)或Git Bash(Windows),一步步来。

第一步:克隆代码

# 这条命令会自动获取最新Release的Tag名,并克隆对应分支 git clone --branch "$(curl -s https://api.github.com/repos/langgenius/dify/releases/latest | jq -r .tag_name)" https://github.com/langgenius/dify.git

这条命令看似简单,但背后有深意。Dify的main分支是开发分支,随时可能有未测试的代码。而releases/latest返回的是经过QA验证的稳定版Tag(如v1.10.1)。强制指定--branch,是为了确保你拿到的是一个确定的、可复现的版本。如果省略这一步,直接git clone https://github.com/langgenius/dify.git,你可能会克隆到一个正在重构中的main分支,导致docker-compose.yml文件结构不兼容,docker compose up直接报错。

第二步:进入Docker目录并复制环境文件

cd dify/docker cp .env.example .env

这是最关键的一步,也是新手最容易翻车的地方。.env.example是一个模板文件,里面充满了占位符,比如:

# Database POSTGRES_HOST=db_postgres POSTGRES_PORT=5432 POSTGRES_DB=dify POSTGRES_USER=postgres POSTGRES_PASSWORD=your_password_here

cp .env.example .env只是复制了模板,你必须手动编辑.env文件,把所有your_password_here替换成你自己的强密码。我见过太多人卡在这一步:他们复制完文件,没改密码,就直接docker compose up。结果db_postgres容器启动成功,但api容器因为连不上数据库,日志里疯狂刷psycopg2.OperationalError: FATAL: password authentication failed for user "postgres",而他们还在傻傻地刷新浏览器,以为是Nginx没配好。

注意:.env文件里的密码,必须和docker-compose.ymldb_postgres服务的environment部分完全一致。docker-compose.yml里有这样一段:

services: db_postgres: image: postgres:15-alpine environment: POSTGRES_DB: ${POSTGRES_DB} POSTGRES_USER: ${POSTGRES_USER} POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}

这里的${POSTGRES_PASSWORD},就是从.env文件里读取的。所以,.env文件不是可有可无的配置,而是整个Docker Compose编排的“中央密码本”。

第三步:关键环境变量详解(不只是密码)除了POSTGRES_PASSWORD.env里还有几个变量,直接决定Dify能否正常访问:

  • SECRET_KEY:这是Dify的加密密钥,用于签名Session Cookie、JWT Token等。必须修改!.env.example里给的是sk-xxx,这是明文泄露风险。生成一个强密钥的最简单方法:在Python环境中(任何Python 3.6+都行),运行:

    import secrets print(secrets.token_urlsafe(32))

    复制输出,粘贴到.env里替换SECRET_KEY=sk-xxx。这个密钥一旦设定,就不能再改,否则所有用户Session都会失效,需要重新登录。

  • S3_*系列变量(S3_ENDPOINT,S3_BUCKET_NAME,S3_ACCESS_KEY,S3_SECRET_KEY):如果你打算用对象存储(如阿里云OSS、腾讯云COS)来存知识库文件,才需要配置。对于纯本地部署,可以完全忽略,保持默认的S3_ENABLED=false即可。很多人误以为必须配S3,结果去申请云厂商密钥,反而增加了安全风险。

  • VECTOR_STORE:Dify支持多种向量数据库(Weaviate、Milvus、Qdrant)。.env.example默认是weaviate,这正是我们要用的。切勿随意改成其他值,除非你清楚知道如何配置对应的envs/vectorstores/xxx.env文件。Weaviate是目前社区最成熟、文档最全的选择。

3.3 启动与验证:读懂docker compose ps输出里的每一条信息

执行docker compose up -d后,你会看到类似这样的输出:

[+] Running 13/13 ✔ Network docker_ssrf_proxy_network Created 10.0s ✔ Network docker_default Created 0.1s ✔ Container docker-sandbox-1 Started 0.3s ✔ Container docker-db_postgres-1 Healthy 2.8s ✔ Container docker-web-1 Started 0.3s ✔ Container docker-redis-1 Started 0.3s ✔ Container docker-ssrf_proxy-1 Started 0.4s ✔ Container docker-weaviate-1 Started 0.3s ✔ Container docker-worker_beat-1 Started 3.2s ✔ Container docker-api-1 Started 3.2s ✔ Container docker-worker-1 Started 3.2s ✔ Container docker-plugin_daemon-1 Started 3.2s ✔ Container docker-nginx-1 Started 3.4s

这段输出的信息量极大,你需要学会“阅读”它:

  • CreatedvsStartedvsHealthyNetwork ... Created表示Docker网络已建好;Container ... Started表示容器进程已启动;Container ... Healthy(如db_postgres-1)表示该容器通过了healthcheck检测,真正就绪。weaviate-1显示Started而非Healthy,是完全正常的——Weaviate的健康检查(/v1/healthz)在它完成向量索引初始化前会返回503,所以它需要更长时间才能变Healthy

  • 端口映射(PORTS列)是访问入口docker compose ps的输出末尾有PORTS列,这是你访问Dify的唯一路径。重点关注:

    • docker-nginx-10.0.0.0:80->80/tcp,表示宿主机的80端口映射到了容器的80端口。所以你在浏览器输入http://localhost,流量会先到nginx,再被它反向代理。
    • docker-api-15001/tcp,这个端口没有对外映射,意味着你不能直接访问http://localhost:5001。它只对同网络下的nginx容器开放(nginx通过http://api:5001访问它)。
    • docker-web-13000/tcp,同样没有对外映射,只对nginx开放(nginx通过http://web:3000获取前端资源)。

所以,Dify的访问链路是:浏览器 -> 宿主机80端口 -> nginx容器 -> (内部) api:5001 或 web:3000。这是一个标准的反向代理模式,nginx是唯一的流量入口,也是安全屏障。

第四步:验证服务健康度docker compose up -d只是启动,不代表一切OK。必须用以下命令逐层验证:

  1. 检查所有容器状态

    docker compose ps

    确保所有容器的STATUS列是Up X secondsUp X minutes (healthy)。如果看到Exited (1) 2 minutes ago,说明该容器启动失败,需要查日志。

  2. 查看关键容器日志(按优先级)

    • 最高优先级:nginx
      docker compose logs -f nginx
      如果nginx日志里出现connect() failed (111: Connection refused) while connecting to upstream,说明nginx找不到apiweb容器。这通常是因为.env文件里POSTGRES_PASSWORD错了,导致api容器启动失败,进而nginx无法连接上游。
    • 次高优先级:api
      docker compose logs -f api
      如果api日志里有psycopg2.OperationalError,100%是数据库密码错误;如果有ConnectionRefusedError: [Errno 111] Connection refused指向redisweaviate,说明依赖服务没起来。
    • 第三优先级:weaviate
      docker compose logs -f weaviate
      Weaviate启动慢是常态。日志里如果一直刷Starting Weaviate...,耐心等待2-5分钟。如果超过10分钟还在刷,可能是内存不足,需要增加Docker Desktop的VM内存。
  3. 手动测试API连通性(绕过Nginx): 如果浏览器打不开,但docker compose ps显示一切正常,可以跳过nginx,直接测试api容器:

    # 进入api容器内部 docker compose exec api sh # 在容器内,用curl测试自己 curl -v http://localhost:5001/health # 应该返回 {"status":"ok"} # 再测试连接postgres curl -v http://db_postgres:5432 # 如果返回"PostgreSQL"字样,说明数据库连通

4. 实操过程与核心环节实现:从“发疯”到“看到安装页面”的完整旅程

4.1 全流程实操记录:以一台全新Ubuntu 22.04服务器为例

为了彻底还原真实场景,我将用一台全新的阿里云ECS(Ubuntu 22.04,4核8G,100G SSD)进行一次从零开始的部署,并记录每一步的命令、预期输出、以及我当时的思考。

Step 0:初始化系统(5分钟)

# 更新系统 sudo apt update && sudo apt upgrade -y # 安装基础工具 sudo apt install -y curl wget git jq unzip # 关闭防火墙(生产环境请谨慎,此处仅为演示) sudo ufw disable

思考:Ubuntu默认防火墙(UFW)会阻止80端口,如果你不关它,后面http://your_server_ip会打不开。生产环境应改为sudo ufw allow 80

Step 1:安装Docker Engine & Docker Compose(10分钟)

# 卸载旧版本(如有) sudo apt remove docker docker-engine docker.io containerd runc # 设置Docker仓库 sudo apt install -y ca-certificates curl gnupg lsb-release curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null # 安装Docker sudo apt update sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin # 验证 sudo docker run hello-world sudo docker compose version

关键点:Ubuntu官方仓库的docker-compose版本太老(v1.x),必须用Docker官方仓库安装docker-compose-plugin,它提供docker compose(v2)命令。sudo docker compose version输出必须是v2.24.0+

Step 2:克隆Dify并配置(3分钟)

# 创建工作目录 mkdir -p ~/dify-deploy && cd ~/dify-deploy # 克隆(注意:这里用curl + jq,确保获取最新版) git clone --branch "$(curl -s https://api.github.com/repos/langgenius/dify/releases/latest | jq -r .tag_name)" https://github.com/langgenius/dify.git cd dify/docker cp .env.example .env # 编辑.env文件(用nano,新手友好) nano .env

nano编辑器里,我做了三件事:

  1. POSTGRES_PASSWORD=your_password_here改为POSTGRES_PASSWORD=MyS3cur3P@ssw0rd!(一个强密码)。
  2. SECRET_KEY=sk-xxx替换为SECRET_KEY=JZqFk7vT9mR2xWnY4pL8cVbN5sH1jQgE6iUoA3tD0fI7yK9lM2zX5wB8vC4nR6p(用Python生成的32字节密钥)。
  3. 确认VECTOR_STORE=weaviate未被改动。

思考:nano是Ubuntu默认的文本编辑器,比vim对新手更友好。保存退出是Ctrl+OEnterCtrl+X

Step 3:启动并监控(15分钟,这是最煎熬的时刻)

# 启动! sudo docker compose up -d # 立即检查状态 sudo docker compose ps

输出显示所有容器都是Up X seconds,但weaviate-1redis-1的状态是Up 15 seconds (health: starting),这很正常。我喝了一杯咖啡,5分钟后再次执行:

sudo docker compose ps

这次,weaviate-1变成了Up 6 minutes (healthy)redis-1也变成了healthy。成功!

Step 4:访问安装页面(1分钟)在浏览器中输入服务器的公网IP地址:http://123.45.67.89/install(用你的真实IP替换)。页面加载出来,一个简洁的表单,要求填写:

  • Email:管理员邮箱(如admin@example.com
  • Password:管理员密码(至少8位,含大小写字母和数字)
  • Confirm Password:确认密码

提交后,页面跳转到http://123.45.67.89,出现Dify的登录界面。输入刚才设置的邮箱和密码,登录成功!首页上赫然显示“Welcome to Dify!”。那一刻,所有的等待和焦虑都烟消云散——你刚刚亲手点亮了一个AI应用平台。

4.2 常见“发疯”场景与即时修复方案

在上述实操中,我刻意跳过了几个最常让人抓狂的错误。现在,我把它们整理成一份“急救手册”,当你遇到时,可以立刻对照解决。

场景一:docker compose up -d后,docker compose ps显示api-1状态是Exited (1)

  • 诊断docker compose logs api | tail -20
  • 典型日志psycopg2.OperationalError: FATAL: password authentication failed for user "postgres"
  • 原因.env文件里的POSTGRES_PASSWORDdocker-compose.ymldb_postgres服务的environment不匹配,或者db_postgres容器本身没启动。
  • 修复
    1. sudo docker compose logs db_postgres | tail -10,确认db_postgres是否在运行。
    2. 如果db_postgres也在Exited,检查.envPOSTGRES_PASSWORD是否有不可见字符(如Windows换行符\r\n)。用cat -A .env | grep POSTGRES_PASSWORD查看。
    3. 修改.env,确保密码正确,然后sudo docker compose down && sudo docker compose up -d

场景二:浏览器访问http://localhost/install,显示This site can’t be reachedERR_CONNECTION_REFUSED

  • 诊断sudo docker compose ps,看nginx-1PORTS列是否是0.0.0.0:80->80/tcp
  • 原因:80端口被其他程序(如Apache、Nginx)占用,或者防火墙阻止。
  • 修复
    1. sudo ss -tulpn | grep ':80',查看哪个进程占用了80端口。如果是nginxapache2sudo systemctl stop nginx && sudo systemctl disable nginx
    2. sudo ufw status,如果显示Status: active,则sudo ufw allow 80
    3. 如果是Windows,检查Docker Desktop设置里“Expose daemon on tcp://localhost:2375 without TLS”是否被勾选(这会导致端口冲突),取消勾选。

场景三:安装页面能打开,但提交管理员信息后,页面卡在加载,或提示Network Error

  • 诊断:浏览器按F12打开开发者工具 →Network标签页 → 刷新页面 → 看哪个XHR请求失败(通常是POST /api/console/install)。
  • 原因api容器无法连接redisweaviate,导致安装流程卡在创建初始用户。
  • 修复
    1. sudo docker compose logs api | grep -i "redis\|weaviate",看是否有连接拒绝错误。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询