☰
Dify 启用 HTTPS 完整指南:SSL证书配置与Nginx反向代理实操
2026/10/17 19:16:31 网站建设 项目流程

1. 为什么我建议你在 Dify 上尽早启用 HTTPS

先说结论:如果你正在用 Dify 搭建知识库问答、内部 AI 工具或者对外提供 AI 应用服务,那么“配 SSL 证书 + 强制 HTTPS 访问”这件事,应该排在功能开发之前完成。

原因不复杂。Dify 这类平台一旦跑起来,上面承载的基本都是真实的业务数据——用户的提问内容、上传的文档、流程编排的 API Key、甚至对接外部模型时的密钥信息。如果整个访问链路是明文 HTTP,那这些数据在网络传输过程中等于裸奔。我自己见过不止一个团队,功能都上线了,才想起来检查证书配置,结果发现管理后台和 API 接口全是 HTTP 直出,数据在公网链路里随便抓包就能看到。

另外一个现实问题:现在很多浏览器对 HTTP 站点会直接打上“不安全”的标记,用户在访问你的 AI 应用时,第一印象就会打折扣。尤其是如果产品面向外部客户,一个绿色的锁形图标,远比一串“此站点不安全”的警告更能建立信任。

这篇内容我会从证书选型、域名与端口规划、Nginx 反代配置、容器环境下的证书挂载、以及几种常见部署形态的排错思路这几个角度,完整梳理一遍 Dify 平台配置 SSL 证书和 HTTPS 安全访问的实操路径。文章里用到的方案都是我实际部署验证过的,不会只讲概念。

顺便说一句:如果你只是在内网环境自己开发调试,HTTP 确实还能凑合;但只要涉及任何跨网络访问、多人协作、或者对外发布,HTTPS 就不是可选项,而是必选项。

2. 配置前的规划:证书类型、域名和端口

2.1 证书类型怎么选:免费证书、云厂商证书还是自签名证书

在动手之前,先想清楚要用哪种证书,这直接决定了后面的配置流程和信任程度。

第一种是免费 DV 证书,最典型的就是 Let's Encrypt 签发的证书,以及国内各大云厂商提供的免费 SSL 证书。优点是零成本、自动续期方便、兼容性好;缺点是有效期短,Let's Encrypt 的证书只有 90 天,必须配置自动续期。对于绝大多数 Dify 部署场景,这种证书完全够用。

第二种是云厂商的付费证书或者企业型 OV/EV 证书。适合对信任等级有硬性要求的企业环境,比如金融机构、政务系统。好处是证书有效期内省心、信任级别高;代价是需要花钱,有些还要走人工审核流程。

第三种是自签名证书,只适合纯内网测试环境。它的特点是部署简单、完全免费,但浏览器会报不受信任,无法用于任何对外服务。我的建议是:能不用就不用,除非你完全控制客户端环境,并且能手动导入证书信任链。

从投入产出比来看,个人开发者、中小团队、甚至一些初创公司,直接用 Let's Encrypt 或者云厂商免费证书是最稳妥的路径。

2.2 域名规划:为什么我不建议用 IP 直连的方式配 HTTPS

这是很多人容易忽略的点。证书签发的对象是域名,不是 IP 地址。虽然也有 IP 证书这种产品,但通用性和浏览器兼容性都不如域名证书。

所以配置 HTTPS 前,先准备一个域名,解析到 Dify 服务器。比如你的业务域名是example.com,那就让ai.example.com这个子域名指向 Dify 服务所在服务器的公网 IP。这样一来,后续申请证书、配置 Nginx、做反向代理,路径都会清晰很多。

另外要考虑端口问题。Dify 默认的 Web 服务跑在 80 端口(HTTP),而 HTTPS 默认走 443 端口。如果你用 Docker Compose 方式部署,通常的做法是让宿主机的 80/443 端口交给 Nginx 或者直接交给 Dify 自带的 Nginx 容器处理,外面统一通过 443 端口访问。

注意:如果服务器上还跑了其他 Web 服务,比如 Grafana、Jenkins,提前规划好 443 端口归属,避免后面出现端口冲突,排查起来非常痛苦。

2.3 部署架构的两种形态:单机 Docker Compose 和 Kubernetes

Dify 最常见的部署方式是 Docker Compose 单机部署,这也是官方推荐的人门方式。它自带的nginx服务容器把前端、API、Web 服务都聚合到了一起。在这种形态下,配置 SSL 证书的核心工作分成两步:一是把证书文件放到 Nginx 容器能访问到的位置,二是修改 Dify 自带的 Nginx 配置模板,让 443 监听生效并指向证书。

另一种形态是 Kubernetes 部署。这种情况一般通过 Ingress 来终结 TLS,证书存放在 Secret 对象中,Dify 应用本身不需要感知证书的存在。如果你已经上了 K8s,直接用 cert-manager 自动签发证书会是最省力的方案。

本文重点展开 Docker Compose 形态,因为大部分读者应该都是这种部署方式。

3. 核心实操:用 Nginx 为 Dify 启用 HTTPS

3.1 证书文件准备与存放路径规划

假设你已经从 Let's Encrypt 或者云厂商那里拿到了证书,你手上会得到两个关键文件:

  • 证书文件,通常是.pem或.crt后缀,里面包含公钥和证书链信息
  • 私钥文件,通常是.key后缀,必须严格保密

这两个文件需要放到服务器上,并且要规划好路径。我一般习惯放在/opt/dify/certs/目录下:

mkdir -p /opt/dify/certs # 将证书和私钥上传到这个目录 # 例如: # /opt/dify/certs/example.com.pem # /opt/dify/certs/example.com.key

务必检查一下私钥文件的权限。私钥暴露等于整个 HTTPS 防线崩溃:

chmod 600 /opt/dify/certs/example.com.key

3.2 Docker Compose 环境中证书挂载的正确姿势

Dify 官方提供的docker-compose.yaml里,Nginx 容器默认只是把宿主机的 80 端口映射到了容器的 80 端口。要启用 HTTPS,我们需要做两件事:修改端口映射,把宿主机的 443 端口也映射到容器的 443 端口;把证书目录挂载进 Nginx 容器。

修改docker-compose.yaml中 nginx 服务的 ports 部分:

services: nginx: ports: - "80:80" - "443:443" volumes: - ./certs:/etc/letsencrypt:ro

这里我把宿主机的/opt/dify/certs目录映射到了容器的/etc/letsencrypt目录,用只读模式挂载,防止容器侧误改证书文件。

实操心得:有些教程喜欢把证书直接塞进 Nginx 镜像或者用 volume 挂载单文件。我个人的习惯是挂载整个目录而不是单文件,这样以后证书续期、替换文件时,不需要重启容器,只要 Nginx reload 就能生效。

3.3 Dify 自带 Nginx 配置模板的修改方法

这是整个配置过程中最关键的步骤。

Dify 的 Docker Compose 目录下有一个nginx子目录,里面放着站点配置模板,通常叫dify.conf或者类似的名字。我们要做的不是直接改容器内文件,而是修改宿主机上的模板文件,然后重启 Nginx 容器让它重新加载配置。

进入目录确认文件位置:

cd /opt/dify/docker/nginx ls -la # 一般会看到类似 dify.conf 或 nginx.conf 的文件

编辑配置文件时,我建议保留原 HTTP 配置作为跳转,而不是直接删掉 80 端口监听。这样的好处是:用户访问旧链接时,能自动跳转到 HTTPS,不会因为协议变更导致访问失败。

下面是一份经过验证的 Nginx 配置片段:

server { listen 80; server_name ai.example.com; # 将所有 HTTP 请求永久重定向到 HTTPS return 301 https://$host$request_uri; } server { listen 443 ssl http2; server_name ai.example.com; # 证书与私钥路径 ssl_certificate /etc/letsencrypt/example.com.pem; ssl_certificate_key /etc/letsencrypt/example.com.key; # 推荐的安全增强配置 ssl_protocols TLSv1.2 TLSv1.3; ssl_prefer_server_ciphers on; ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384'; client_max_body_size 15M; location / { proxy_pass http://web:3000; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } location /api { proxy_pass http://api:5001; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } }

这里有一个核心逻辑需要理解:Dify 容器内部用的是服务名互相通信,Nginx 容器通过 Docker 内部网络把请求转发给web容器(前端,端口 3000)和api容器(后端 API,端口 5001)。我们只要保持这种内部转发关系不变,只在外层加上 443 监听和证书配置,就能无缝升级到 HTTPS。

需要注意X-Forwarded-Proto这个请求头。Dify 的后端服务需要知道用户的原始请求是 HTTP 还是 HTTPS,才能生成正确的回调地址、网页跳转链接和 API 响应。如果少了这个头,Dify 内部可能会生成指向http://的链接,导致页面能打开但部分功能异常。

3.4 修改完成后重启容器并验证

配置文件改好后,回到 Dify 的 docker 目录执行:

cd /opt/dify/docker docker compose down && docker compose up -d

如果不想中断服务,也可以只重启 Nginx 容器:

docker compose restart nginx

然后检查容器是否正常运行:

docker compose ps

接下来验证 HTTPS 是否生效:

curl -I https://ai.example.com # 如果返回 200 OK,说明 HTTPS 已经打通 # 如果返回证书错误,多半是证书路径或者证书链配置有问题

用浏览器访问https://ai.example.com,确认地址栏出现锁形图标,并且没有红色警告。

4. Nginx 与容器编排里的常见配置坑

4.1 端口映射漏改导致 HTTPS 无法访问

这是我见过最多的问题。很多人在 Nginx 容器里改了监听 443 的配置,但docker-compose.yaml的端口映射部分却还是只有"80:80"。结果就是容器内 Nginx 明明在监听 443,但宿主机上根本看不到 443 端口,外部请求自然进不来。

排查命令很直接:

netstat -tlnp | grep 443 # 或者 ss -tlnp | grep 443

如果没有输出,基本可以断定是端口映射没生效,赶紧回docker-compose.yaml补上"443:443"。

4.2 证书链不完整导致部分浏览器报错

有时候curl访问没问题,但浏览器报 SSL 错误,原因多半是证书链没配全。很多免费证书包含两个文件:域名证书和中间证书。部分厂商会帮你合成好一个.pem,但有些需要手动拼接。

拼接方法很简单,直接把中间证书内容追加到域名证书内容后面即可:

cat example.com.crt intermediate.crt > fullchain.pem

然后 Nginx 里引用这个合成的fullchain.pem文件。

实操心得:用curl -vI https://your.domain可以查看完整的证书链信息。如果输出里只有一层证书,缺少 intermediate 层级,那就大概率需要手动拼接。

4.3 容器内时间不同步导致的证书校验失败

这个问题非常隐蔽。TLS 握手时,客户端会校验服务端证书的有效期;如果服务器系统时间或容器时间严重偏离当前时间,证书会被判定为未生效或已过期。

如果你用的是云服务器,建议开启 NTP 自动同步时间。在宿主机上执行:

timedatectl set-ntp true

同时检查容器时间:

docker exec dify-nginx-1 date

如果容器时间和宿主机不一致,可以在docker-compose.yaml中增加时间卷挂载:

volumes: - /etc/localtime:/etc/localtime:ro

这种问题往往只影响 HTTPS,不影响 HTTP,所以很多人排查了很久都找不到原因。

5. 访问链路与内部服务转发:让 Dify 正确识别 HTTPS

5.1 修改 Dify 环境变量,避免生成 HTTP 链接

有些时候,证书配好了,页面也能打开,但 Dify 应用内部生成的某些链接仍然是 HTTP。症状包括:分享出来的对话链接打开后跳回 HTTP、部分 API 回调地址异常等。

这通常是因为 Dify 后端不知道外部访问协议已经变成了 HTTPS。需要在 Dify 的环境配置中显式声明。

打开docker-compose.yaml,找到api服务的 environment 部分,确认或者添加以下变量:

environment: # 其他配置保持不变 CONSOLE_API_URL: "https://ai.example.com/api" SERVICE_API_URL: "https://ai.example.com" APP_WEB_URL: "https://ai.example.com"

这三个变量分别控制控制台 API、服务 API 和应用 Web 页面的基础 URL。改成 HTTPS 后,Dify 生成的所有链接都会基于这个地址拼接,不会再出现协议不对的情况。

改完环境变量后,需要重启 api 和 web 容器:

docker compose up -d

5.2 浏览器缓存和 Service Worker 导致的“顽固”问题

如果你之前用 HTTP 访问过 Dify,升级 HTTPS 后浏览器可能还缓存着旧的 Service Worker 脚本。这时候哪怕服务器完全正常,浏览器仍然可能报错或者加载不到资源。

解决办法是强制刷新,或者清除该站点缓存:

  • Windows/Linux:Ctrl + Shift + R
  • Mac:Cmd + Shift + R

如果问题依旧,在浏览器开发者工具里进入 Application 面板,手动注销 Service Worker,然后刷新页面。这个坑很冷门,但遇到一次就很头疼。

6. 多域名与多应用场景下的 HTTPS 配置

6.1 用同一张证书覆盖多个子域名

如果你的 Dify 实例同时绑定多个子域名,比如ai.example.com和console.example.com,建议直接申请一张覆盖泛域名的证书(*.example.com),然后在 Nginx 配置中为不同 server_name 分别配置即可。

如果用的是单域名证书,那也没问题,多加几个 server 块,每个块指向对应证书即可。

6.2 API 对外服务的 HTTPS 配置

Dify 的 API 端口默认是 5001,但对外提供服务时,建议通过 Nginx 统一走 443,而不是直接暴露 5001 端口。原因很直接:5001 端口上跑的是裸 HTTP,一旦开放到公网,等于把 API 数据明文暴露在网络上;而且端口扫描器往往会对非标准端口格外敏感。

正确做法是在 Nginx 上为 API 单独加一个 location 转发,或者用子域名解析到 API。比如:

server { listen 443 ssl http2; server_name api.example.com; ssl_certificate /etc/letsencrypt/example.com.pem; ssl_certificate_key /etc/letsencrypt/example.com.key; location / { proxy_pass http://api:5001; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } }

所有通过 SDK 或者 HTTP 客户端访问 Dify API 的请求,统一走https://api.example.com,既安全又整洁。

6.3 同一台服务器上部署其他服务时的端口规划

很多人的服务器上不只有 Dify,可能还跑了 Compose 之外的其他容器或者应用。这时要特别注意 443 端口只能被一个进程监听。如果你的 Nginx 容器占了 443,那其他服务可以用Nginx 反向代理的方式挂在同一个 443 端口下,用不同域名区分,而不是再开一个 443。

比如:

# 域名 ai.example.com 指向 Dify server { listen 443 ssl http2; server_name ai.example.com; # Dify 反代配置省略... } # 域名 tools.example.com 指向另外一个工具 server { listen 443 ssl http2; server_name tools.example.com; location / { proxy_pass http://tool-container:8080; } }

这样所有服务统一走 443 + TLS,既安全又省事,还避免了端口冲突。

7. 自动续期:用 Let's Encrypt 省掉 90 天的烦恼

7.1 手动续期是反模式,必须自动化

Let's Encrypt 的证书有效期只有 90 天,意味着每三个月你就要换一次证书。如果你觉得“续期不就是手动跑一下命令”,那你就等着某天早上收到用户报告“证书过期了”的惊吓吧。

自动续期这件事,提前做好能省掉无数后续烦恼。官方推荐的工具是certbot。

在宿主机上安装 certbot:

apt update apt install certbot -y

然后用 webroot 模式或者 DNS 插件申请证书。最省事的做法是直接用 DNS 插件,因为这样不需要在 Nginx 里做临时验证路径。

以 Cloudflare DNS 为例(其他 DNS 厂商也有对应插件,原理一样):

certbot certonly --manual --preferred-challenges dns \ -d "*.example.com" \ -d "example.com"

按提示在 DNS 管理后台添加对应的 TXT 记录,验证通过后证书会生成在/etc/letsencrypt/live/example.com/目录。

7.2 续期后自动部署证书到容器目录

证书续期后,Dify 的 Nginx 容器需要拿到新证书才能生效。如果使用简单的目录挂载,那只需要把新证书复制到宿主机挂载目录,然后重载 Nginx 即可。

可以写一个简单的脚本,放在 crontab 里:

#!/bin/bash # /usr/local/bin/renew-dify-cert.sh # 1. 执行续期 certbot renew --quiet # 2. 将新证书复制到 Dify 挂载目录 cp /etc/letsencrypt/live/example.com/fullchain.pem /opt/dify/certs/example.com.pem cp /etc/letsencrypt/live/example.com/privkey.pem /opt/dify/certs/example.com.key # 3. 让 Nginx 重新加载配置 docker exec dify-nginx-1 nginx -s reload

然后加入 crontab,每月执行一次足够:

crontab -e # 每月 1 号凌晨 3 点执行 0 3 1 * * /usr/local/bin/renew-dify-cert.sh

实操心得:帮我省过很多事的做法是先把证书复制脚本写好,再单独手动跑一遍确认无报错,最后才挂 crontab。不要在没验证脚本的情况下直接挂定时任务——否则命中的概率不高,一旦命中就是证书过期事故。

8. 常见问题速查表

症状可能原因排查/解决办法
浏览器访问 443 无响应docker-compose 端口映射没改检查 ports 是否有"443:443"
浏览器报证书不受信任自签名证书或者证书链缺失用受信任 CA 证书,或者拼接证书链
curl 正常但浏览器报错证书链不完整拼接中间证书到 fullchain
页面能打开但部分链接是 httpDify 环境变量未更新协议修改 CONSOLE_API_URL、SERVICE_API_URL、APP_WEB_URL
容器时间不对导致证书校验失败服务器/容器时间偏差开启 NTP,挂载 localtime
页面加载资源 404浏览器缓存了旧 Service Worker强制刷新,注销 Service Worker
更换证书后仍报旧证书错误Nginx 未 reload执行docker exec dify-nginx-1 nginx -s reload
访问/api接口报 502API 容器未启动或代理目标错误检查docker compose ps,确认 api 容器运行正常

9. 我踩过的一些坑和最终建议

配置过程中最容易被忽视的,其实是“环境变量更新”这一步。很多教程只讲了怎么配 Nginx,没提 Dify 后端如何感知 HTTPS。结果就是证书生效了,浏览器锁也有了,但应用内生成的链接还是 HTTP,用户点分享出来的链接又回到明文访问。这个问题我在第一次部署时就踩过,后来看到日志里回调地址全是http://,才意识到要改 API 服务的环境变量。

另一个让我印象深刻的教训是:不要把证书文件直接塞进容器镜像。当时我图省事,把证书写进了自定义 Nginx 镜像,结果证书快到期时,要去重新构建镜像、推送、再拉取,整个过程耗费了不少时间。改成目录挂载之后,续期只要复制文件加 reload 就完成,省心太多。

如果你是从零开始部署 Dify,我的建议是先把 HTTP 跑通,确认服务正常,再动手配置 HTTPS。不要把两件事混在一起,否则出了问题很难分清是 Dify 配置问题还是 Nginx 问题。

最后再分享一个小技巧:配置完成后,可以定期用一个外部监控服务去检查你的 HTTPS 端点,设置好证书到期告警。这样即使自动续期脚本出了意外,你也能提前发现,不会等到用户来投诉才后知后觉。安全这件事,很多时候拼的不是配置多高级,而是能不能做到“提前发现问题”。

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

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

立即咨询