
很多第一次部署Dify的朋友都会卡在同一个地方——不是容器起不来不是模型用不了而是docker/compose目录下那一堆.env变量让人头晕。我也见过不少人在群里问“为什么我改了端口不生效”“SECRET_KEY到底填什么”“数据库连接失败是哪里错了”。今天这篇就把Dify环境变量配置这件事彻底讲清楚从cp .env.example开始到你上线之后要防的几个坑一次说透。这篇内容适合谁看刚接触Dify想做本地部署的开发者正在规划生产环境但不确定哪些变量必须改的运维以及升级Dify版本时被新变量搞得一头雾水的朋友。我会把变量按职责拆开讲也会把真正的实操命令和排查思路放进来尽量让你对着屏幕就能解决自己的问题。1. 先搞懂Dify的.env这个文件到底在管什么1.1 为什么Dify要把这么多配置压进一个文件里Dify本质上不是一个单体应用而是由前端、API服务、Worker任务队列、Sandbox代码执行器、多个数据库和中间件组成的分布式服务栈。你用Docker Compose一键启动时看到的那些容器每个都需要知道“数据库在哪里”“Redis密码是多少”“向量库用什么”“存储要不要走S3”。如果每次部署都手动在Docker Compose里改几十个镜像配置维护成本会高得离谱。所以Dify的官方做法是把所有可变配置集中到一个.env文件里然后通过docker-compose.yaml里的env_file指令加载进去。这个文件就是整个部署的“总控台”。你在里面改一个变量重启容器所有相关服务就会按新配置运行。我见过很多人忽略了这一点直接去改docker-compose.yaml里的端口号或者去容器内部改环境变量——不是不能改而是这些修改在容器重建后会全部丢光。正确做法永远是所有持久化的配置都放进.envCompose文件只是读取方不该频繁手动改。1.2 环境变量在Dify里的加载链路简单梳理一下变量是怎么从.env走到运行程序里的理解这条链路后面排查问题会省很多时间docker-compose.yaml 通过env_file: .env把所有变量注入到容器进程。容器内的Python服务启动时读取os.environ中的值。Dify后端用flask框架配置文件里会通过os.environ.get(变量名, 默认值)拿到具体配置。部分变量还会被docker-compose.yaml用于决定启动哪些容器比如向量库类型不同启动的容器就不同。这条链路意味着如果你改了.env但忘记docker compose up -d重新创建容器那么变量实际不会生效。更隐蔽的是只有变量被重新读取到容器进程里才算生效重启容器时必须让Compose重新读取.env不是只重启某个容器就万事大吉。2. 从cp .env.example开始初始化的关键操作2.1 第一步做什么官方文档和社区里最常出现的一条命令是这样的cd dify/docker cp .env.example .env这条命令做的事很简单把样例配置复制成你真正要用的环境变量文件。你可能会问为什么不直接内置一个.env非得复制一份因为.env里含有机密信息直接入库版本管理会有安全隐患而且不同部署实例的数据库密码、密钥必须互相隔离。.env.example是安全的公共样例.env才是你自家生产的配置文件。复制完成后我建议先别急着启动做两个动作# 查看当前文件里哪些变量被标记为必须修改 grep -n SECRET_KEY .env第一次启动前至少要保证SECRET_KEY不是示例值。这个值在Dify里承担着加密数据库内容、会话数据等敏感信息的职责如果你直接用默认值部署别人一旦拿到你暴露的配置就能解析你的会话数据。生产环境尤其不能用默认值。2.2 .env.example 和 .env 的区别.env.example是模板.env是实例。模板里的注释和默认值是为了让你判断“这里应该填什么”。实例里才是你真正调好的值。很多人会犯一个错误把.env文件提交到Git仓库。一旦仓库泄露数据库密码、密钥、甚至第三方服务的API Key全都会暴露。比较稳妥的做法是在dify/docker目录下维护一个.env.example作为模板真实.env加入.gitignore。如果你用Git管理部署配置记住.env必须忽略.env.example保留但不放真实密码每次升级版本时对照新模板检查自己有没有漏掉的变量。2.3 生成自己的SECRET_KEYSECRET_KEY是Dify环境变量里最重要的一个它直接关系到数据加密和会话安全。Dify在.env.example里给的默认值是your-secret-key如果你直接启动服务通常也能跑起来但这是极度危险的做法。正确生成方式是用系统的加密随机数生成工具openssl rand -base64 42在Linux终端、macOS终端、Windows的Git Bash里都可以执行。你会得到一串类似这样的输出4v0A0JPc4sC0OLi9o4Jz5g6cF2VnXYdFNLu1Jh2sMjM4把这段输出粘贴到.env里的SECRET_KEY后面。注意不要加引号不要带空格Dify读取时会按整行字符串处理一旦不小心带了引号反而可能导致加密逻辑出错。还有一点SECRET_KEY一旦设定并用于生产后不要轻易改。改掉它会让你已生成的API密钥、工作流中的加密凭证全部失效用户会突然发现自己的Bot“失忆”了。3. 核心变量逐项拆解改错会出大事3.1 基本服务类变量docker-compose.yaml启动服务时会用.env里的变量决定Nginx、API容器监听哪个端口。最常用的是变量名默认值作用EXPOSE_NGINX_PORT80Nginx对外暴露端口也就是你浏览器访问Dify的入口端口EXPOSE_NGINX_SSL_PORT443HTTPS端口NGINX_PORT80容器内部Nginx监听端口一般不动DEBUGfalse调试模式开关生产必须false我经常遇到有人问“我想用8080端口访问Dify改了NGINX_PORT怎么不行”这里就是概念混淆。对外访问端口是EXPOSE_NGINX_PORT不是NGINX_PORT。你要访问http://服务器IP:8080就那么改EXPOSE_NGINX_PORT8080改完之后执行docker compose up -d它会重新创建映射端口你再用8080端口访问。如果你改了端口发现还是80先检查是不是忘加-d之后的重新创建或者防火墙没有放行对应端口。DEBUG这个变量也很关键。默认是false如果你在做二次开发想看到详细报错堆栈可以临时设成true。但上生产前必须改回来否则不只会暴露敏感错误信息还会让Flask服务以调试模式运行性能和安全性都会打折。3.2 数据存储类变量Dify默认使用PostgreSQL存储元数据和业务数据用Redis做缓存、队列和会话管理。这两块的配置位于.env上半部分变量名默认值作用DB_USERNAMEdify数据库用户名DB_PASSWORDdifyai数据库密码DB_HOSTdb数据库主机名默认是Docker Compose里的db服务名DB_PORT5432PostgreSQL端口REDIS_HOSTredisRedis主机名REDIS_PORT6379Redis端口REDIS_PASSWORDdifyaiRedis密码如果你只是本地体验默认值可以不动。但如果是部署到公网服务器DB_PASSWORD和REDIS_PASSWORD一定要改成强密码。否则你的PostgreSQL端口一旦暴露到外网会遭遇扫描爆破数据库内容可能被删光这就是网上常见的“数据库失陷勒索”事件。如果你想把Dify的数据存到外部已有的PostgreSQL或Redis实例不要改DB_HOST127.0.0.1就完事。要注意如果你把Dify部署在Docker容器里容器内访问宿主机不能用127.0.0.1要用宿主机在容器网络中的网关地址或者用host.docker.internal这类特殊域名。最稳的方式是让数据库和Dify在同一个Docker网络里直接用服务名访问。我在生产环境踩过这个坑把DB_HOST改成外网数据库IP后连接慢得离谱后来才发现是容器网络MTU问题改用同一内网网段才好。还有一点Dify默认要求PostgreSQL版本匹配。比如某些版本要求PostgreSQL 14/15如果你用旧版的13启动时可能不会报错但运行一段时间后会碰到奇怪的数据类型错误。升级Dify时记得看看官方docker-compose.yaml里用的镜像版本尽量保持一致不要随便换数据库大版本。3.3 向量数据库类变量Dify作为LLM应用开发平台知识库功能依赖向量数据库。环境变量里与向量库相关的核心配置是变量名默认值说明VECTOR_STOREweaviate向量库类型默认是weaviate可换qdrant/milvus等WAVIATE_HOSTweaviate向量库主机名WAVIATE_PORT8080向量库端口WAVIATE_SCHEMEhttphttp或httpsWAVIATE_API_KEYWVFA55...Weaviate的鉴权Key初次接触的朋友经常会忽略VECTOR_STORE的拼写。这个变量取值一旦写错比如写成weaviate全小写没问题但如果写成Weaviate服务启动后可能会创建不兼容的存储结构。更常见的问题是改向量库类型时只改了VECTOR_STORE但对应的主机变量没改。比如你切换到qdrant那QDRANT_HOST必须对应正确的服务名否则API连不上向量库知识库的“索引”和“检索”功能就会报错。我自己的习惯是小规模项目和测试环境用默认的Weaviate就够了开源版自带的容器编排已经把它包进去了。但如果你的知识库文档量特别大、检索延迟敏感建议换Qdrant或Milvus它们的性能在不同场景下有差异。切换之前一定要先备份原来的向量数据或者干脆重建索引因为不同类型的向量库数据格式不互通。3.4 存储类变量Dify要让用户上传文件、对话记录有时候也要持久化所以存储配置也很关键。相关变量主要是变量名默认值说明STORAGE_TYPElocalstorage类型local为本地存储STORAGE_LOCAL_PATHstorage本地存储路径相对路径STORAGE_LOCAL_HOST无本地存储对外访问域名或IPSTORAGE_S3_BUCKET_NAME无S3桶名STORAGE_S3_REGION无S3区域STORAGE_S3_ACCESS_KEY无S3 Access KeySTORAGE_S3_SECRET_KEY无S3 Secret Key很多人在本地体验时不会注意STORAGE_TYPE因为默认值就是local所有上传的文件会落在volumes目录里。但生产环境如果你不做S3或阿里云OSS这类对象存储文件一旦存储在容器本地做多副本部署时会出现文件不同步的问题。假设你部署了两台Dify实例用户在A机器上传了一个附件请求被负载均衡转发到B机器B机器是找不到这个文件的因为文件只存在A机器的磁盘里。所以我的建议是一旦计划对外提供服务第一时间把存储切到对象存储。Dify支持S3、Azure Blob、阿里OSS、腾讯COS等。拿S3举例你需要填好桶名、区域、AccessKey和SecretKey然后在STORAGE_TYPEs3后重启。注意对象存储的桶建议设置为私有读写Dify上传时会自行处理文件访问权限你别图省事把桶设为公有读虽然能访问但会产生一堆公开链接安全上不划算。3.5 模型供应商与第三方服务Dify的模型供应商API Key通常是在控制台界面里填的不走环境变量。你配置好OpenAI或通义千问的Key之后它会被加密存入数据库。这里涉及到一个容易被误解的点你在界面里填的供应商Key是Dify作为平台统一调用的Key你通过API调用Dify时用的Key才是环境变量里SECRET_KEY加密保护的平台Key。但有一些第三方工具会用到环境变量。比如邮件通知功能需要在.env里配SMTP变量名说明MAIL_TYPEsmtpMAIL_DEFAULT_SENDER发件人地址MAIL_USERNAMESMTP账号MAIL_PASSWORDSMTP密码或授权码MAIL_SERVERSMTP服务器地址MAIL_PORTSMTP端口465/587等MAIL_USE_TLS是否启用TLStrue/false我遇到过最典型的问题是邮件发送失败但控制台没有任何明显报错日志里只有一行SMTPAuthenticationError。这种情况八成是SMTP密码写错或者邮箱服务商要求使用“授权码”而不是登录密码。像QQ邮箱、163邮箱你直接用账号密码登录SMTP是无效的必须在邮箱设置里生成一个授权码填到MAIL_PASSWORD里。另外Dify的沙箱Sandbox和CLI工具也会读环境变量例如SANDBOX_API_KEY。这个变量涉及代码解释器的安全隔离如果你在应用里启用了“代码节点”沙箱调用的鉴权就靠它。首次部署时如果不改默认值也能跑但为了安全还是建议用openssl重新生成一个跟SECRET_KEY一样处理。4. 几个高频场景的配置实操4.1 Docker Compose方式本地快速部署最经典的本地部署路径就是先确认环境依赖Docker、Docker Compose。然后拉取Dify仓库进入docker目录复制.env.example为.env生成密钥修改端口最后docker compose up -d。git clone https://github.com/langgenius/dify.git cd dify/docker cp .env.example .env openssl rand -base64 42 # 将生成的值填入 .env 中的 SECRET_KEY docker compose up -d第一次启动时会拉取大量镜像耗时取决于你的网络情况。如果镜像拉取很慢或直接失败最常见的解决思路是给Docker配置国内镜像加速源。不要尝试反复重试一个超时的镜像源那只会浪费时间。配置后重启Docker守护进程再执行docker compose pull拉一次镜像。启动后用http://localhost:80访问你会进入Dify的初始化页面。这个过程里环境变量最核心的就是端口和SECRET_KEY。有一次我在Windows上用Docker Desktop跑默认80端口被占用这时就把EXPOSE_NGINX_PORT改成8000刷新页面用http://localhost:8000访问一切正常。注意Windows和Mac上用Docker Desktop如果你修改了.env建议执行docker compose down再up -d只执行restart可能会保留旧容器的环境变量导致改动不生效。4.2 生产环境多租户部署的变量考量Dify社区版更新到1.10之后开始支持多租户能力。所谓多租户简单说就是一套Dify平台可以开通多个独立的工作空间不同团队的数据、成员、应用互相隔离。环境变量里跟多租户相关的配置常见的有变量名说明MANAGE_ACCOUNT平台管理员账号默认可能是admin相关配置MANAGE_PASSWORD平台管理员初始密码ENABLE_ACCOUNT_EMAIL是否允许通过邮箱注册新账号ENABLE_ACCOUNT_EMAIL_CONFIRMATION新注册是否强制邮箱验证在多租户模式下管理员密码的安全性比单机部署更关键因为平台管理员能查看所有租户的应用和数据。我建议第一次登录后立刻去“账号设置”里改掉初始密码而不是只依赖.env里的MANAGE_PASSWORD。如果你要对外给客户提供SaaS服务另一组变量也要注意域名配置以及NGINX_PROXY相关的反代设置。生产环境一般不会让用户直接访问服务器IP加端口而是会用Nginx或Caddy做反向代理。Dify的.env里相关的变量像是APP_HOST之类确保你配置对外域名后生成的分享链接和回调地址都是正确的域名而不是IP加端口。这步没配对飞书、企微、微信等第三方授权登录很容易回调失败。第三方授权这块比如你想对接飞书云文档控制台会要求填一个授权回调地址。这个地址的域名和你实际使用的访问域名必须完全一致。很多人回调失败不是因为在控制台填错而是环境变量里的对外地址没配对。你先在.env里把对外域名配置好再拿着这个域名去飞书开放平台申请凭证才不会来回折腾。4.3 知识库与向量库切换的配置实操Dify知识库的检索依赖向量库。第一次部署默认是Weaviate容器编排里已经定义了Weaviate服务。如果你要换成Qdrant除了把VECTOR_STOREqdrant还要确保docker-compose.yaml中Qdrant相关的容器没有被注释掉。官方模板通常会把几个主流向量库的服务定义都写在Compose文件里但你需要注意版本和服务名。一个容易犯的错是只把.env改成VECTOR_STOREqdrant却在Compose里把qdrant的容器注释了。启动时API倒是能起来但一问知识库就报“向量数据库连接失败”。排查了半天其实只是Compose模板没启用qdrant服务。另外知识库分段chunking相关参数Dify的界面可以手动调不一定要动环境变量。但有一个变量会影响默认的Embedding模型的配置VECTOR_STORE只解决向量存储Embedding的模型Key还是在模型供应商配置里指定。所以你会发现换了向量库知识库索引还是要重新生成因为旧索引里存储的是旧向量库格式的向量数据。想保留原有索引的几乎没有捷径只能重新跑一遍“索引”任务。4.4 CELERY并发与任务调优Dify的API服务和Worker任务是分开的。你在界面上触发一个工作流、知识库索引、消息异步处理很多后台任务都交给Worker来处理。与它相关的环境变量有变量名默认值说明CELERY_WORKER_QUEUES空指定Worker监听的队列多个队列用逗号分隔CELERY_WORKER_CONCURRENCY10Worker并发数CELERY_WORKER_ENABLE_SCHEDULERtrue是否启用定时调度任务如果你的服务器内存只有2G默认并发数10可能会把内存占满。我建议低配置机器把并发调到4或5实测能明显降低内存压力任务吞吐量影响不大。如果你在界面里发现“文档索引”老是不执行很可能是Worker任务队列异常。可以查看运行日志也可以把CELERY_WORKER_QUEUES里不需要的队列去掉避免Worker去拉取无关任务。5. 常见问题排查与避坑指南5.1 修改.env后不生效怎么办这是出现频率最高的问题。处理顺序我建议你按这个来先确认改的是dify/docker下的.env文件不是其他位置的.env。执行docker compose config检查Compose实际加载的变量值。这个命令会把变量渲染结果打印出来你可以直接看到目标变量有没有被正确读取。执行docker compose down然后docker compose up -d。注意down会删除容器但不会删除卷数据还在所以不用担心。如果还不行进容器确认实际环境变量docker exec -it docker-api-1 env | grep SECRET_KEY你看到的如果是旧值说明容器没有被重新创建如果是新值说明Dify读取逻辑或代码里没有覆盖该变量的地方。我见过最坑的情况是.env最后一行没有换行符导致最后一个变量拼接到了上一行看起来配置没问题实际值却是残缺的。所以在编辑.env后建议末尾保留一个空行避免这类低级错误。5.2 SECRET_KEY错误导致的问题SECRET_KEY写错或重复会导致什么现象最直接的表现是登录后会话很快失效或者你调用API创建的Token无法解析。更隐蔽的是Dify会把模型供应商的Key加密后存到数据库里加密过程依赖SECRET_KEY。如果你某天改了.env里的SECRET_KEY表面上API服务正常启动但你在界面上看到已配置的模型Key全部无法用报错信息类似“解密失败”。遇到这种情况不要惊慌解决方案有两个如果还没存什么重要数据把数据库清掉重建用新SECRET_KEY重新配置。如果已经有生产数据只能把.env里的SECRET_KEY改回原来的值重启。所以我在前面强调过SECRET_KEY一旦定下来就要备份到你本地密码管理工具里。我通常会在部署文档里单独记一行SECRET_KEYxxxx然后整个.env文件用加密压缩包归档防止哪天需要恢复环境找不到原密钥。5.3 拉取镜像失败与慢的排查思路拉取镜像失败是新手最容易卡住的步骤。报错类型通常分三类网络超时i/o timeout或TLS handshake timeout。镜像不存在manifest unknown通常是版本号写错了。磁盘空间不足no space left on device。网络超时的常见处理方式是给Docker配置国内镜像源。你可以在/etc/docker/daemon.jsonLinux或者Docker Desktop的Settings里配置Registry mirrors然后重启Docker。镜像拉下来后后续启动就快了。磁盘空间不足则很隐蔽。Dify全家桶镜像加数据卷占用空间大概在3G到10G之间如果你服务器系统盘只有20G很容易在拉取到一半时失败。这时你要先清理旧的镜像docker system prune -a但注意这句话会删掉所有未被容器使用的镜像如果是多项目共用Docker要谨慎。清理完磁盘后再docker compose pull。5.4 数据库连接失败怎么定位启动后API容器报could not translate host name db to address意思是找不到名为db的主机。这通常是因为数据库容器没起来或者所有依赖数据库的服务没在同一个网络里。排查步骤# 查看所有容器状态 docker compose ps # 查看数据库容器日志 docker compose logs db如果数据库容器反复重启查看日志是否提示数据目录权限不对。Dify的PostgreSQL容器会使用命名卷保存数据如果卷权限不对数据库无法写入容器会崩溃。常见解决办法是# 重置db卷会清空数据库数据 docker compose down -v docker compose up -d db-v参数很危险它会把所有命名卷删掉包括你之后可能要用的向量库数据。所以这个操作只能在你确定数据不需要的前提下执行。还有一类情况是数据库密码不一致。你在.env里改了DB_PASSWORD但Postgres容器已经在旧密码下初始化了数据卷容器每次启动时实际使用的还是初始化时写入的密码导致API连不上后端。这种问题很经典处理办法是修改.env后不仅up -d还要确认数据库容器用的是新环境变量初始化。最稳妥的办法就是把db数据卷删掉重建但同样会清空已有数据。6. 升级Dify版本时环境变量如何处理6.1 版本升级为什么会引入新变量每次Dify发版都可能引入新的功能模块伴随而来的是.env.example里出现全新的变量。比如知识库功能改版之后向量库相关变量变多了多租户上线后权限和账号体系相关变量也增加了。如果你直接从旧版本跳到一个大版本比如从1.6升到1.17.1只保留旧的.env会有风险——新代码可能读取缺失的变量导致某些功能启动异常。我的习惯是升级前做一次环境变量差异对比# 备份当前使用的.env cp .env .env.bak # 对比新版示例与当前配置找出新增变量 diff .env.example .env | grep ^ | head -50开头的行是.env.example里有而你当前.env里没有的变量。逐条确认把新增变量在官方文档或示例文件里的取值说明看懂再补充到自己的.env里。6.2 升级时最容易踩的坑升级过程中比忘记加新变量更棘手的是数据库迁移带来的兼容问题。Dify启动时API容器内会自动执行数据库迁移脚本如果旧数据里的结构和新代码期望的结构不一致迁移可能失败API容器日志里会看到Migration failed之类的报错。这时候不建议直接去改数据库表结构正确做法是先用旧版本容器把数据库完整备份然后再升级。备份可以利用PostgreSQL的pg_dump工具docker exec docker-db-1 pg_dump -U dify dify dify_backup.sql备份完再替换新版本镜像、启动服务。如果迁移失败你至少能回滚到备份状态重新查原因。另外升级前要特别关注官方升级文档里提到的重要变更比如某个向量库类型是否被废弃、是否强制要求开启某种存储格式等。这些信息通常写在Release Notes里很多人不看直接盲改.env结果升级后功能对不上。6.3 升级后的验证清单升级完成后我一般不会立刻把流量切过去而是先跑一遍基础验证能正常登录管理后台能创建一个新的模型供应商配置并成功调用一次LLM能对一份测试文档创建知识库索引并检索到内容已有的应用和工作流能正常发布检查日志里有没有ERROR或WARNING级别的异常输出。这些验证项全部通过我才会认为这次升级在环境变量层面没有遗留问题。如果你发现模型调用失败优先检查是否因为新版要求你重新填写模型供应商Key或者环境变量里的加密逻辑变化导致老Key失效。写在最后的一点个人经验配置Dify环境变量这件事表面上是填键值对实质上是你在为自己整个平台定“地基”。地基没打稳后面加再多应用都会时不时冒出奇怪的问题。我从本地Docker Desktop到服务器部署再到后来做多租户生产环境被.env坑过不止一次。现在的习惯是每次改完.env都先用docker compose config验证一遍再docker compose up -d每次升级版本先diff模板和当前文件再备份数据库和数据卷。这个流程看起来多花几分钟但能帮你避开很多查日志查到怀疑人生的深夜。最后再分享一个小技巧.env文件里所有密码和密钥我从来不会直接手敲都是先用密码生成器生成随机串再复制进去。这样即使某个变量泄露影响范围也是可控的。等你在生产环境吃过一次“默认密码被扫爆”的亏就会明白这件事比想象中更重要。