Dify本地部署全解析:Docker Compose安装原理与排错实战

Dify本地部署全解析:Docker Compose安装原理与排错实战
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/.env和docker/envs/vectorstores/weaviate.env之间的优先级覆盖关系就像理解公司里部门主管和CEO的签字权限它逼你搞懂restart: always在docker-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 install2.1 Dify的架构基因决定了它无法“单体化”运行很多人第一次接触Dify时会本能地想“既然它是Python写的能不能像Flask项目一样pip install dify然后python app.py就跑起来” 这个想法非常合理但完全行不通。原因在于Dify从诞生第一天起就不是一个单进程Web应用而是一个典型的微服务协同体。我们来拆解一下docker compose up -d启动后实际跑起来的11个容器5个核心服务api处理所有HTTP请求和LLM调用、worker异步执行知识库索引、工作流任务、worker_beatCelery定时任务调度器、webReact前端静态资源、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_on和healthcheck保证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 -d1条命令需要精确记忆并按依赖顺序执行11条命令漏一条或顺序错整个系统瘫痪修改一个环境变量编辑docker/.env文件docker compose down docker compose up -d2步需要找到对应容器的docker run命令修改-e KEYVALUE参数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 -d3步需手动拉取11个镜像docker pull langgenius/dify-api:1.10.1等再逐个docker stopdocker 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只保证nginx在web和api容器创建后才启动但不保证它们已就绪真正的“就绪”由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内核程序它无法直接在macOSXNU内核或WindowsNT内核上原生运行。因此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有两个关键配置项启用Docker Compose V2在Docker Desktop设置里必须勾选“Use the new Docker Compose V2”新版Docker Compose V2。老版本的docker-compose带横杠已被废弃Dify文档明确要求2.24.0而只有V2才支持docker compose无横杠这个子命令。WSL2集成仅WindowsWindows用户必须启用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机器上部署Difydocker 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 环境准备硬件、软件、网络的三重校验清单在敲下第一条命令前请拿出一张纸逐项核对以下清单。这不是形式主义而是避免后续数小时无效调试的唯一捷径。硬件层面最容易被忽视的“隐形杀手”内存RAMDify官方文档写的是“4 GiB”但这只是理论最小值。实测下来weaviate向量数据库在初始化知识库时峰值内存占用轻松突破6 GiBpostgres在处理大量工作流历史时也会吃掉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_beat和worker两个服务都是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 gitUbuntu用sudo apt install git。关键点克隆命令中包含--branch $(curl -s https://api.github.com/repos/langgenius/dify/releases/latest | jq -r .tag_name)这需要系统里同时有curl和jq。Ubuntu/Debian用户sudo apt install curl jqMac用户brew install curl jqWindows用户在Git Bash里curl自带jq需单独下载jq-win64.exe并加入PATH。Python环境仅用于本地开发非部署必需Dify的后端是PythonFastAPI但生产部署完全走Docker镜像你本地无需安装Python。网上很多教程误导人先装Python、再pip install dify这是完全错误的路径。Dify的docker/.env文件里有一行PYTHONUNBUFFERED1这只是告诉容器内的Python进程不要缓冲日志方便docker compose logs实时查看和你宿主机的Python无关。请彻底忘记“Python安装”这个念头除非你打算贡献代码。网络层面国内用户的心头之痛Docker Hub镜像拉取Dify的docker-compose.yml里引用的镜像如langgenius/dify-api:1.10.1、postgres:15-alpine都托管在Docker Hub上。国内直连Docker Hub拉取速度可能低于10KB/s甚至超时失败。解决方案只有两个配置Docker镜像加速器这是最稳妥的方法。在Docker Desktop设置里Mac/Windows或/etc/docker/daemon.jsonLinux添加国内镜像源。我长期使用中科大的https://docker.mirrors.ustc.edu.cn稳定可靠。配置后docker pull postgres:15-alpine速度可达10MB/s。使用代理不推荐虽然技术上可行但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 BashWindows一步步来。第一步克隆代码# 这条命令会自动获取最新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_HOSTdb_postgres POSTGRES_PORT5432 POSTGRES_DBdify POSTGRES_USERpostgres POSTGRES_PASSWORDyour_password_herecp .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.yml中db_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_KEYsk-xxx。这个密钥一旦设定就不能再改否则所有用户Session都会失效需要重新登录。S3_*系列变量S3_ENDPOINT,S3_BUCKET_NAME,S3_ACCESS_KEY,S3_SECRET_KEY如果你打算用对象存储如阿里云OSS、腾讯云COS来存知识库文件才需要配置。对于纯本地部署可以完全忽略保持默认的S3_ENABLEDfalse即可。很多人误以为必须配S3结果去申请云厂商密钥反而增加了安全风险。VECTOR_STOREDify支持多种向量数据库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。必须用以下命令逐层验证检查所有容器状态docker compose ps确保所有容器的STATUS列是Up X seconds或Up X minutes (healthy)。如果看到Exited (1) 2 minutes ago说明该容器启动失败需要查日志。查看关键容器日志按优先级最高优先级nginxdocker compose logs -f nginx如果nginx日志里出现connect() failed (111: Connection refused) while connecting to upstream说明nginx找不到api或web容器。这通常是因为.env文件里POSTGRES_PASSWORD错了导致api容器启动失败进而nginx无法连接上游。次高优先级apidocker compose logs -f api如果api日志里有psycopg2.OperationalError100%是数据库密码错误如果有ConnectionRefusedError: [Errno 111] Connection refused指向redis或weaviate说明依赖服务没起来。第三优先级weaviatedocker compose logs -f weaviateWeaviate启动慢是常态。日志里如果一直刷Starting Weaviate...耐心等待2-5分钟。如果超过10分钟还在刷可能是内存不足需要增加Docker Desktop的VM内存。手动测试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服务器为例为了彻底还原真实场景我将用一台全新的阿里云ECSUbuntu 22.044核8G100G 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 Compose10分钟# 卸载旧版本如有 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 composev2命令。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编辑器里我做了三件事将POSTGRES_PASSWORDyour_password_here改为POSTGRES_PASSWORDMyS3cur3Pssw0rd!一个强密码。将SECRET_KEYsk-xxx替换为SECRET_KEYJZqFk7vT9mR2xWnY4pL8cVbN5sH1jQgE6iUoA3tD0fI7yK9lM2zX5wB8vC4nR6p用Python生成的32字节密钥。确认VECTOR_STOREweaviate未被改动。思考nano是Ubuntu默认的文本编辑器比vim对新手更友好。保存退出是CtrlO→Enter→CtrlX。Step 3启动并监控15分钟这是最煎熬的时刻# 启动 sudo docker compose up -d # 立即检查状态 sudo docker compose ps输出显示所有容器都是Up X seconds但weaviate-1和redis-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管理员邮箱如adminexample.comPassword管理员密码至少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_PASSWORD和docker-compose.yml中db_postgres服务的environment不匹配或者db_postgres容器本身没启动。修复sudo docker compose logs db_postgres | tail -10确认db_postgres是否在运行。如果db_postgres也在Exited检查.env里POSTGRES_PASSWORD是否有不可见字符如Windows换行符\r\n。用cat -A .env | grep POSTGRES_PASSWORD查看。修改.env确保密码正确然后sudo docker compose down sudo docker compose up -d。场景二浏览器访问http://localhost/install显示This site can’t be reached或ERR_CONNECTION_REFUSED诊断sudo docker compose ps看nginx-1的PORTS列是否是0.0.0.0:80-80/tcp。原因80端口被其他程序如Apache、Nginx占用或者防火墙阻止。修复sudo ss -tulpn | grep :80查看哪个进程占用了80端口。如果是nginx或apache2sudo systemctl stop nginx sudo systemctl disable nginx。sudo ufw status如果显示Status: active则sudo ufw allow 80。如果是Windows检查Docker Desktop设置里“Expose daemon on tcp://localhost:2375 without TLS”是否被勾选这会导致端口冲突取消勾选。场景三安装页面能打开但提交管理员信息后页面卡在加载或提示Network Error诊断浏览器按F12打开开发者工具 →Network标签页 → 刷新页面 → 看哪个XHR请求失败通常是POST /api/console/install。原因api容器无法连接redis或weaviate导致安装流程卡在创建初始用户。修复sudo docker compose logs api | grep -i redis\|weaviate看是否有连接拒绝错误。