MoreRSS

site iconLaoda | 咕咕修改

主要分享服务器折腾指南、Docker自建项目、博客搭建等技术内容,同时推荐好用的网站和在线工具。
请复制 RSS 到你的阅读器,或快速订阅到 :

Inoreader Feedly Follow Feedbin Local Reader

Laoda | 咕咕的 RSS 预览

十分钟搭建一个「万物皆可存」的智能书签应用——karakeep|好玩儿的 Docker 项目

2025-11-13 09:55:12

1. 唠嗑

好久没更新了,这周来和大家分享一个好用的书签工具——Karakeep

2. karakeep 简介

Karakeep(前身为 Hoarder)是一款可自托管的「万物皆可存」书签应用,专为数据囤积爱好者打造,融入一丝 AI 魔法。

b877b9e2ebadea6bd7eb91991a4744e4.png

功能

  • 🔗 书签链接、记录简单笔记,并存储图片和 PDF 文件。
  • ⬇️ 自动抓取链接标题、描述和预览图。
  • 📋 将书签整理到不同列表中。
  • 🔎 全文本搜索所有存储内容。
  • ✨ 基于 AI(类似 ChatGPT)自动打标签和生成摘要。支持使用 Ollama 运行本地模型!
  • 🤖 规则引擎,实现自定义管理。
  • 🎆 图像 OCR,提取图片中的文字。
  • 🔖 Chrome 插件和 Firefox 扩展,快速添加书签。
  • 📱 iOS 应用和 Android 应用。
  • 📰 从 RSS 订阅源自动归档内容。
  • 🔌 REST API 和多种客户端。
  • 🌐 多语言支持。
  • 🖍️ 标记并保存归档内容中的高亮片段。
  • 🗄️ 完整页面归档(使用 monolith),防止链接失效。
  • ▶️ 使用 yt-dlp 自动归档视频。
  • ☑️ 支持批量操作。
  • 🔐 支持 SSO 单点登录。
  • 🌙 深色模式。
  • 💾 优先支持自托管。
  • ⬇️ 从 Chrome、Pocket、Linkwarden、Omnivore、Tab Session Manager 导入书签。
  • 🔄 通过 floccus 与浏览器书签自动同步。
  • [计划中] 移动端离线阅读、书签语义搜索,……

6fb0d16e6fa436a7fceaa95125fee34d.png

3. 相关地址

官方 GitHub 地址:https://github.com/karakeep-app/karakeep (目前 21.1k 个 star,欢迎大家去给项目点星星!)

Demo 地址:https://try.karakeep.app

默认账号密码:

Email: [email protected]

Password: demodemo

当然如果你体验完还想自己用 docker 搭建一个,那我们就继续往下!

4. 搭建环境

5. 搭建视频(过俩周补充 = =)

5.1 YouTube

视频地址:

5.2 哔哩哔哩

哔哩哔哩:

6. 搭建方式

6.1 安装 Docker 与 Nginx Proxy Manager

可以直接参考这篇内容:

https://blog.laoda.de/archives/nginxproxymanager/

6.2 创建安装目录

创建一下安装的目录:

sudo -i

mkdir -p /root/data/docker_data/karakeep

cd /root/data/docker_data/karakeep

接着我们来编辑下docker-compose.yml

vim docker-compose.yml
services:
  web:
    image: ghcr.io/karakeep-app/karakeep:latest
    restart: unless-stopped
    volumes:
      # By default, the data is stored in a docker volume called "data".
      # If you want to mount a custom directory, change the volume mapping to:
      # - /path/to/your/directory:/data
      - ./data:/data
    ports:
      - 3030:3000
    env_file:
      - .env
    environment:
      MEILI_ADDR: http://meilisearch:7700
      BROWSER_WEB_URL: http://chrome:9222
      # OPENAI_API_KEY: ...

      # You almost never want to change the value of the DATA_DIR variable.
      # If you want to mount a custom directory, change the volume mapping above instead.
      DATA_DIR: /data # DON'T CHANGE THIS
  chrome:
    image: gcr.io/zenika-hub/alpine-chrome:124
    restart: unless-stopped
    command:
      - --no-sandbox
      - --disable-gpu
      - --disable-dev-shm-usage
      - --remote-debugging-address=0.0.0.0
      - --remote-debugging-port=9222
      - --hide-scrollbars
  meilisearch:
    image: getmeili/meilisearch:v1.13.3
    restart: unless-stopped
    env_file:
      - .env
    environment:
      MEILI_NO_ANALYTICS: "true"
    volumes:
      - ./meilisearch:/meili_data

其中的左边的3030可以改成服务器上没有用过的端口,如果要用到AI功能的话,可以取消OPENAI_API_KEY的注释,填入自己的密钥。

修改完成之后,可以在英文输入法下,按 i 修改,完成之后,按一下 esc,然后 :wq 保存退出。

接着我们来编辑下.env

cd /root/data/docker_data/karakeep
vim .env

粘贴如下内容:

KARAKEEP_VERSION=release
NEXTAUTH_SECRET=super_random_string
MEILI_MASTER_KEY=another_random_string
NEXTAUTH_URL=http://localhost:3000
  • 其中的http://localhost:3000这个改成你自己之后用域名访问的地址,比如我的https://karakeep.gugu.ovh
  • 其中的super_random_stringanother_random_string需要我们自己生成。

我们可以先在命令行里面输入

openssl rand -base64 36

生成随机的字符,然后替代它们。

aebf462264a0d4c95fa1416bee41830a.png

我需要放在.env里的内容就是:

KARAKEEP_VERSION=release
NEXTAUTH_SECRET=Lu4YuG5pXji2/QB6blXaoWnfK2WdtKifPhEBt0UQCHqkxCAe
MEILI_MASTER_KEY=wJ222cTFWJ0/9Jnu38gU9Wb+AdCk2SBmQ687MdTbxT8c/V0b
NEXTAUTH_URL=https://karakeep.gugu.ovh

修改完成之后,同样的,可以在英文输入法下,按 i 修改,完成之后,按一下 esc,然后 :wq 保存退出。

6.3 查看端口是否被占用

查看端口是否被占用(以 3030 为例),输入:

lsof -i:3030  #查看 3030 端口是否被占用,如果被占用,重新自定义一个端口

如果啥也没出现,表示端口未被占用,我们可以继续下面的操作了~

如果出现:

-bash: lsof: command not found

运行:

apt install lsof  #安装 lsof

如果端口没有被占用(被占用了就修改一下端口,比如改成 8381,注意 docker 命令行里和防火墙都要改)

6.4 启动 karakeep

cd /root/data/docker_data/karakeep

docker compose up -d   # 注意,老版本用户用 docker-compose up -d

耐心等待拉取好镜像,出现 done的字样之后,

理论上我们就可以输入 http://ip:3030 访问了。

但是这边这个服务必须先搞一下反向代理!既然是加密的项目,不能用 http 使用明文传输,我们部署在公网一定要考虑使用反向代理工具配置 SSL!

做反向代理前,你需要一个域名!

namesilo 上面 xyz 后缀的域名一年就 7 块钱,可以年抛。(冷知识,namesilo 上 6 位数字的 xyz 续费永远都是 0.99 美元 = =)

如果想要长期使用,还是建议买 com 后缀的域名,更加正规一些,可以输入 laodade 来获得 1 美元的优惠(不知道现在还有没有)

namesilo 自带隐私保护,咕咕一直在用这家,价格也是这些注册商里面比较低的,关键是他家不像其他家域名注册商,没有七七八八的套路!(就是后台界面有些 古老 = =)

【域名购买】Namesilo 优惠码和域名解析教程(附带服务器购买推荐和注意事项)

我们接着往下看!

7. 反向代理

7.1 利用 Nginx Proxy Manager

在添加反向代理之前,确保你已经完成了域名解析,不会的可以看这个:域名一枚,并做好解析到服务器上域名购买、域名解析 视频教程) (名称改成你自己想要的域名前缀即可)

8a522c57d08898256ce3814d5183f811.png

之后,登陆 Nginx Proxy Manager(不会的看这个:安装 Nginx Proxy Manager相关教程))

注意:

Nginx Proxy Manager(以下简称 NPM)会用到 80443 端口,所以本机不能占用(比如原来就有 Nginx)

直接丢几张图:

deeedad5afbbcc25441ac1a41e89ba31.pngcf5928e754752471d09460cd31fb2eae.png832a857e518a6999f692c56a1b0d6d18.pngbd08eed12b655993b53b6df83bcb6606.pngec68bb8adeb0d9661917ba2e77032906.png

注意填写对应的 域名IP端口,按文章来的话,应该是 3030

IP 填写:

如果 Nginx Proxy Manager 和 karakeep 在同一台服务器上,可以在终端输入:

ip addr show docker0

查看对应的 Docker 容器内部 IP。

否则直接填 karakeep 所在的服务器 IP 就行。

然后访问域名就可以访问了!

7.2 利用宝塔面板

发现还是有不少小伙伴习惯用宝塔面板,这边也贴一个宝塔面板的反代配置:

直接新建一个站点,不要数据库,不要 php,纯静态即可。

然后打开下面的配置,修改 Nginx 的配置。

image-20220819150345725image-20220819150542867

代码如下:

location / {
      proxy_pass http://127.0.0.1:3030/;       # 注意改成你实际使用的端口
      rewrite ^/(.*)$ /$1 break;
      proxy_redirect off;
      proxy_set_header Host $host;
      proxy_set_header X-Forwarded-Proto $scheme;
      proxy_set_header X-Real-IP $remote_addr;
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header Upgrade-Insecure-Requests 1;
      proxy_set_header X-Forwarded-Proto https;
    }

此方法对 90% 的反向代理都能生效,然后就可以用域名来安装访问了。

有同学可能会问,为什么不直接用宝塔自带的反向代理功能。

image-20220819150730128

也可以,不过咕咕自己之前遇到过当有多个网站需要反代的时候,在这边设置会报错的情况 = =

所以后来就不用了,直接用上面的方法来操作了。

8. 使用教程

非常简单,所见即所得。

登录,

32cb2fe6c8694197a931f84b06e6931d.png

首先注册一个账号,

e04dc92bb6e9435aaebfc5d43eb4f56f.png

后台页面,

2069ec87e83c0c1ad747046940e44717.png

用户设置,

213472f4fcb8caa51ae8344d98424a60.png

如果觉得英文不习惯,也可以改成中文,

0cfd2e99f9d8a159389de1d0f8b3f163.png

输入一个网址,测试一下,

2d1764ecbf9c5ff13e0692864d15659b.png

支持给你存下来的网页打标签,

58b7e0e99d814b62bfa15217b140b3a4.png

服务器统计情况,

abe96ef7a5a74c3d3cd8330ec85073c2.png

Karakeep是支持浏览器插件的,这边可以直接下载浏览器插件,方便浏览网页的时候使用,

c5519d815ece46e7a66ebf39b763ec26.png

输入你搭建好的域名,然后登录即可,

ccd39153c2f87d5ae8be6ee098cfbf7c.png

使用

ea1377f2cd994631248c61114a911c92.png

c89e80bfa4ab4a3de5f1e1b7e6c11124.png

也支持下载完整页面,

502f8bd34f6f45f8af5ad101bd17bd69.png

还有一些AI功能,大家可以自行探索。或者查看Karakeep的官方文档

8.1 更新 karakeep

这个项目后续会持续有更新,所以提供一个更新的方式。

cd /root/data/docker_data/karakeep

docker compose pull

docker compose up -d    # 请不要使用 docker compose stop 来停止容器,因为这么做需要额外的时间等待容器停止;docker compose up -d 直接升级容器时会自动停止并立刻重建新的容器,完全没有必要浪费那些时间。

docker image prune  # prune 命令用来删除不再使用的 docker 对象。删除所有未被 tag 标记和未被容器使用的镜像

提示:

WARNING! This will remove all dangling images.
Are you sure you want to continue? [y/N]

输入 y

利用 Docker 搭建的应用,更新非常容易~

8.2 卸载 karakeep

同样进入安装页面,先停止所有容器。

cd /root/data/docker_data/karakeep

docker compose down

cd ..

rm -rf /root/data/docker_data/karakeep  # 完全删除

可以卸载得很干净。

9. 使用简介

大家有问题欢迎评论区交流。

10. 结尾

祝大家用得开心,有问题可以去 GitHub 提 Issues,也可以在评论区互相交流探讨。

同时,有能力给项目做贡献的同学,也欢迎积极加入到 项目 中来,贡献自己的一份力量!

最后,感谢作者 @civilblur 的辛苦付出,让我们能用到这么优秀的项目!欢迎大家都去给这个项目点个 star。

参考资料

官方 GitHub:https://github.com/karakeep-app/karakeep

十分钟搭建一次性私密信息共享平台——OTS|好玩儿的Docker项目

2025-10-22 11:04:21

1. 唠嗑

好久没更新了,这周来和大家分享一个阅后即焚工具,安全高效的一次性私密信息共享平台——OTS(One-Time-Secret)

2. OTS 简介

OTS 是一个一次性私密信息分享平台。私密信息在发送到服务器之前,会在浏览器中使用对称的 256 位 AES 加密进行加密。之后会生成一个包含私密信息的 ID 和密码的 URL。密码永远不会发送到服务器,因此服务器无法以合理的方式解密它所传递的私密信息。此外,私密信息在第一次读取后会立即被删除。

功能

  • 私密信息在浏览器中通过 AES 256 位加密进行加密
  • 服务器永远不会接收到明文私密信息
  • 私密信息在第一次读取后即被删除

1fda6d3277a6b618383e3f5d09ecc446.png

c25e783b58219bbb18541bb45c1688e9.png

3. 相关地址

官方 GitHub 地址:https://github.com/Luzifer/ots (目前 638 个 star,欢迎大家去给项目点星星!)

Demo 地址:https://ots.fyi/

当然如果你看到这边还想自己用 docker 搭建一个,那我们就继续往下!

4. 搭建环境

5. 搭建视频(过俩天补充 = =)

5.1 YouTube

视频地址:

5.2 哔哩哔哩

哔哩哔哩:

6. 搭建方式

6.1 安装 Docker 与 Nginx Proxy Manager

可以直接参考这篇内容:

https://blog.laoda.de/archives/nginxproxymanager/

6.2 创建安装目录

创建一下安装的目录:

sudo -i

mkdir -p /root/data/docker_data/OTS

cd /root/data/docker_data/OTS

接着我们来编辑下docker-compose.yml

vim docker-compose.yml
services:
  app:
    image: ghcr.io/luzifer/ots:latest
    container_name: ots-app
    restart: always
    ports:
      - 3003:3000
    environment:
      # Optional, see "Customization" in README
      #CUSTOMIZE: '/etc/ots/customize.yaml'
      # See README for details
      REDIS_URL: redis://redis:6379/0
      # 168h = 1w
      SECRET_EXPIRY: "604800"
      # "mem" or "redis" (See README)
      STORAGE_TYPE: redis
    depends_on:
      - redis

  redis:
    image: redis:latest
    container_name: ots-redis
    restart: always
    volumes:
      - ./data:/data

环境变量的说明如下:

环境变量 描述
REDIS_URL Redis 数据库的连接字符串,格式为 redis://USR:PWD@HOST:PORT/DB。用于指定 OTS 应用连接的 Redis 实例
SECRET_EXPIRY 秘密的过期时间,单位为秒(默认 0 = 无过期)。此示例中设置为 604800(168 小时 = 1 周)
STORAGE_TYPE 用于指定存储类型,可以是 mem(内存存储)或 redis(使用 Redis 存储秘密)

最后,在 ots 目录下执行以下命令一键启动:

其中的左边的3003可以改成服务器上没有用过的端口,记得修改自己的用户名和密码,修改完成之后,可以在英文输入法下,按 i 修改,完成之后,按一下 esc,然后 :wq 保存退出。

6.3 查看端口是否被占用

查看端口是否被占用(以 3003 为例),输入:

lsof -i:3003  #查看 3003 端口是否被占用,如果被占用,重新自定义一个端口

如果啥也没出现,表示端口未被占用,我们可以继续下面的操作了~

如果出现:

-bash: lsof: command not found

运行:

apt install lsof  #安装 lsof

如果端口没有被占用(被占用了就修改一下端口,比如改成 8381,注意 docker 命令行里和防火墙都要改)

6.4 启动 OTS

cd /root/data/docker_data/OTS

docker compose up -d   # 注意,老版本用户用 docker-compose up -d

耐心等待拉取好镜像,出现 done的字样之后,

理论上我们就可以输入 http://ip:3003 访问了。

但是这边这个服务必须先搞一下反向代理!既然是加密的项目,不能用 http 使用明文传输,我们部署在公网一定要考虑使用反向代理工具配置 SSL!

做反向代理前,你需要一个域名!

namesilo 上面 xyz 后缀的域名一年就 7 块钱,可以年抛。(冷知识,namesilo 上 6 位数字的 xyz 续费永远都是 0.99 美元 = =)

如果想要长期使用,还是建议买 com 后缀的域名,更加正规一些,可以输入 laodade 来获得 1 美元的优惠(不知道现在还有没有)

namesilo 自带隐私保护,咕咕一直在用这家,价格也是这些注册商里面比较低的,关键是他家不像其他家域名注册商,没有七七八八的套路!(就是后台界面有些 古老 = =)

【域名购买】Namesilo 优惠码和域名解析教程(附带服务器购买推荐和注意事项)

我们接着往下看!

7. 反向代理

7.1 利用 Nginx Proxy Manager

在添加反向代理之前,确保你已经完成了域名解析,不会的可以看这个:域名一枚,并做好解析到服务器上域名购买、域名解析 视频教程) (名称改成你自己想要的域名前缀即可)

08b09ee8604e6250e24354ccb4cd926b.png

之后,登陆 Nginx Proxy Manager(不会的看这个:安装 Nginx Proxy Manager相关教程))

注意:

Nginx Proxy Manager(以下简称 NPM)会用到 80443 端口,所以本机不能占用(比如原来就有 Nginx)

直接丢几张图:

78186b53ea22c99caa737ec043e24947.pngc2075b8e6a85bff585396fd4c0bca1ed.png525e20e0bea1448ff37e3d95dec2876c.pngf5137b06b270769cc2ebca7019f47e35.png

注意填写对应的 域名IP端口,按文章来的话,应该是 3003

IP 填写:

如果 Nginx Proxy Manager 和 OTS 在同一台服务器上,可以在终端输入:

ip addr show docker0

查看对应的 Docker 容器内部 IP。

否则直接填 OTS 所在的服务器 IP 就行。

然后访问域名就可以访问了!

7.2 利用宝塔面板

发现还是有不少小伙伴习惯用宝塔面板,这边也贴一个宝塔面板的反代配置:

直接新建一个站点,不要数据库,不要 php,纯静态即可。

然后打开下面的配置,修改 Nginx 的配置。

image-20220819150345725image-20220819150542867

代码如下:

location / {
      proxy_pass http://127.0.0.1:3003/;       # 注意改成你实际使用的端口
      rewrite ^/(.*)$ /$1 break;
      proxy_redirect off;
      proxy_set_header Host $host;
      proxy_set_header X-Forwarded-Proto $scheme;
      proxy_set_header X-Real-IP $remote_addr;
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header Upgrade-Insecure-Requests 1;
      proxy_set_header X-Forwarded-Proto https;
    }

此方法对 90% 的反向代理都能生效,然后就可以用域名来安装访问了。

有同学可能会问,为什么不直接用宝塔自带的反向代理功能。

image-20220819150730128

也可以,不过咕咕自己之前遇到过当有多个网站需要反代的时候,在这边设置会报错的情况 = =

所以后来就不用了,直接用上面的方法来操作了。

8. 使用教程

非常简单,所见即所得。

19f97b0b247033100477307b379bd7b8.png

6e3f18b4fc5aeef1a5bdb998d4decf6e.png

ddd6171537aa47f30f150dfa9d9f8d6b.png

8.1 更新 OTS

这个项目后续会持续有更新,所以提供一个更新的方式。

cd /root/data/docker_data/OTS

docker compose pull

docker compose up -d    # 请不要使用 docker compose stop 来停止容器,因为这么做需要额外的时间等待容器停止;docker compose up -d 直接升级容器时会自动停止并立刻重建新的容器,完全没有必要浪费那些时间。

docker image prune  # prune 命令用来删除不再使用的 docker 对象。删除所有未被 tag 标记和未被容器使用的镜像

提示:

WARNING! This will remove all dangling images.
Are you sure you want to continue? [y/N]

输入 y

利用 Docker 搭建的应用,更新非常容易~

8.2 卸载 OTS

同样进入安装页面,先停止所有容器。

cd /root/data/docker_data/OTS

docker compose down

cd ..

rm -rf /root/data/docker_data/OTS  # 完全删除

可以卸载得很干净。

9. 常见问题及注意点

大家有问题欢迎评论区交流。

10. 结尾

祝大家用得开心,有问题可以去 GitHub 提 Issues,也可以在评论区互相交流探讨。

同时,有能力给项目做贡献的同学,也欢迎积极加入到 项目 中来,贡献自己的一份力量!

最后,感谢作者 @civilblur 的辛苦付出,让我们能用到这么优秀的项目!欢迎大家都去给这个项目点个 star。

参考资料

官方 GitHub:https://github.com/Luzifer/ots

3分钟利用 Paypal 领取免费一年 Perplexity 会员! 解锁AI搜索神器!网页点点就行!

2025-09-04 18:31:06

简介

Perplexity是什么?

Perplexity 是一个结合了 AI 聊天机器人和搜索引擎功能的工具,旨在快速提供准确、简洁的答案,并附上可靠的来源引用。它通过理解用户问题,从网络上实时抓取信息,整理成清晰的回答,特别适合需要快速查资料或做研究的用户。

Pro版本的功能:

Perplexity Pro 提供更高级的功能,收费20美元/月,功能包括:

  • 多模型选择:用户可切换使用 GPT-4o、Claude 3.7、Gemini Flash 等不同语言模型,灵活应对不同需求。
  • Pages报告生成:可根据用户需求生成定制化的精美简报,适合研究或商务用途。
  • 高级搜索功能:如学术论文模式,专注搜索学术资源(如 Arxiv、SemanticScholar),提升研究效率。
  • 更高使用额度:相比免费版,Pro 版支持更多查询次数和更复杂的任务。

如果你需要快速查资料、做研究或验证信息,Perplexity 是最佳选择,尤其适合学术和专业场景。

领取条件

  • 1个PayPal账号(我用的是美区,据网友测试国区也可以)
  • 能访问真正的互联网
  • Perplexity 账号(可以现场注册)

领取方式

领取地址:https://www.perplexity.ai/join/p/paypal-subscription

ca3e75602a808c3b92397198da35363b.png

链接PayPal,

b4718b6f264d1c7de5207d0b5b7f9e34.png

我这边登录的是美区的PayPal,

a1f67cdf27b91ba2458beef66f8cfa17.png

选择接受优惠,
2f608f0e1364368ec38a54e434a4ac29.png

成功领取!

7f1cf6733ecd5e65c02f165a6c8a1964.png

已经可以正常使用了!

b12078649e490b14d6fee9c83be13f85.png

如果担心被反薅,记得取消 Perplexity 自动续费订阅,

访问:https://www.perplexity.ai/account/details

fa470b29a43e2a70b1eb49c74b2f6dcb.png

a6afdd3b8f2a1095fdabd1ee7fe59c19.png

取消订阅即可,不影响使用

同样的,Perplexity 还支持Mac桌面端,也可以用起来了!

257164195481a94f33de0c5b62a87130.png

注意点

  • 这次似乎国区的PayPal也可以领取。
  • 有不少网友评价Perplexity玩不起,之前三星的泄漏的一年优惠码,没用几天被收回了。
  • 也有网友表示现在这次打开会提示开通过了。 You are already subscribed or have previously subscribed to Perplexity Pro.
  • 还有一些一注册上就风控,即使美区也是,原先注册好的死活都不让领说领过了,换无数个邮箱尝试依旧如此,这个时候可以考虑换一个干净的IP再试试。

给你的Docker应用加一层保险!10分钟搭建一个简单好用的认证中间件—— Tinyauth

2025-09-03 16:30:34

1. 唠嗑

这两三年来,我们搭建了不少好玩的Docker应用,其实一直陆陆续续有小伙伴在视频评论区和博客的评论区询问,怎么样才能让我的Docker应用更安全一点?

这一期,我们就来介绍这样一个工具,用最简单的方式来给我们的Docker应用加一层保险!

效果展示:

保存之后。

再次打开简历这个网页。

提示需要登录了。

ae23d63f56a62d74560f7997f8537212.png

输入账号密码,继续

9cb7f756e503807085b95ed778e742c8.png

进来了。

cd86b2609a4ec471929f0fbc4d43d825.png

2. Tinyauth简介

Tinyauth 是个简单好用的认证中间件,能给你的 Docker 应用加个简洁的登录页面,或者支持 Google、GitHub 以及其他平台的 OAuth 认证。它跟主流代理比如 Nginx Proxy Manager、Traefik、Nginx 和 Caddy 都能无缝配合。

355959a7fc641c514e84dc5272ba9893.png

3. 相关地址

官方GitHub地址:https://github.com/steveiliop56/tinyauth (目前5.3K个star,欢迎大家去给项目点星星!)

文档地址:https://tinyauth.app/docs/guides/nginx-proxy-manager

Demo地址:https://tinyauth.app/

下面我们就用 Tinyauth配合 Nginx Proxy Manager,简单分享一下是怎么搭建这个中间件从而来保护我们的Docker应用的。

4. 搭建环境

5. 搭建视频(过俩天补充 = =)

5.1 YouTube

视频地址:

5.2 哔哩哔哩

哔哩哔哩:

6. 搭建方式

6.1 安装 Docker 与 Nginx Proxy Manager

可以直接参考这篇内容:

https://blog.laoda.de/archives/nginxproxymanager/

我们这边假设大家都装好了Nginx Proxy Manger,

假设Nginx Proxy Manger在服务器上的路径是~/data/docker_data/npm

这边的话就只需要修改一下即可。

官方文档给的参考如下:

services:
  npm:
    container_name: npm
    image: jc21/nginx-proxy-manager:2
    restart: unless-stopped
    ports:
      - 80:80
      - 443:443
      - 81:81
    volumes:
      - npm-data:/data
      - npm-letsencrypt:/etc/letsencrypt

  nginx:
    container_name: nginx
    image: nginx:latest
    restart: unless-stopped

  tinyauth:
    container_name: tinyauth
    image: ghcr.io/steveiliop56/tinyauth:v3
    restart: unless-stopped
    environment:
      - SECRET_FILE=/secret.txt
      - APP_URL=http://tinyauth.example.com
      - USERS=user:$$2a$$10$$UdLYoJ5lgPsC0RKqYH/jMua7zIn0g9kPqWmhYayJYLaZQ/FTmH2/u # user:password

volumes:
  npm-data:
  npm-letsencrypt:

如果直接使用,你一定会遇到很多问题。

我不会告诉你我用官方的这个配置文件,折腾了大半小时 = =

这边直接用咕咕修改过的这个:

重新编辑你的NPM的docker-compose.yaml文件,改成下面这个:

services:
  npm:
    container_name: npm
    image: jc21/nginx-proxy-manager:2
    restart: unless-stopped
    ports:
      - 80:80
      - 443:443
      - 81:81
    volumes:
      - ./data:/data         # 冒号左边的 ./data改成你自己实际的路径
      - ./letsencrypt:/etc/letsencrypt  # 冒号左边的 ./letsencrypt改成你自己实际的路径

  tinyauth:
    container_name: tinyauth
    image: ghcr.io/steveiliop56/tinyauth:v3
    restart: unless-stopped
    environment:
      - SECRET=kX9mPqW3zT7rY2vN8bL4jF6hD1cA5eK2  # 这个也要修改
      - APP_URL=https://auth.gugu.ovh  #这个也要修改
      - USERS=roy:$$2a$$10$$oXMqgLV/S1hrknYQht.WYu7YfWxkI4VriQn/y # user:password 这边要修改

然后我们来看需要修改的部分。

SECRET,这个的话,直接在命令行操作:

生成secret:

openssl rand -base64 32 | tr -dc 'a-zA-Z0-9' | head -c 32 && echo

输出类似:kX9mPqW3zT7rY2vN8bL4jF6hD1cA5eK2 填入yaml即可。

APP_URL 这里改成你的tinyauth将来想要使用的域名,比如我这边https://auth.gugu.ovh

USERS ,这个官方也提供了方法,生成用户名和密码。

docker run -i -t --rm ghcr.io/steveiliop56/tinyauth:v3 user create --interactive

6788be9f0dedebd6fa8cd177d5dfe651.png

为docker格式化输出这个,记得选yes(按住shift再按小键盘方向键就可以选)

原因是USERS这边在yaml文件里要做哈希转换(比如哈希中的 $ 需要正确转义为 $$,命令行的 Docker 格式会自动处理。),如果不格式化输出会有问题。

c60fa52194d0d7b685327187290f75de.png

当然也支持多个用户,可以再打一遍代码,设置第二个用户,

595a1c77b1cc3807c6f4d398609c5c20.png

如果是一个用户,我们直接贴到yaml文件里即可,但是如果像我们现在这样,有三个用户,直接放进yaml文件会有点长,而且也不好维护。

所以,我们可以把用户配置放入 .env 文件,可以这样做:

编辑 ~/data/docker_data/npm/.env

SECRET=kX9mPqW3zT7rY2vN8bL4jF6hD1cA5eK2
APP_URL=https://auth.gugu.ovh
USERS=roy:$$2a$$10$$oXMqgLV/S1hrknYQht.WYu7YfEjBdSB5rIicj23O8WxkI4VriQn/y,gugu:$$2a$$10$$s.nq/KZLBlFwUiSUNyRUGe0j2pp.A9/.tecuX7QsCBq242baKgKJ.,xixi:$$2a$$10$$6smj5Y/PD.jB1a2Z2gDAxOVnlcv8HfINtLrzCmmTjMZLObBwV8DoW

修改 docker-compose.yaml 以引用 .env

services:
  npm:
    container_name: npm
    image: jc21/nginx-proxy-manager:2
    restart: unless-stopped
    ports:
      - 80:80
      - 443:443
      - 81:81
    volumes:
      - ./data:/data
      - ./letsencrypt:/etc/letsencrypt

  nginx:
    container_name: nginx
    image: nginx:latest
    restart: unless-stopped

  tinyauth:
    container_name: tinyauth
    image: ghcr.io/steveiliop56/tinyauth:v3
    restart: unless-stopped
	env_file:
      - .env
#    environment:
#      - SECRET=kX9mPqW3zT7rY2vN8bL4jF6hD1cA5eK2
#      - APP_URL=https://auth.gugu.ovh
#      - USERS=roy:$$2a$$10$$oXMqgLV/S1hrknYQht.WYu7YfEjBdSB5rIicj23O8WxkI4VriQn/y # user:password

这样基本上就OK啦。

重新启动NPM

cd ~/data/docker_data/npm

docker compose down 

docker compose up -d 

docker compose logs tinyauth

出现类似,代表成功。

d9f4bfbde7c1b712d735d834b0cffb87.png

这边我们先搞一下反向代理!

做反向代理前,你需要一个域名!

namesilo 上面 xyz 后缀的域名一年就 7 块钱,可以年抛。(冷知识,namesilo上 6位数字的xyz续费永远都是0.99美元 = =)

如果想要长期使用,还是建议买 com 后缀的域名,更加正规一些,可以输入 laodade 来获得 1 美元的优惠(不知道现在还有没有)

namesilo 自带隐私保护,咕咕一直在用这家,价格也是这些注册商里面比较低的,关键是他家不像其他家域名注册商,没有七七八八的套路!(就是后台界面有些 古老 = =)

【域名购买】Namesilo 优惠码和域名解析教程(附带服务器购买推荐和注意事项)

我们接着往下看!

7. 反向代理

7.1 配置Tinyauth的反向代理

在添加反向代理之前,确保你已经完成了域名解析,不会的可以看这个:域名一枚,并做好解析到服务器上域名购买、域名解析 视频教程) (名称改成你自己想要的域名前缀即可)

343d7766a70c301276c8bfae52fae8e3.png

之后,登陆 Nginx Proxy Manager(不会的看这个:安装 Nginx Proxy Manager相关教程))

注意:

Nginx Proxy Manager(以下简称 NPM)会用到 80443 端口,所以本机不能占用(比如原来就有 Nginx)

直接丢几张图:

aca0ebcc28a73586bb9c43131b0490cf.png

确保“阻止常见漏洞”(Bolck Common Exploits)选项是关掉的。如果这选项开了,Nginx 会把 URL 里的查询参数给拦下来,而 Tinyauth 得靠这些参数才能正常工作。

tinyauth这个是容器的名字,因为它和NPM在一个网络下,所以可以用容器名字来代替域名,3000是内部的端口,保持即可不要更改。

8ecf402ef51f5a3ec7ca759a85ae647c.png48c4db84474ea229406a39104f965c33.pngb1f1a1aec3c198cc06b60758a3fad1e5.png

然后访问域名就可以访问了!

5c42cfa09961f64c36e18ea9d2ba4aeb.png

7.2 配置需要保护的应用的反向代理

我这边以之前介绍的简历应用(让写简历变得简单且智能!十分钟搭建一个在线简历编辑器——Magic Resume|好玩儿的Docker项目)为例子,

084d9f5958a47f6b0e867f163ddc06de.png

找到你需要添加登录页的应用的对应的NPM配置,在Advance里面添加:

# Root location
location / {
  # Pass the request to the app
  proxy_pass          $forward_scheme://$server:$port;

  # Add other app specific config here

  # Tinyauth auth request
  auth_request /tinyauth;
  error_page 401 = @tinyauth_login;
}

# Tinyauth auth request
location /tinyauth {
  # Pass request to Tinyauth
  proxy_pass http://tinyauth:3000/api/auth/nginx;

  # Pass the request headers
  proxy_set_header x-forwarded-proto $scheme;
  proxy_set_header x-forwarded-host $http_host;
  proxy_set_header x-forwarded-uri $request_uri;
}

# Tinyauth login redirect
location @tinyauth_login {
  return 302 https://auth.gugu.ovh/login?redirect_uri=$scheme://$http_host$request_uri; # Make sure to replace the https://auth.gugu.ovh with your own app URL
}

其他地方都不用管,只要把https://auth.gugu.ovh 替换成你自己的tinyauth的域名即可。

75bde1737d7b3d2d605860bb839fa567.png

保存之后。

再次打开简历这个网页。

提示需要登录了。

ae23d63f56a62d74560f7997f8537212.png

输入账号密码,继续

9cb7f756e503807085b95ed778e742c8.png

进来了。

cd86b2609a4ec471929f0fbc4d43d825.png

8. 使用教程

其他的也类似,只需要在对应应用的NPM的Advance里面加:

# Root location
location / {
  # Pass the request to the app
  proxy_pass          $forward_scheme://$server:$port;

  # Add other app specific config here

  # Tinyauth auth request
  auth_request /tinyauth;
  error_page 401 = @tinyauth_login;
}

# Tinyauth auth request
location /tinyauth {
  # Pass request to Tinyauth
  proxy_pass http://tinyauth:3000/api/auth/nginx;

  # Pass the request headers
  proxy_set_header x-forwarded-proto $scheme;
  proxy_set_header x-forwarded-host $http_host;
  proxy_set_header x-forwarded-uri $request_uri;
}

# Tinyauth login redirect
location @tinyauth_login {
  return 302 https://auth.gugu.ovh/login?redirect_uri=$scheme://$http_host$request_uri; # Make sure to replace the https://auth.gugu.ovh with your own app URL
}

即可。

PS: /tinyauth 这个路径可以随便改,指南里用这个名字只是为了方便。

9. 常见问题及注意点

大家有问题欢迎评论区交流。

10. 结尾

祝大家用得开心,有问题可以去 GitHub 提 Issues,也可以在评论区互相交流探讨。

同时,有能力给项目做贡献的同学,也欢迎积极加入到 项目 中来,贡献自己的一份力量!

最后,感谢作者@steveiliop56的辛苦付出,让我们能用到这么优秀的项目!欢迎大家都去给这个项目点个 star ⭐️

参考资料

官方GitHub:https://github.com/steveiliop56/tinyauth

Dify本地部署上手攻略:轻松打造你的专属AI神器|好玩儿的Docker项目

2025-08-28 16:50:27

前言

Dify是一个开源的AI应用开发平台,简单来说,它能让普通人也能轻松创建智能聊天机器人或AI助手。

它通过拖拽式的界面,整合了各种大语言模型和工具,比如可以连接企业知识库或外部API,让AI能回答专业问题或完成复杂任务。无论是程序员还是非技术人员,都能用它快速搭建AI应用,省时省力。Dify还支持本地部署,数据安全有保障,特别适合想快速上手AI的团队或个人。

其实Dify已经火了有很长时间了,之前嫌麻烦,我一直没怎么用。最近,公司里的一批小伙伴都换了配置更高的新电脑,纷纷在本地部署起了Dify,这一期就来一个小白级别的教程,和大家简单分享一下Dify的本地部署。

准备工作

Dify本身官方对电脑硬件的建议要求是:

  • CPU >= 2 Core
  • RAM >= 4 GiB

如果你打算做完全本地的部署,即不用云端的大模型,

如果你是windows电脑,建议配置如下:

内存:至少 16GB 系统内存(推荐 24GB 以上,留 8GB 给操作系统和其他软件)。

GPU(可选但推荐):至少 16GB VRAM 的 GPU(如 AMD Radeon RX 9070 XT 或 NVIDIA RTX 3090),支持 MXFP4 量化。GPU 内存带宽需高(如 GDDR6X/GDDR7,1000+ GB/s)。

CPU:支持 CPU 推理,但速度较慢。推荐高性能 CPU(如 AMD Ryzen 9 5900X 或 Intel Core i9)。

如果是Mac的话,

硬件:Apple Silicon(M1/M2/M3/M4),至少 16GB 统一内存(推荐 32GB)。

我自己这边用的是Mac,部署起来相对简单一些,用Windows的小伙伴可能会稍微复杂一丢丢。

Windows安装Docker可以参考这个:https://docs.docker.com/desktop/windows/install/#wsl-2-backend

本质都是先在本地电脑安装好Docker,然后通过Docker来部署Dify。

安装Docker

本地装docker,可以去docker官网直接下载一个安装包。

官方地址:https://www.docker.com/products/docker-desktop/

img

下载之后,就像安装普通软件一样,安装一下。

然后打开docker。

打开Mac的终端,输入docker -v,有版本号说明安装好了。

img

img

这边还会涉及docker换源,由于防火墙的原因,我们大陆可能无法访问docker的镜像仓库,建议大家换成中科大的源:https://docker.mirrors.ustc.edu.cn/

img

改成这个:

{
  "builder": {
    "gc": {
      "defaultKeepStorage": "20GB",
      "enabled": true
    }
  },
  "experimental": false,
  "features": {
    "buildkit": true
  },
  "registry-mirrors": [
    "https://docker.mirrors.ustc.edu.cn"
  ]
}

img

然后记得点击应用并重启。

使用如下命令查看Docker配置,

docker info

3c158daac7e908df23db4bede4f8db8d.png

就可以了。

安装Dify

Docker安装好之后,接下来安装我们今天的主角——Dify。

文档地址:https://docs.dify.ai/en/introduction

这边一直关注咕咕的小伙伴可以很轻松的安装好。

Mac和Linux其实差不多,我们直接像操作VPS一样来就行。

mkdir ./data/docker_data
cd data/docker_data

img

git clone --branch "$(curl -s https://api.github.com/repos/langgenius/dify/releases/latest | jq -r .tag_name)" https://github.com/langgenius/dify.git      # 从GitHub下载dify源码

cd dify/docker    # 进入文件夹

cp .env.example .env    # 拷贝一份配置文件

这里如果后续有需求,可以自行修改这个配置文件,一起来看一下

# ------------------------------
# Environment Variables for API service & worker
# ------------------------------

# ------------------------------
# Common Variables
# ------------------------------

# The backend URL of the console API,
# used to concatenate the authorization callback.
# If empty, it is the same domain.
# Example: https://api.console.dify.ai
CONSOLE_API_URL=

# The front-end URL of the console web,
# used to concatenate some front-end addresses and for CORS configuration use.
# If empty, it is the same domain.
# Example: https://console.dify.ai
CONSOLE_WEB_URL=

# Service API Url,
# used to display Service API Base Url to the front-end.
# If empty, it is the same domain.
# Example: https://api.dify.ai
SERVICE_API_URL=

# WebApp API backend Url,
# used to declare the back-end URL for the front-end API.
# If empty, it is the same domain.
# Example: https://api.app.dify.ai
APP_API_URL=

# WebApp Url,
# used to display WebAPP API Base Url to the front-end.
# If empty, it is the same domain.
# Example: https://app.dify.ai
APP_WEB_URL=

# File preview or download Url prefix.
# used to display File preview or download Url to the front-end or as Multi-model inputs;
# Url is signed and has expiration time.
# Setting FILES_URL is required for file processing plugins.
#   - For https://example.com, use FILES_URL=https://example.com
#   - For http://example.com, use FILES_URL=http://example.com
#   Recommendation: use a dedicated domain (e.g., https://upload.example.com).
#   Alternatively, use http://<your-ip>:5001 or http://api:5001,
#   ensuring port 5001 is externally accessible (see docker-compose.yaml).
FILES_URL=

# INTERNAL_FILES_URL is used for plugin daemon communication within Docker network.
# Set this to the internal Docker service URL for proper plugin file access.
# Example: INTERNAL_FILES_URL=http://api:5001
INTERNAL_FILES_URL=

# Ensure UTF-8 encoding
LANG=en_US.UTF-8
LC_ALL=en_US.UTF-8
PYTHONIOENCODING=utf-8

# ------------------------------
# Server Configuration
# ------------------------------

# The log level for the application.
# Supported values are `DEBUG`, `INFO`, `WARNING`, `ERROR`, `CRITICAL`
LOG_LEVEL=INFO
# Log file path
LOG_FILE=/app/logs/server.log
# Log file max size, the unit is MB
LOG_FILE_MAX_SIZE=20
# Log file max backup count
LOG_FILE_BACKUP_COUNT=5
# Log dateformat
LOG_DATEFORMAT=%Y-%m-%d %H:%M:%S
# Log Timezone
LOG_TZ=UTC

# Debug mode, default is false.
# It is recommended to turn on this configuration for local development
# to prevent some problems caused by monkey patch.
DEBUG=false

# Flask debug mode, it can output trace information at the interface when turned on,
# which is convenient for debugging.
FLASK_DEBUG=false

# Enable request logging, which will log the request and response information.
# And the log level is DEBUG
ENABLE_REQUEST_LOGGING=False

# A secret key that is used for securely signing the session cookie
# and encrypting sensitive information on the database.
# You can generate a strong key using `openssl rand -base64 42`.
SECRET_KEY=sk-9f73s3ljTXVcMT3Blb3ljTqtsKiGHXVcMT3BlbkFJLK7U

# Password for admin user initialization.
# If left unset, admin user will not be prompted for a password
# when creating the initial admin account.
# The length of the password cannot exceed 30 characters.
INIT_PASSWORD=

# Deployment environment.
# Supported values are `PRODUCTION`, `TESTING`. Default is `PRODUCTION`.
# Testing environment. There will be a distinct color label on the front-end page,
# indicating that this environment is a testing environment.
DEPLOY_ENV=PRODUCTION

# Whether to enable the version check policy.
# If set to empty, https://updates.dify.ai will be called for version check.
CHECK_UPDATE_URL=https://updates.dify.ai

# Used to change the OpenAI base address, default is https://api.openai.com/v1.
# When OpenAI cannot be accessed in China, replace it with a domestic mirror address,
# or when a local model provides OpenAI compatible API, it can be replaced.
OPENAI_API_BASE=https://api.openai.com/v1

# When enabled, migrations will be executed prior to application startup
# and the application will start after the migrations have completed.
MIGRATION_ENABLED=true

# File Access Time specifies a time interval in seconds for the file to be accessed.
# The default value is 300 seconds.
FILES_ACCESS_TIMEOUT=300

# Access token expiration time in minutes
ACCESS_TOKEN_EXPIRE_MINUTES=60

# Refresh token expiration time in days
REFRESH_TOKEN_EXPIRE_DAYS=30

# The maximum number of active requests for the application, where 0 means unlimited, should be a non-negative integer.
APP_MAX_ACTIVE_REQUESTS=0
APP_MAX_EXECUTION_TIME=1200

# ------------------------------
# Container Startup Related Configuration
# Only effective when starting with docker image or docker-compose.
# ------------------------------

# API service binding address, default: 0.0.0.0, i.e., all addresses can be accessed.
DIFY_BIND_ADDRESS=0.0.0.0

# API service binding port number, default 5001.
DIFY_PORT=5001

# The number of API server workers, i.e., the number of workers.
# Formula: number of cpu cores x 2 + 1 for sync, 1 for Gevent
# Reference: https://docs.gunicorn.org/en/stable/design.html#how-many-workers
SERVER_WORKER_AMOUNT=1

# Defaults to gevent. If using windows, it can be switched to sync or solo.
SERVER_WORKER_CLASS=gevent

# Default number of worker connections, the default is 10.
SERVER_WORKER_CONNECTIONS=10

# Similar to SERVER_WORKER_CLASS.
# If using windows, it can be switched to sync or solo.
CELERY_WORKER_CLASS=

# Request handling timeout. The default is 200,
# it is recommended to set it to 360 to support a longer sse connection time.
GUNICORN_TIMEOUT=360

# The number of Celery workers. The default is 1, and can be set as needed.
CELERY_WORKER_AMOUNT=

# Flag indicating whether to enable autoscaling of Celery workers.
#
# Autoscaling is useful when tasks are CPU intensive and can be dynamically
# allocated and deallocated based on the workload.
#
# When autoscaling is enabled, the maximum and minimum number of workers can
# be specified. The autoscaling algorithm will dynamically adjust the number
# of workers within the specified range.
#
# Default is false (i.e., autoscaling is disabled).
#
# Example:
# CELERY_AUTO_SCALE=true
CELERY_AUTO_SCALE=false

# The maximum number of Celery workers that can be autoscaled.
# This is optional and only used when autoscaling is enabled.
# Default is not set.
CELERY_MAX_WORKERS=

# The minimum number of Celery workers that can be autoscaled.
# This is optional and only used when autoscaling is enabled.
# Default is not set.
CELERY_MIN_WORKERS=

# API Tool configuration
API_TOOL_DEFAULT_CONNECT_TIMEOUT=10
API_TOOL_DEFAULT_READ_TIMEOUT=60

# -------------------------------
# Datasource Configuration
# --------------------------------
ENABLE_WEBSITE_JINAREADER=true
ENABLE_WEBSITE_FIRECRAWL=true
ENABLE_WEBSITE_WATERCRAWL=true

# ------------------------------
# Database Configuration
# The database uses PostgreSQL. Please use the public schema.
# It is consistent with the configuration in the 'db' service below.
# ------------------------------

DB_USERNAME=postgres
DB_PASSWORD=difyai123456
DB_HOST=db
DB_PORT=5432
DB_DATABASE=dify
# The size of the database connection pool.
# The default is 30 connections, which can be appropriately increased.
SQLALCHEMY_POOL_SIZE=30
# The default is 10 connections, which allows temporary overflow beyond the pool size.
SQLALCHEMY_MAX_OVERFLOW=10
# Database connection pool recycling time, the default is 3600 seconds.
SQLALCHEMY_POOL_RECYCLE=3600
# Whether to print SQL, default is false.
SQLALCHEMY_ECHO=false
# If True, will test connections for liveness upon each checkout
SQLALCHEMY_POOL_PRE_PING=false
# Whether to enable the Last in first out option or use default FIFO queue if is false
SQLALCHEMY_POOL_USE_LIFO=false

# Maximum number of connections to the database
# Default is 100
#
# Reference: https://www.postgresql.org/docs/current/runtime-config-connection.html#GUC-MAX-CONNECTIONS
POSTGRES_MAX_CONNECTIONS=100

# Sets the amount of shared memory used for postgres's shared buffers.
# Default is 128MB
# Recommended value: 25% of available memory
# Reference: https://www.postgresql.org/docs/current/runtime-config-resource.html#GUC-SHARED-BUFFERS
POSTGRES_SHARED_BUFFERS=128MB

# Sets the amount of memory used by each database worker for working space.
# Default is 4MB
#
# Reference: https://www.postgresql.org/docs/current/runtime-config-resource.html#GUC-WORK-MEM
POSTGRES_WORK_MEM=4MB

# Sets the amount of memory reserved for maintenance activities.
# Default is 64MB
#
# Reference: https://www.postgresql.org/docs/current/runtime-config-resource.html#GUC-MAINTENANCE-WORK-MEM
POSTGRES_MAINTENANCE_WORK_MEM=64MB

# Sets the planner's assumption about the effective cache size.
# Default is 4096MB
#
# Reference: https://www.postgresql.org/docs/current/runtime-config-query.html#GUC-EFFECTIVE-CACHE-SIZE
POSTGRES_EFFECTIVE_CACHE_SIZE=4096MB

# ------------------------------
# Redis Configuration
# This Redis configuration is used for caching and for pub/sub during conversation.
# ------------------------------

REDIS_HOST=redis
REDIS_PORT=6379
REDIS_USERNAME=
REDIS_PASSWORD=difyai123456
REDIS_USE_SSL=false
# SSL configuration for Redis (when REDIS_USE_SSL=true)
REDIS_SSL_CERT_REQS=CERT_NONE
# Options: CERT_NONE, CERT_OPTIONAL, CERT_REQUIRED
REDIS_SSL_CA_CERTS=
# Path to CA certificate file for SSL verification
REDIS_SSL_CERTFILE=
# Path to client certificate file for SSL authentication
REDIS_SSL_KEYFILE=
# Path to client private key file for SSL authentication
REDIS_DB=0

# Whether to use Redis Sentinel mode.
# If set to true, the application will automatically discover and connect to the master node through Sentinel.
REDIS_USE_SENTINEL=false

# List of Redis Sentinel nodes. If Sentinel mode is enabled, provide at least one Sentinel IP and port.
# Format: `<sentinel1_ip>:<sentinel1_port>,<sentinel2_ip>:<sentinel2_port>,<sentinel3_ip>:<sentinel3_port>`
REDIS_SENTINELS=
REDIS_SENTINEL_SERVICE_NAME=
REDIS_SENTINEL_USERNAME=
REDIS_SENTINEL_PASSWORD=
REDIS_SENTINEL_SOCKET_TIMEOUT=0.1

# List of Redis Cluster nodes. If Cluster mode is enabled, provide at least one Cluster IP and port.
# Format: `<Cluster1_ip>:<Cluster1_port>,<Cluster2_ip>:<Cluster2_port>,<Cluster3_ip>:<Cluster3_port>`
REDIS_USE_CLUSTERS=false
REDIS_CLUSTERS=
REDIS_CLUSTERS_PASSWORD=

# ------------------------------
# Celery Configuration
# ------------------------------

# Use standalone redis as the broker, and redis db 1 for celery broker. (redis_username is usually set by defualt as empty)
# Format as follows: `redis://<redis_username>:<redis_password>@<redis_host>:<redis_port>/<redis_database>`.
# Example: redis://:difyai123456@redis:6379/1
# If use Redis Sentinel, format as follows: `sentinel://<redis_username>:<redis_password>@<sentinel_host1>:<sentinel_port>/<redis_database>`
# For high availability, you can configure multiple Sentinel nodes (if provided) separated by semicolons like below example:
# Example: sentinel://:difyai123456@localhost:26379/1;sentinel://:difyai12345@localhost:26379/1;sentinel://:difyai12345@localhost:26379/1
CELERY_BROKER_URL=redis://:difyai123456@redis:6379/1
CELERY_BACKEND=redis
BROKER_USE_SSL=false

# If you are using Redis Sentinel for high availability, configure the following settings.
CELERY_USE_SENTINEL=false
CELERY_SENTINEL_MASTER_NAME=
CELERY_SENTINEL_PASSWORD=
CELERY_SENTINEL_SOCKET_TIMEOUT=0.1

# ------------------------------
# CORS Configuration
# Used to set the front-end cross-domain access policy.
# ------------------------------

# Specifies the allowed origins for cross-origin requests to the Web API,
# e.g. https://dify.app or * for all origins.
WEB_API_CORS_ALLOW_ORIGINS=*

# Specifies the allowed origins for cross-origin requests to the console API,
# e.g. https://cloud.dify.ai or * for all origins.
CONSOLE_CORS_ALLOW_ORIGINS=*

# ------------------------------
# File Storage Configuration
# ------------------------------

# The type of storage to use for storing user files.
STORAGE_TYPE=opendal

# Apache OpenDAL Configuration
# The configuration for OpenDAL consists of the following format: OPENDAL_<SCHEME_NAME>_<CONFIG_NAME>.
# You can find all the service configurations (CONFIG_NAME) in the repository at: https://github.com/apache/opendal/tree/main/core/src/services.
# Dify will scan configurations starting with OPENDAL_<SCHEME_NAME> and automatically apply them.
# The scheme name for the OpenDAL storage.
OPENDAL_SCHEME=fs
# Configurations for OpenDAL Local File System.
OPENDAL_FS_ROOT=storage

# ClickZetta Volume Configuration (for storage backend)
# To use ClickZetta Volume as storage backend, set STORAGE_TYPE=clickzetta-volume
# Note: ClickZetta Volume will reuse the existing CLICKZETTA_* connection parameters

# Volume type selection (three types available):
# - user: Personal/small team use, simple config, user-level permissions
# - table: Enterprise multi-tenant, smart routing, table-level + user-level permissions
# - external: Data lake integration, external storage connection, volume-level + storage-level permissions
CLICKZETTA_VOLUME_TYPE=user

# External Volume name (required only when TYPE=external)
CLICKZETTA_VOLUME_NAME=

# Table Volume table prefix (used only when TYPE=table)
CLICKZETTA_VOLUME_TABLE_PREFIX=dataset_

# Dify file directory prefix (isolates from other apps, recommended to keep default)
CLICKZETTA_VOLUME_DIFY_PREFIX=dify_km

# S3 Configuration
#
S3_ENDPOINT=
S3_REGION=us-east-1
S3_BUCKET_NAME=difyai
S3_ACCESS_KEY=
S3_SECRET_KEY=
# Whether to use AWS managed IAM roles for authenticating with the S3 service.
# If set to false, the access key and secret key must be provided.
S3_USE_AWS_MANAGED_IAM=false

# Azure Blob Configuration
#
AZURE_BLOB_ACCOUNT_NAME=difyai
AZURE_BLOB_ACCOUNT_KEY=difyai
AZURE_BLOB_CONTAINER_NAME=difyai-container
AZURE_BLOB_ACCOUNT_URL=https://<your_account_name>.blob.core.windows.net

# Google Storage Configuration
#
GOOGLE_STORAGE_BUCKET_NAME=your-bucket-name
GOOGLE_STORAGE_SERVICE_ACCOUNT_JSON_BASE64=

# The Alibaba Cloud OSS configurations,
#
ALIYUN_OSS_BUCKET_NAME=your-bucket-name
ALIYUN_OSS_ACCESS_KEY=your-access-key
ALIYUN_OSS_SECRET_KEY=your-secret-key
ALIYUN_OSS_ENDPOINT=https://oss-ap-southeast-1-internal.aliyuncs.com
ALIYUN_OSS_REGION=ap-southeast-1
ALIYUN_OSS_AUTH_VERSION=v4
# Don't start with '/'. OSS doesn't support leading slash in object names.
ALIYUN_OSS_PATH=your-path

# Tencent COS Configuration
#
TENCENT_COS_BUCKET_NAME=your-bucket-name
TENCENT_COS_SECRET_KEY=your-secret-key
TENCENT_COS_SECRET_ID=your-secret-id
TENCENT_COS_REGION=your-region
TENCENT_COS_SCHEME=your-scheme

# Oracle Storage Configuration
#
OCI_ENDPOINT=https://your-object-storage-namespace.compat.objectstorage.us-ashburn-1.oraclecloud.com
OCI_BUCKET_NAME=your-bucket-name
OCI_ACCESS_KEY=your-access-key
OCI_SECRET_KEY=your-secret-key
OCI_REGION=us-ashburn-1

# Huawei OBS Configuration
#
HUAWEI_OBS_BUCKET_NAME=your-bucket-name
HUAWEI_OBS_SECRET_KEY=your-secret-key
HUAWEI_OBS_ACCESS_KEY=your-access-key
HUAWEI_OBS_SERVER=your-server-url

# Volcengine TOS Configuration
#
VOLCENGINE_TOS_BUCKET_NAME=your-bucket-name
VOLCENGINE_TOS_SECRET_KEY=your-secret-key
VOLCENGINE_TOS_ACCESS_KEY=your-access-key
VOLCENGINE_TOS_ENDPOINT=your-server-url
VOLCENGINE_TOS_REGION=your-region

# Baidu OBS Storage Configuration
#
BAIDU_OBS_BUCKET_NAME=your-bucket-name
BAIDU_OBS_SECRET_KEY=your-secret-key
BAIDU_OBS_ACCESS_KEY=your-access-key
BAIDU_OBS_ENDPOINT=your-server-url

# Supabase Storage Configuration
#
SUPABASE_BUCKET_NAME=your-bucket-name
SUPABASE_API_KEY=your-access-key
SUPABASE_URL=your-server-url

# ------------------------------
# Vector Database Configuration
# ------------------------------

# The type of vector store to use.
# Supported values are `weaviate`, `qdrant`, `milvus`, `myscale`, `relyt`, `pgvector`, `pgvecto-rs`, `chroma`, `opensearch`, `oracle`, `tencent`, `elasticsearch`, `elasticsearch-ja`, `analyticdb`, `couchbase`, `vikingdb`, `oceanbase`, `opengauss`, `tablestore`,`vastbase`,`tidb`,`tidb_on_qdrant`,`baidu`,`lindorm`,`huawei_cloud`,`upstash`, `matrixone`, `clickzetta`.
VECTOR_STORE=weaviate
# Prefix used to create collection name in vector database
VECTOR_INDEX_NAME_PREFIX=Vector_index

# The Weaviate endpoint URL. Only available when VECTOR_STORE is `weaviate`.
WEAVIATE_ENDPOINT=http://weaviate:8080
WEAVIATE_API_KEY=WVF5YThaHlkYwhGUSmCRgsX3tD5ngdN8pkih

# The Qdrant endpoint URL. Only available when VECTOR_STORE is `qdrant`.
QDRANT_URL=http://qdrant:6333
QDRANT_API_KEY=difyai123456
QDRANT_CLIENT_TIMEOUT=20
QDRANT_GRPC_ENABLED=false
QDRANT_GRPC_PORT=6334
QDRANT_REPLICATION_FACTOR=1

# Milvus configuration. Only available when VECTOR_STORE is `milvus`.
# The milvus uri.
MILVUS_URI=http://host.docker.internal:19530
MILVUS_DATABASE=
MILVUS_TOKEN=
MILVUS_USER=
MILVUS_PASSWORD=
MILVUS_ENABLE_HYBRID_SEARCH=False
MILVUS_ANALYZER_PARAMS=

# MyScale configuration, only available when VECTOR_STORE is `myscale`
# For multi-language support, please set MYSCALE_FTS_PARAMS with referring to:
# https://myscale.com/docs/en/text-search/#understanding-fts-index-parameters
MYSCALE_HOST=myscale
MYSCALE_PORT=8123
MYSCALE_USER=default
MYSCALE_PASSWORD=
MYSCALE_DATABASE=dify
MYSCALE_FTS_PARAMS=

# Couchbase configurations, only available when VECTOR_STORE is `couchbase`
# The connection string must include hostname defined in the docker-compose file (couchbase-server in this case)
COUCHBASE_CONNECTION_STRING=couchbase://couchbase-server
COUCHBASE_USER=Administrator
COUCHBASE_PASSWORD=password
COUCHBASE_BUCKET_NAME=Embeddings
COUCHBASE_SCOPE_NAME=_default

# pgvector configurations, only available when VECTOR_STORE is `pgvector`
PGVECTOR_HOST=pgvector
PGVECTOR_PORT=5432
PGVECTOR_USER=postgres
PGVECTOR_PASSWORD=difyai123456
PGVECTOR_DATABASE=dify
PGVECTOR_MIN_CONNECTION=1
PGVECTOR_MAX_CONNECTION=5
PGVECTOR_PG_BIGM=false
PGVECTOR_PG_BIGM_VERSION=1.2-20240606

# vastbase configurations, only available when VECTOR_STORE is `vastbase`
VASTBASE_HOST=vastbase
VASTBASE_PORT=5432
VASTBASE_USER=dify
VASTBASE_PASSWORD=Difyai123456
VASTBASE_DATABASE=dify
VASTBASE_MIN_CONNECTION=1
VASTBASE_MAX_CONNECTION=5

# pgvecto-rs configurations, only available when VECTOR_STORE is `pgvecto-rs`
PGVECTO_RS_HOST=pgvecto-rs
PGVECTO_RS_PORT=5432
PGVECTO_RS_USER=postgres
PGVECTO_RS_PASSWORD=difyai123456
PGVECTO_RS_DATABASE=dify

# analyticdb configurations, only available when VECTOR_STORE is `analyticdb`
ANALYTICDB_KEY_ID=your-ak
ANALYTICDB_KEY_SECRET=your-sk
ANALYTICDB_REGION_ID=cn-hangzhou
ANALYTICDB_INSTANCE_ID=gp-ab123456
ANALYTICDB_ACCOUNT=testaccount
ANALYTICDB_PASSWORD=testpassword
ANALYTICDB_NAMESPACE=dify
ANALYTICDB_NAMESPACE_PASSWORD=difypassword
ANALYTICDB_HOST=gp-test.aliyuncs.com
ANALYTICDB_PORT=5432
ANALYTICDB_MIN_CONNECTION=1
ANALYTICDB_MAX_CONNECTION=5

# TiDB vector configurations, only available when VECTOR_STORE is `tidb_vector`
TIDB_VECTOR_HOST=tidb
TIDB_VECTOR_PORT=4000
TIDB_VECTOR_USER=
TIDB_VECTOR_PASSWORD=
TIDB_VECTOR_DATABASE=dify

# Matrixone vector configurations.
MATRIXONE_HOST=matrixone
MATRIXONE_PORT=6001
MATRIXONE_USER=dump
MATRIXONE_PASSWORD=111
MATRIXONE_DATABASE=dify

# Tidb on qdrant configuration, only available when VECTOR_STORE is `tidb_on_qdrant`
TIDB_ON_QDRANT_URL=http://127.0.0.1
TIDB_ON_QDRANT_API_KEY=dify
TIDB_ON_QDRANT_CLIENT_TIMEOUT=20
TIDB_ON_QDRANT_GRPC_ENABLED=false
TIDB_ON_QDRANT_GRPC_PORT=6334
TIDB_PUBLIC_KEY=dify
TIDB_PRIVATE_KEY=dify
TIDB_API_URL=http://127.0.0.1
TIDB_IAM_API_URL=http://127.0.0.1
TIDB_REGION=regions/aws-us-east-1
TIDB_PROJECT_ID=dify
TIDB_SPEND_LIMIT=100

# Chroma configuration, only available when VECTOR_STORE is `chroma`
CHROMA_HOST=127.0.0.1
CHROMA_PORT=8000
CHROMA_TENANT=default_tenant
CHROMA_DATABASE=default_database
CHROMA_AUTH_PROVIDER=chromadb.auth.token_authn.TokenAuthClientProvider
CHROMA_AUTH_CREDENTIALS=

# Oracle configuration, only available when VECTOR_STORE is `oracle`
ORACLE_USER=dify
ORACLE_PASSWORD=dify
ORACLE_DSN=oracle:1521/FREEPDB1
ORACLE_CONFIG_DIR=/app/api/storage/wallet
ORACLE_WALLET_LOCATION=/app/api/storage/wallet
ORACLE_WALLET_PASSWORD=dify
ORACLE_IS_AUTONOMOUS=false

# relyt configurations, only available when VECTOR_STORE is `relyt`
RELYT_HOST=db
RELYT_PORT=5432
RELYT_USER=postgres
RELYT_PASSWORD=difyai123456
RELYT_DATABASE=postgres

# open search configuration, only available when VECTOR_STORE is `opensearch`
OPENSEARCH_HOST=opensearch
OPENSEARCH_PORT=9200
OPENSEARCH_SECURE=true
OPENSEARCH_VERIFY_CERTS=true
OPENSEARCH_AUTH_METHOD=basic
OPENSEARCH_USER=admin
OPENSEARCH_PASSWORD=admin
# If using AWS managed IAM, e.g. Managed Cluster or OpenSearch Serverless
OPENSEARCH_AWS_REGION=ap-southeast-1
OPENSEARCH_AWS_SERVICE=aoss

# tencent vector configurations, only available when VECTOR_STORE is `tencent`
TENCENT_VECTOR_DB_URL=http://127.0.0.1
TENCENT_VECTOR_DB_API_KEY=dify
TENCENT_VECTOR_DB_TIMEOUT=30
TENCENT_VECTOR_DB_USERNAME=dify
TENCENT_VECTOR_DB_DATABASE=dify
TENCENT_VECTOR_DB_SHARD=1
TENCENT_VECTOR_DB_REPLICAS=2
TENCENT_VECTOR_DB_ENABLE_HYBRID_SEARCH=false

# ElasticSearch configuration, only available when VECTOR_STORE is `elasticsearch`
ELASTICSEARCH_HOST=0.0.0.0
ELASTICSEARCH_PORT=9200
ELASTICSEARCH_USERNAME=elastic
ELASTICSEARCH_PASSWORD=elastic
KIBANA_PORT=5601

# Using ElasticSearch Cloud Serverless, or not.
ELASTICSEARCH_USE_CLOUD=false
ELASTICSEARCH_CLOUD_URL=YOUR-ELASTICSEARCH_CLOUD_URL
ELASTICSEARCH_API_KEY=YOUR-ELASTICSEARCH_API_KEY

ELASTICSEARCH_VERIFY_CERTS=False
ELASTICSEARCH_CA_CERTS=
ELASTICSEARCH_REQUEST_TIMEOUT=100000
ELASTICSEARCH_RETRY_ON_TIMEOUT=True
ELASTICSEARCH_MAX_RETRIES=10

# baidu vector configurations, only available when VECTOR_STORE is `baidu`
BAIDU_VECTOR_DB_ENDPOINT=http://127.0.0.1:5287
BAIDU_VECTOR_DB_CONNECTION_TIMEOUT_MS=30000
BAIDU_VECTOR_DB_ACCOUNT=root
BAIDU_VECTOR_DB_API_KEY=dify
BAIDU_VECTOR_DB_DATABASE=dify
BAIDU_VECTOR_DB_SHARD=1
BAIDU_VECTOR_DB_REPLICAS=3

# VikingDB configurations, only available when VECTOR_STORE is `vikingdb`
VIKINGDB_ACCESS_KEY=your-ak
VIKINGDB_SECRET_KEY=your-sk
VIKINGDB_REGION=cn-shanghai
VIKINGDB_HOST=api-vikingdb.xxx.volces.com
VIKINGDB_SCHEMA=http
VIKINGDB_CONNECTION_TIMEOUT=30
VIKINGDB_SOCKET_TIMEOUT=30

# Lindorm configuration, only available when VECTOR_STORE is `lindorm`
LINDORM_URL=http://lindorm:30070
LINDORM_USERNAME=lindorm
LINDORM_PASSWORD=lindorm
LINDORM_QUERY_TIMEOUT=1

# OceanBase Vector configuration, only available when VECTOR_STORE is `oceanbase`
OCEANBASE_VECTOR_HOST=oceanbase
OCEANBASE_VECTOR_PORT=2881
OCEANBASE_VECTOR_USER=root@test
OCEANBASE_VECTOR_PASSWORD=difyai123456
OCEANBASE_VECTOR_DATABASE=test
OCEANBASE_CLUSTER_NAME=difyai
OCEANBASE_MEMORY_LIMIT=6G
OCEANBASE_ENABLE_HYBRID_SEARCH=false

# opengauss configurations, only available when VECTOR_STORE is `opengauss`
OPENGAUSS_HOST=opengauss
OPENGAUSS_PORT=6600
OPENGAUSS_USER=postgres
OPENGAUSS_PASSWORD=Dify@123
OPENGAUSS_DATABASE=dify
OPENGAUSS_MIN_CONNECTION=1
OPENGAUSS_MAX_CONNECTION=5
OPENGAUSS_ENABLE_PQ=false

# huawei cloud search service vector configurations, only available when VECTOR_STORE is `huawei_cloud`
HUAWEI_CLOUD_HOSTS=https://127.0.0.1:9200
HUAWEI_CLOUD_USER=admin
HUAWEI_CLOUD_PASSWORD=admin

# Upstash Vector configuration, only available when VECTOR_STORE is `upstash`
UPSTASH_VECTOR_URL=https://xxx-vector.upstash.io
UPSTASH_VECTOR_TOKEN=dify

# TableStore Vector configuration
# (only used when VECTOR_STORE is tablestore)
TABLESTORE_ENDPOINT=https://instance-name.cn-hangzhou.ots.aliyuncs.com
TABLESTORE_INSTANCE_NAME=instance-name
TABLESTORE_ACCESS_KEY_ID=xxx
TABLESTORE_ACCESS_KEY_SECRET=xxx
TABLESTORE_NORMALIZE_FULLTEXT_BM25_SCORE=false

# Clickzetta configuration, only available when VECTOR_STORE is `clickzetta`
CLICKZETTA_USERNAME=
CLICKZETTA_PASSWORD=
CLICKZETTA_INSTANCE=
CLICKZETTA_SERVICE=api.clickzetta.com
CLICKZETTA_WORKSPACE=quick_start
CLICKZETTA_VCLUSTER=default_ap
CLICKZETTA_SCHEMA=dify
CLICKZETTA_BATCH_SIZE=100
CLICKZETTA_ENABLE_INVERTED_INDEX=true
CLICKZETTA_ANALYZER_TYPE=chinese
CLICKZETTA_ANALYZER_MODE=smart
CLICKZETTA_VECTOR_DISTANCE_FUNCTION=cosine_distance

# ------------------------------
# Knowledge Configuration
# ------------------------------

# Upload file size limit, default 15M.
UPLOAD_FILE_SIZE_LIMIT=15

# The maximum number of files that can be uploaded at a time, default 5.
UPLOAD_FILE_BATCH_LIMIT=5

# ETL type, support: `dify`, `Unstructured`
# `dify` Dify's proprietary file extraction scheme
# `Unstructured` Unstructured.io file extraction scheme
ETL_TYPE=dify

# Unstructured API path and API key, needs to be configured when ETL_TYPE is Unstructured
# Or using Unstructured for document extractor node for pptx.
# For example: http://unstructured:8000/general/v0/general
UNSTRUCTURED_API_URL=
UNSTRUCTURED_API_KEY=
SCARF_NO_ANALYTICS=true

# ------------------------------
# Model Configuration
# ------------------------------

# The maximum number of tokens allowed for prompt generation.
# This setting controls the upper limit of tokens that can be used by the LLM
# when generating a prompt in the prompt generation tool.
# Default: 512 tokens.
PROMPT_GENERATION_MAX_TOKENS=512

# The maximum number of tokens allowed for code generation.
# This setting controls the upper limit of tokens that can be used by the LLM
# when generating code in the code generation tool.
# Default: 1024 tokens.
CODE_GENERATION_MAX_TOKENS=1024

# Enable or disable plugin based token counting. If disabled, token counting will return 0.
# This can improve performance by skipping token counting operations.
# Default: false (disabled).
PLUGIN_BASED_TOKEN_COUNTING_ENABLED=false

# ------------------------------
# Multi-modal Configuration
# ------------------------------

# The format of the image/video/audio/document sent when the multi-modal model is input,
# the default is base64, optional url.
# The delay of the call in url mode will be lower than that in base64 mode.
# It is generally recommended to use the more compatible base64 mode.
# If configured as url, you need to configure FILES_URL as an externally accessible address so that the multi-modal model can access the image/video/audio/document.
MULTIMODAL_SEND_FORMAT=base64
# Upload image file size limit, default 10M.
UPLOAD_IMAGE_FILE_SIZE_LIMIT=10
# Upload video file size limit, default 100M.
UPLOAD_VIDEO_FILE_SIZE_LIMIT=100
# Upload audio file size limit, default 50M.
UPLOAD_AUDIO_FILE_SIZE_LIMIT=50

# ------------------------------
# Sentry Configuration
# Used for application monitoring and error log tracking.
# ------------------------------
SENTRY_DSN=

# API Service Sentry DSN address, default is empty, when empty,
# all monitoring information is not reported to Sentry.
# If not set, Sentry error reporting will be disabled.
API_SENTRY_DSN=
# API Service The reporting ratio of Sentry events, if it is 0.01, it is 1%.
API_SENTRY_TRACES_SAMPLE_RATE=1.0
# API Service The reporting ratio of Sentry profiles, if it is 0.01, it is 1%.
API_SENTRY_PROFILES_SAMPLE_RATE=1.0

# Web Service Sentry DSN address, default is empty, when empty,
# all monitoring information is not reported to Sentry.
# If not set, Sentry error reporting will be disabled.
WEB_SENTRY_DSN=

# ------------------------------
# Notion Integration Configuration
# Variables can be obtained by applying for Notion integration: https://www.notion.so/my-integrations
# ------------------------------

# Configure as "public" or "internal".
# Since Notion's OAuth redirect URL only supports HTTPS,
# if deploying locally, please use Notion's internal integration.
NOTION_INTEGRATION_TYPE=public
# Notion OAuth client secret (used for public integration type)
NOTION_CLIENT_SECRET=
# Notion OAuth client id (used for public integration type)
NOTION_CLIENT_ID=
# Notion internal integration secret.
# If the value of NOTION_INTEGRATION_TYPE is "internal",
# you need to configure this variable.
NOTION_INTERNAL_SECRET=

# ------------------------------
# Mail related configuration
# ------------------------------

# Mail type, support: resend, smtp, sendgrid
MAIL_TYPE=resend

# Default send from email address, if not specified
# If using SendGrid, use the 'from' field for authentication if necessary.
MAIL_DEFAULT_SEND_FROM=

# API-Key for the Resend email provider, used when MAIL_TYPE is `resend`.
RESEND_API_URL=https://api.resend.com
RESEND_API_KEY=your-resend-api-key


# SMTP server configuration, used when MAIL_TYPE is `smtp`
SMTP_SERVER=
SMTP_PORT=465
SMTP_USERNAME=
SMTP_PASSWORD=
SMTP_USE_TLS=true
SMTP_OPPORTUNISTIC_TLS=false

# Sendgid configuration
SENDGRID_API_KEY=

# ------------------------------
# Others Configuration
# ------------------------------

# Maximum length of segmentation tokens for indexing
INDEXING_MAX_SEGMENTATION_TOKENS_LENGTH=4000

# Member invitation link valid time (hours),
# Default: 72.
INVITE_EXPIRY_HOURS=72

# Reset password token valid time (minutes),
RESET_PASSWORD_TOKEN_EXPIRY_MINUTES=5
CHANGE_EMAIL_TOKEN_EXPIRY_MINUTES=5
OWNER_TRANSFER_TOKEN_EXPIRY_MINUTES=5

# The sandbox service endpoint.
CODE_EXECUTION_ENDPOINT=http://sandbox:8194
CODE_EXECUTION_API_KEY=dify-sandbox
CODE_MAX_NUMBER=9223372036854775807
CODE_MIN_NUMBER=-9223372036854775808
CODE_MAX_DEPTH=5
CODE_MAX_PRECISION=20
CODE_MAX_STRING_LENGTH=80000
CODE_MAX_STRING_ARRAY_LENGTH=30
CODE_MAX_OBJECT_ARRAY_LENGTH=30
CODE_MAX_NUMBER_ARRAY_LENGTH=1000
CODE_EXECUTION_CONNECT_TIMEOUT=10
CODE_EXECUTION_READ_TIMEOUT=60
CODE_EXECUTION_WRITE_TIMEOUT=10
TEMPLATE_TRANSFORM_MAX_LENGTH=80000

# Workflow runtime configuration
WORKFLOW_MAX_EXECUTION_STEPS=500
WORKFLOW_MAX_EXECUTION_TIME=1200
WORKFLOW_CALL_MAX_DEPTH=5
MAX_VARIABLE_SIZE=204800
WORKFLOW_PARALLEL_DEPTH_LIMIT=3
WORKFLOW_FILE_UPLOAD_LIMIT=10

# Workflow storage configuration
# Options: rdbms, hybrid
# rdbms: Use only the relational database (default)
# hybrid: Save new data to object storage, read from both object storage and RDBMS
WORKFLOW_NODE_EXECUTION_STORAGE=rdbms

# Repository configuration
# Core workflow execution repository implementation
# Options:
#   - core.repositories.sqlalchemy_workflow_execution_repository.SQLAlchemyWorkflowExecutionRepository (default)
#   - core.repositories.celery_workflow_execution_repository.CeleryWorkflowExecutionRepository
CORE_WORKFLOW_EXECUTION_REPOSITORY=core.repositories.sqlalchemy_workflow_execution_repository.SQLAlchemyWorkflowExecutionRepository

# Core workflow node execution repository implementation
# Options:
#   - core.repositories.sqlalchemy_workflow_node_execution_repository.SQLAlchemyWorkflowNodeExecutionRepository (default)
#   - core.repositories.celery_workflow_node_execution_repository.CeleryWorkflowNodeExecutionRepository
CORE_WORKFLOW_NODE_EXECUTION_REPOSITORY=core.repositories.sqlalchemy_workflow_node_execution_repository.SQLAlchemyWorkflowNodeExecutionRepository

# API workflow run repository implementation
API_WORKFLOW_RUN_REPOSITORY=repositories.sqlalchemy_api_workflow_run_repository.DifyAPISQLAlchemyWorkflowRunRepository

# API workflow node execution repository implementation
API_WORKFLOW_NODE_EXECUTION_REPOSITORY=repositories.sqlalchemy_api_workflow_node_execution_repository.DifyAPISQLAlchemyWorkflowNodeExecutionRepository

# Workflow log cleanup configuration
# Enable automatic cleanup of workflow run logs to manage database size
WORKFLOW_LOG_CLEANUP_ENABLED=false
# Number of days to retain workflow run logs (default: 30 days)
WORKFLOW_LOG_RETENTION_DAYS=30
# Batch size for workflow log cleanup operations (default: 100)
WORKFLOW_LOG_CLEANUP_BATCH_SIZE=100

# HTTP request node in workflow configuration
HTTP_REQUEST_NODE_MAX_BINARY_SIZE=10485760
HTTP_REQUEST_NODE_MAX_TEXT_SIZE=1048576
HTTP_REQUEST_NODE_SSL_VERIFY=True

# Respect X-* headers to redirect clients
RESPECT_XFORWARD_HEADERS_ENABLED=false

# SSRF Proxy server HTTP URL
SSRF_PROXY_HTTP_URL=http://ssrf_proxy:3128
# SSRF Proxy server HTTPS URL
SSRF_PROXY_HTTPS_URL=http://ssrf_proxy:3128

# Maximum loop count in the workflow
LOOP_NODE_MAX_COUNT=100

# The maximum number of tools that can be used in the agent.
MAX_TOOLS_NUM=10

# Maximum number of Parallelism branches in the workflow
MAX_PARALLEL_LIMIT=10

# The maximum number of iterations for agent setting
MAX_ITERATIONS_NUM=99

# ------------------------------
# Environment Variables for web Service
# ------------------------------

# The timeout for the text generation in millisecond
TEXT_GENERATION_TIMEOUT_MS=60000

# Allow rendering unsafe URLs which have "data:" scheme.
ALLOW_UNSAFE_DATA_SCHEME=false

# Maximum number of tree depth in the workflow
MAX_TREE_DEPTH=50

# ------------------------------
# Environment Variables for db Service
# ------------------------------

# The name of the default postgres user.
POSTGRES_USER=${DB_USERNAME}
# The password for the default postgres user.
POSTGRES_PASSWORD=${DB_PASSWORD}
# The name of the default postgres database.
POSTGRES_DB=${DB_DATABASE}
# postgres data directory
PGDATA=/var/lib/postgresql/data/pgdata

# ------------------------------
# Environment Variables for sandbox Service
# ------------------------------

# The API key for the sandbox service
SANDBOX_API_KEY=dify-sandbox
# The mode in which the Gin framework runs
SANDBOX_GIN_MODE=release
# The timeout for the worker in seconds
SANDBOX_WORKER_TIMEOUT=15
# Enable network for the sandbox service
SANDBOX_ENABLE_NETWORK=true
# HTTP proxy URL for SSRF protection
SANDBOX_HTTP_PROXY=http://ssrf_proxy:3128
# HTTPS proxy URL for SSRF protection
SANDBOX_HTTPS_PROXY=http://ssrf_proxy:3128
# The port on which the sandbox service runs
SANDBOX_PORT=8194

# ------------------------------
# Environment Variables for weaviate Service
# (only used when VECTOR_STORE is weaviate)
# ------------------------------
WEAVIATE_PERSISTENCE_DATA_PATH=/var/lib/weaviate
WEAVIATE_QUERY_DEFAULTS_LIMIT=25
WEAVIATE_AUTHENTICATION_ANONYMOUS_ACCESS_ENABLED=true
WEAVIATE_DEFAULT_VECTORIZER_MODULE=none
WEAVIATE_CLUSTER_HOSTNAME=node1
WEAVIATE_AUTHENTICATION_APIKEY_ENABLED=true
WEAVIATE_AUTHENTICATION_APIKEY_ALLOWED_KEYS=WVF5YThaHlkYwhGUSmCRgsX3tD5ngdN8pkih
[email protected]
WEAVIATE_AUTHORIZATION_ADMINLIST_ENABLED=true
[email protected]

# ------------------------------
# Environment Variables for Chroma
# (only used when VECTOR_STORE is chroma)
# ------------------------------

# Authentication credentials for Chroma server
CHROMA_SERVER_AUTHN_CREDENTIALS=difyai123456
# Authentication provider for Chroma server
CHROMA_SERVER_AUTHN_PROVIDER=chromadb.auth.token_authn.TokenAuthenticationServerProvider
# Persistence setting for Chroma server
CHROMA_IS_PERSISTENT=TRUE

# ------------------------------
# Environment Variables for Oracle Service
# (only used when VECTOR_STORE is oracle)
# ------------------------------
ORACLE_PWD=Dify123456
ORACLE_CHARACTERSET=AL32UTF8

# ------------------------------
# Environment Variables for milvus Service
# (only used when VECTOR_STORE is milvus)
# ------------------------------
# ETCD configuration for auto compaction mode
ETCD_AUTO_COMPACTION_MODE=revision
# ETCD configuration for auto compaction retention in terms of number of revisions
ETCD_AUTO_COMPACTION_RETENTION=1000
# ETCD configuration for backend quota in bytes
ETCD_QUOTA_BACKEND_BYTES=4294967296
# ETCD configuration for the number of changes before triggering a snapshot
ETCD_SNAPSHOT_COUNT=50000
# MinIO access key for authentication
MINIO_ACCESS_KEY=minioadmin
# MinIO secret key for authentication
MINIO_SECRET_KEY=minioadmin
# ETCD service endpoints
ETCD_ENDPOINTS=etcd:2379
# MinIO service address
MINIO_ADDRESS=minio:9000
# Enable or disable security authorization
MILVUS_AUTHORIZATION_ENABLED=true

# ------------------------------
# Environment Variables for pgvector / pgvector-rs Service
# (only used when VECTOR_STORE is pgvector / pgvector-rs)
# ------------------------------
PGVECTOR_PGUSER=postgres
# The password for the default postgres user.
PGVECTOR_POSTGRES_PASSWORD=difyai123456
# The name of the default postgres database.
PGVECTOR_POSTGRES_DB=dify
# postgres data directory
PGVECTOR_PGDATA=/var/lib/postgresql/data/pgdata

# ------------------------------
# Environment Variables for opensearch
# (only used when VECTOR_STORE is opensearch)
# ------------------------------
OPENSEARCH_DISCOVERY_TYPE=single-node
OPENSEARCH_BOOTSTRAP_MEMORY_LOCK=true
OPENSEARCH_JAVA_OPTS_MIN=512m
OPENSEARCH_JAVA_OPTS_MAX=1024m
OPENSEARCH_INITIAL_ADMIN_PASSWORD=Qazwsxedc!@#123
OPENSEARCH_MEMLOCK_SOFT=-1
OPENSEARCH_MEMLOCK_HARD=-1
OPENSEARCH_NOFILE_SOFT=65536
OPENSEARCH_NOFILE_HARD=65536

# ------------------------------
# Environment Variables for Nginx reverse proxy
# ------------------------------
NGINX_SERVER_NAME=_
NGINX_HTTPS_ENABLED=false
# HTTP port
NGINX_PORT=80
# SSL settings are only applied when HTTPS_ENABLED is true
NGINX_SSL_PORT=443
# if HTTPS_ENABLED is true, you're required to add your own SSL certificates/keys to the `./nginx/ssl` directory
# and modify the env vars below accordingly.
NGINX_SSL_CERT_FILENAME=dify.crt
NGINX_SSL_CERT_KEY_FILENAME=dify.key
NGINX_SSL_PROTOCOLS=TLSv1.1 TLSv1.2 TLSv1.3

# Nginx performance tuning
NGINX_WORKER_PROCESSES=auto
NGINX_CLIENT_MAX_BODY_SIZE=100M
NGINX_KEEPALIVE_TIMEOUT=65

# Proxy settings
NGINX_PROXY_READ_TIMEOUT=3600s
NGINX_PROXY_SEND_TIMEOUT=3600s

# Set true to accept requests for /.well-known/acme-challenge/
NGINX_ENABLE_CERTBOT_CHALLENGE=false

# ------------------------------
# Certbot Configuration
# ------------------------------

# Email address (required to get certificates from Let's Encrypt)
[email protected]

# Domain name
CERTBOT_DOMAIN=your_domain.com

# certbot command options
# i.e: --force-renewal --dry-run --test-cert --debug
CERTBOT_OPTIONS=

# ------------------------------
# Environment Variables for SSRF Proxy
# ------------------------------
SSRF_HTTP_PORT=3128
SSRF_COREDUMP_DIR=/var/spool/squid
SSRF_REVERSE_PROXY_PORT=8194
SSRF_SANDBOX_HOST=sandbox
SSRF_DEFAULT_TIME_OUT=5
SSRF_DEFAULT_CONNECT_TIME_OUT=5
SSRF_DEFAULT_READ_TIME_OUT=5
SSRF_DEFAULT_WRITE_TIME_OUT=5

# ------------------------------
# docker env var for specifying vector db type at startup
# (based on the vector db type, the corresponding docker
# compose profile will be used)
# if you want to use unstructured, add ',unstructured' to the end
# ------------------------------
COMPOSE_PROFILES=${VECTOR_STORE:-weaviate}

# ------------------------------
# Docker Compose Service Expose Host Port Configurations
# ------------------------------
EXPOSE_NGINX_PORT=80
EXPOSE_NGINX_SSL_PORT=443

# ----------------------------------------------------------------------------
# ModelProvider & Tool Position Configuration
# Used to specify the model providers and tools that can be used in the app.
# ----------------------------------------------------------------------------

# Pin, include, and exclude tools
# Use comma-separated values with no spaces between items.
# Example: POSITION_TOOL_PINS=bing,google
POSITION_TOOL_PINS=
POSITION_TOOL_INCLUDES=
POSITION_TOOL_EXCLUDES=

# Pin, include, and exclude model providers
# Use comma-separated values with no spaces between items.
# Example: POSITION_PROVIDER_PINS=openai,openllm
POSITION_PROVIDER_PINS=
POSITION_PROVIDER_INCLUDES=
POSITION_PROVIDER_EXCLUDES=

# CSP https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP
CSP_WHITELIST=

# Enable or disable create tidb service job
CREATE_TIDB_SERVICE_JOB_ENABLED=false

# Maximum number of submitted thread count in a ThreadPool for parallel node execution
MAX_SUBMIT_COUNT=100

# The maximum number of top-k value for RAG.
TOP_K_MAX_VALUE=10

# ------------------------------
# Plugin Daemon Configuration
# ------------------------------

DB_PLUGIN_DATABASE=dify_plugin
EXPOSE_PLUGIN_DAEMON_PORT=5002
PLUGIN_DAEMON_PORT=5002
PLUGIN_DAEMON_KEY=lYkiYYT6owG+71oLerGzA7GXCgOT++6ovaezWAjpCjf+Sjc3ZtU+qUEi
PLUGIN_DAEMON_URL=http://plugin_daemon:5002
PLUGIN_MAX_PACKAGE_SIZE=52428800
PLUGIN_PPROF_ENABLED=false

PLUGIN_DEBUGGING_HOST=0.0.0.0
PLUGIN_DEBUGGING_PORT=5003
EXPOSE_PLUGIN_DEBUGGING_HOST=localhost
EXPOSE_PLUGIN_DEBUGGING_PORT=5003

# If this key is changed, DIFY_INNER_API_KEY in plugin_daemon service must also be updated or agent node will fail.
PLUGIN_DIFY_INNER_API_KEY=QaHbTe77CtuXmsfyhR7+vRjI/+XbV1AaFy691iy+kGDv2Jvy0/eAh8Y1
PLUGIN_DIFY_INNER_API_URL=http://api:5001

ENDPOINT_URL_TEMPLATE=http://localhost/e/{hook_id}

MARKETPLACE_ENABLED=true
MARKETPLACE_API_URL=https://marketplace.dify.ai

FORCE_VERIFYING_SIGNATURE=true

PLUGIN_STDIO_BUFFER_SIZE=1024
PLUGIN_STDIO_MAX_BUFFER_SIZE=5242880

PLUGIN_PYTHON_ENV_INIT_TIMEOUT=120
PLUGIN_MAX_EXECUTION_TIMEOUT=600
# PIP_MIRROR_URL=https://pypi.tuna.tsinghua.edu.cn/simple
PIP_MIRROR_URL=

# https://github.com/langgenius/dify-plugin-daemon/blob/main/.env.example
# Plugin storage type, local aws_s3 tencent_cos azure_blob aliyun_oss volcengine_tos
PLUGIN_STORAGE_TYPE=local
PLUGIN_STORAGE_LOCAL_ROOT=/app/storage
PLUGIN_WORKING_PATH=/app/storage/cwd
PLUGIN_INSTALLED_PATH=plugin
PLUGIN_PACKAGE_CACHE_PATH=plugin_packages
PLUGIN_MEDIA_CACHE_PATH=assets
# Plugin oss bucket
PLUGIN_STORAGE_OSS_BUCKET=
# Plugin oss s3 credentials
PLUGIN_S3_USE_AWS=false
PLUGIN_S3_USE_AWS_MANAGED_IAM=false
PLUGIN_S3_ENDPOINT=
PLUGIN_S3_USE_PATH_STYLE=false
PLUGIN_AWS_ACCESS_KEY=
PLUGIN_AWS_SECRET_KEY=
PLUGIN_AWS_REGION=
# Plugin oss azure blob
PLUGIN_AZURE_BLOB_STORAGE_CONTAINER_NAME=
PLUGIN_AZURE_BLOB_STORAGE_CONNECTION_STRING=
# Plugin oss tencent cos
PLUGIN_TENCENT_COS_SECRET_KEY=
PLUGIN_TENCENT_COS_SECRET_ID=
PLUGIN_TENCENT_COS_REGION=
# Plugin oss aliyun oss
PLUGIN_ALIYUN_OSS_REGION=
PLUGIN_ALIYUN_OSS_ENDPOINT=
PLUGIN_ALIYUN_OSS_ACCESS_KEY_ID=
PLUGIN_ALIYUN_OSS_ACCESS_KEY_SECRET=
PLUGIN_ALIYUN_OSS_AUTH_VERSION=v4
PLUGIN_ALIYUN_OSS_PATH=
# Plugin oss volcengine tos
PLUGIN_VOLCENGINE_TOS_ENDPOINT=
PLUGIN_VOLCENGINE_TOS_ACCESS_KEY=
PLUGIN_VOLCENGINE_TOS_SECRET_KEY=
PLUGIN_VOLCENGINE_TOS_REGION=

# ------------------------------
# OTLP Collector Configuration
# ------------------------------
ENABLE_OTEL=false
OTLP_TRACE_ENDPOINT=
OTLP_METRIC_ENDPOINT=
OTLP_BASE_ENDPOINT=http://localhost:4318
OTLP_API_KEY=
OTEL_EXPORTER_OTLP_PROTOCOL=
OTEL_EXPORTER_TYPE=otlp
OTEL_SAMPLING_RATE=0.1
OTEL_BATCH_EXPORT_SCHEDULE_DELAY=5000
OTEL_MAX_QUEUE_SIZE=2048
OTEL_MAX_EXPORT_BATCH_SIZE=512
OTEL_METRIC_EXPORT_INTERVAL=60000
OTEL_BATCH_EXPORT_TIMEOUT=10000
OTEL_METRIC_EXPORT_TIMEOUT=30000

# Prevent Clickjacking
ALLOW_EMBED=false

# Dataset queue monitor configuration
QUEUE_MONITOR_THRESHOLD=200
# You can configure multiple ones, separated by commas. eg: [email protected],[email protected]
QUEUE_MONITOR_ALERT_EMAILS=
# Monitor interval in minutes, default is 30 minutes
QUEUE_MONITOR_INTERVAL=30

# Swagger UI configuration
SWAGGER_UI_ENABLED=true
SWAGGER_UI_PATH=/swagger-ui.html

# Celery schedule tasks configuration
ENABLE_CLEAN_EMBEDDING_CACHE_TASK=false
ENABLE_CLEAN_UNUSED_DATASETS_TASK=false
ENABLE_CREATE_TIDB_SERVERLESS_TASK=false
ENABLE_UPDATE_TIDB_SERVERLESS_STATUS_TASK=false
ENABLE_CLEAN_MESSAGES=false
ENABLE_MAIL_CLEAN_DOCUMENT_NOTIFY_TASK=false
ENABLE_DATASETS_QUEUE_MONITOR=false
ENABLE_CHECK_UPGRADABLE_PLUGIN_TASK=true

太长了,其实很多都可以安装好之后,我们慢慢配置的,这边先无视它……

然后处于好奇,我们来看一下它的docker-compose.yml文件

# ==================================================================
# WARNING: This file is auto-generated by generate_docker_compose
# Do not modify this file directly. Instead, update the .env.example
# or docker-compose-template.yaml and regenerate this file.
# ==================================================================

x-shared-env: &shared-api-worker-env
  CONSOLE_API_URL: ${CONSOLE_API_URL:-}
  CONSOLE_WEB_URL: ${CONSOLE_WEB_URL:-}
  SERVICE_API_URL: ${SERVICE_API_URL:-}
  APP_API_URL: ${APP_API_URL:-}
  APP_WEB_URL: ${APP_WEB_URL:-}
  FILES_URL: ${FILES_URL:-}
  INTERNAL_FILES_URL: ${INTERNAL_FILES_URL:-}
  LANG: ${LANG:-en_US.UTF-8}
  LC_ALL: ${LC_ALL:-en_US.UTF-8}
  PYTHONIOENCODING: ${PYTHONIOENCODING:-utf-8}
  LOG_LEVEL: ${LOG_LEVEL:-INFO}
  LOG_FILE: ${LOG_FILE:-/app/logs/server.log}
  LOG_FILE_MAX_SIZE: ${LOG_FILE_MAX_SIZE:-20}
  LOG_FILE_BACKUP_COUNT: ${LOG_FILE_BACKUP_COUNT:-5}
  LOG_DATEFORMAT: ${LOG_DATEFORMAT:-%Y-%m-%d %H:%M:%S}
  LOG_TZ: ${LOG_TZ:-UTC}
  DEBUG: ${DEBUG:-false}
  FLASK_DEBUG: ${FLASK_DEBUG:-false}
  ENABLE_REQUEST_LOGGING: ${ENABLE_REQUEST_LOGGING:-False}
  SECRET_KEY: ${SECRET_KEY:-sk-9f73s3ljTXVcMT3Blb3ljTqtsKiGHXVcMT3BlbkFJLK7U}
  INIT_PASSWORD: ${INIT_PASSWORD:-}
  DEPLOY_ENV: ${DEPLOY_ENV:-PRODUCTION}
  CHECK_UPDATE_URL: ${CHECK_UPDATE_URL:-https://updates.dify.ai}
  OPENAI_API_BASE: ${OPENAI_API_BASE:-https://api.openai.com/v1}
  MIGRATION_ENABLED: ${MIGRATION_ENABLED:-true}
  FILES_ACCESS_TIMEOUT: ${FILES_ACCESS_TIMEOUT:-300}
  ACCESS_TOKEN_EXPIRE_MINUTES: ${ACCESS_TOKEN_EXPIRE_MINUTES:-60}
  REFRESH_TOKEN_EXPIRE_DAYS: ${REFRESH_TOKEN_EXPIRE_DAYS:-30}
  APP_MAX_ACTIVE_REQUESTS: ${APP_MAX_ACTIVE_REQUESTS:-0}
  APP_MAX_EXECUTION_TIME: ${APP_MAX_EXECUTION_TIME:-1200}
  DIFY_BIND_ADDRESS: ${DIFY_BIND_ADDRESS:-0.0.0.0}
  DIFY_PORT: ${DIFY_PORT:-5001}
  SERVER_WORKER_AMOUNT: ${SERVER_WORKER_AMOUNT:-1}
  SERVER_WORKER_CLASS: ${SERVER_WORKER_CLASS:-gevent}
  SERVER_WORKER_CONNECTIONS: ${SERVER_WORKER_CONNECTIONS:-10}
  CELERY_WORKER_CLASS: ${CELERY_WORKER_CLASS:-}
  GUNICORN_TIMEOUT: ${GUNICORN_TIMEOUT:-360}
  CELERY_WORKER_AMOUNT: ${CELERY_WORKER_AMOUNT:-}
  CELERY_AUTO_SCALE: ${CELERY_AUTO_SCALE:-false}
  CELERY_MAX_WORKERS: ${CELERY_MAX_WORKERS:-}
  CELERY_MIN_WORKERS: ${CELERY_MIN_WORKERS:-}
  API_TOOL_DEFAULT_CONNECT_TIMEOUT: ${API_TOOL_DEFAULT_CONNECT_TIMEOUT:-10}
  API_TOOL_DEFAULT_READ_TIMEOUT: ${API_TOOL_DEFAULT_READ_TIMEOUT:-60}
  ENABLE_WEBSITE_JINAREADER: ${ENABLE_WEBSITE_JINAREADER:-true}
  ENABLE_WEBSITE_FIRECRAWL: ${ENABLE_WEBSITE_FIRECRAWL:-true}
  ENABLE_WEBSITE_WATERCRAWL: ${ENABLE_WEBSITE_WATERCRAWL:-true}
  DB_USERNAME: ${DB_USERNAME:-postgres}
  DB_PASSWORD: ${DB_PASSWORD:-difyai123456}
  DB_HOST: ${DB_HOST:-db}
  DB_PORT: ${DB_PORT:-5432}
  DB_DATABASE: ${DB_DATABASE:-dify}
  SQLALCHEMY_POOL_SIZE: ${SQLALCHEMY_POOL_SIZE:-30}
  SQLALCHEMY_MAX_OVERFLOW: ${SQLALCHEMY_MAX_OVERFLOW:-10}
  SQLALCHEMY_POOL_RECYCLE: ${SQLALCHEMY_POOL_RECYCLE:-3600}
  SQLALCHEMY_ECHO: ${SQLALCHEMY_ECHO:-false}
  SQLALCHEMY_POOL_PRE_PING: ${SQLALCHEMY_POOL_PRE_PING:-false}
  SQLALCHEMY_POOL_USE_LIFO: ${SQLALCHEMY_POOL_USE_LIFO:-false}
  POSTGRES_MAX_CONNECTIONS: ${POSTGRES_MAX_CONNECTIONS:-100}
  POSTGRES_SHARED_BUFFERS: ${POSTGRES_SHARED_BUFFERS:-128MB}
  POSTGRES_WORK_MEM: ${POSTGRES_WORK_MEM:-4MB}
  POSTGRES_MAINTENANCE_WORK_MEM: ${POSTGRES_MAINTENANCE_WORK_MEM:-64MB}
  POSTGRES_EFFECTIVE_CACHE_SIZE: ${POSTGRES_EFFECTIVE_CACHE_SIZE:-4096MB}
  REDIS_HOST: ${REDIS_HOST:-redis}
  REDIS_PORT: ${REDIS_PORT:-6379}
  REDIS_USERNAME: ${REDIS_USERNAME:-}
  REDIS_PASSWORD: ${REDIS_PASSWORD:-difyai123456}
  REDIS_USE_SSL: ${REDIS_USE_SSL:-false}
  REDIS_SSL_CERT_REQS: ${REDIS_SSL_CERT_REQS:-CERT_NONE}
  REDIS_SSL_CA_CERTS: ${REDIS_SSL_CA_CERTS:-}
  REDIS_SSL_CERTFILE: ${REDIS_SSL_CERTFILE:-}
  REDIS_SSL_KEYFILE: ${REDIS_SSL_KEYFILE:-}
  REDIS_DB: ${REDIS_DB:-0}
  REDIS_USE_SENTINEL: ${REDIS_USE_SENTINEL:-false}
  REDIS_SENTINELS: ${REDIS_SENTINELS:-}
  REDIS_SENTINEL_SERVICE_NAME: ${REDIS_SENTINEL_SERVICE_NAME:-}
  REDIS_SENTINEL_USERNAME: ${REDIS_SENTINEL_USERNAME:-}
  REDIS_SENTINEL_PASSWORD: ${REDIS_SENTINEL_PASSWORD:-}
  REDIS_SENTINEL_SOCKET_TIMEOUT: ${REDIS_SENTINEL_SOCKET_TIMEOUT:-0.1}
  REDIS_USE_CLUSTERS: ${REDIS_USE_CLUSTERS:-false}
  REDIS_CLUSTERS: ${REDIS_CLUSTERS:-}
  REDIS_CLUSTERS_PASSWORD: ${REDIS_CLUSTERS_PASSWORD:-}
  CELERY_BROKER_URL: ${CELERY_BROKER_URL:-redis://:difyai123456@redis:6379/1}
  CELERY_BACKEND: ${CELERY_BACKEND:-redis}
  BROKER_USE_SSL: ${BROKER_USE_SSL:-false}
  CELERY_USE_SENTINEL: ${CELERY_USE_SENTINEL:-false}
  CELERY_SENTINEL_MASTER_NAME: ${CELERY_SENTINEL_MASTER_NAME:-}
  CELERY_SENTINEL_PASSWORD: ${CELERY_SENTINEL_PASSWORD:-}
  CELERY_SENTINEL_SOCKET_TIMEOUT: ${CELERY_SENTINEL_SOCKET_TIMEOUT:-0.1}
  WEB_API_CORS_ALLOW_ORIGINS: ${WEB_API_CORS_ALLOW_ORIGINS:-*}
  CONSOLE_CORS_ALLOW_ORIGINS: ${CONSOLE_CORS_ALLOW_ORIGINS:-*}
  STORAGE_TYPE: ${STORAGE_TYPE:-opendal}
  OPENDAL_SCHEME: ${OPENDAL_SCHEME:-fs}
  OPENDAL_FS_ROOT: ${OPENDAL_FS_ROOT:-storage}
  CLICKZETTA_VOLUME_TYPE: ${CLICKZETTA_VOLUME_TYPE:-user}
  CLICKZETTA_VOLUME_NAME: ${CLICKZETTA_VOLUME_NAME:-}
  CLICKZETTA_VOLUME_TABLE_PREFIX: ${CLICKZETTA_VOLUME_TABLE_PREFIX:-dataset_}
  CLICKZETTA_VOLUME_DIFY_PREFIX: ${CLICKZETTA_VOLUME_DIFY_PREFIX:-dify_km}
  S3_ENDPOINT: ${S3_ENDPOINT:-}
  S3_REGION: ${S3_REGION:-us-east-1}
  S3_BUCKET_NAME: ${S3_BUCKET_NAME:-difyai}
  S3_ACCESS_KEY: ${S3_ACCESS_KEY:-}
  S3_SECRET_KEY: ${S3_SECRET_KEY:-}
  S3_USE_AWS_MANAGED_IAM: ${S3_USE_AWS_MANAGED_IAM:-false}
  AZURE_BLOB_ACCOUNT_NAME: ${AZURE_BLOB_ACCOUNT_NAME:-difyai}
  AZURE_BLOB_ACCOUNT_KEY: ${AZURE_BLOB_ACCOUNT_KEY:-difyai}
  AZURE_BLOB_CONTAINER_NAME: ${AZURE_BLOB_CONTAINER_NAME:-difyai-container}
  AZURE_BLOB_ACCOUNT_URL: ${AZURE_BLOB_ACCOUNT_URL:-https://<your_account_name>.blob.core.windows.net}
  GOOGLE_STORAGE_BUCKET_NAME: ${GOOGLE_STORAGE_BUCKET_NAME:-your-bucket-name}
  GOOGLE_STORAGE_SERVICE_ACCOUNT_JSON_BASE64: ${GOOGLE_STORAGE_SERVICE_ACCOUNT_JSON_BASE64:-}
  ALIYUN_OSS_BUCKET_NAME: ${ALIYUN_OSS_BUCKET_NAME:-your-bucket-name}
  ALIYUN_OSS_ACCESS_KEY: ${ALIYUN_OSS_ACCESS_KEY:-your-access-key}
  ALIYUN_OSS_SECRET_KEY: ${ALIYUN_OSS_SECRET_KEY:-your-secret-key}
  ALIYUN_OSS_ENDPOINT: ${ALIYUN_OSS_ENDPOINT:-https://oss-ap-southeast-1-internal.aliyuncs.com}
  ALIYUN_OSS_REGION: ${ALIYUN_OSS_REGION:-ap-southeast-1}
  ALIYUN_OSS_AUTH_VERSION: ${ALIYUN_OSS_AUTH_VERSION:-v4}
  ALIYUN_OSS_PATH: ${ALIYUN_OSS_PATH:-your-path}
  TENCENT_COS_BUCKET_NAME: ${TENCENT_COS_BUCKET_NAME:-your-bucket-name}
  TENCENT_COS_SECRET_KEY: ${TENCENT_COS_SECRET_KEY:-your-secret-key}
  TENCENT_COS_SECRET_ID: ${TENCENT_COS_SECRET_ID:-your-secret-id}
  TENCENT_COS_REGION: ${TENCENT_COS_REGION:-your-region}
  TENCENT_COS_SCHEME: ${TENCENT_COS_SCHEME:-your-scheme}
  OCI_ENDPOINT: ${OCI_ENDPOINT:-https://your-object-storage-namespace.compat.objectstorage.us-ashburn-1.oraclecloud.com}
  OCI_BUCKET_NAME: ${OCI_BUCKET_NAME:-your-bucket-name}
  OCI_ACCESS_KEY: ${OCI_ACCESS_KEY:-your-access-key}
  OCI_SECRET_KEY: ${OCI_SECRET_KEY:-your-secret-key}
  OCI_REGION: ${OCI_REGION:-us-ashburn-1}
  HUAWEI_OBS_BUCKET_NAME: ${HUAWEI_OBS_BUCKET_NAME:-your-bucket-name}
  HUAWEI_OBS_SECRET_KEY: ${HUAWEI_OBS_SECRET_KEY:-your-secret-key}
  HUAWEI_OBS_ACCESS_KEY: ${HUAWEI_OBS_ACCESS_KEY:-your-access-key}
  HUAWEI_OBS_SERVER: ${HUAWEI_OBS_SERVER:-your-server-url}
  VOLCENGINE_TOS_BUCKET_NAME: ${VOLCENGINE_TOS_BUCKET_NAME:-your-bucket-name}
  VOLCENGINE_TOS_SECRET_KEY: ${VOLCENGINE_TOS_SECRET_KEY:-your-secret-key}
  VOLCENGINE_TOS_ACCESS_KEY: ${VOLCENGINE_TOS_ACCESS_KEY:-your-access-key}
  VOLCENGINE_TOS_ENDPOINT: ${VOLCENGINE_TOS_ENDPOINT:-your-server-url}
  VOLCENGINE_TOS_REGION: ${VOLCENGINE_TOS_REGION:-your-region}
  BAIDU_OBS_BUCKET_NAME: ${BAIDU_OBS_BUCKET_NAME:-your-bucket-name}
  BAIDU_OBS_SECRET_KEY: ${BAIDU_OBS_SECRET_KEY:-your-secret-key}
  BAIDU_OBS_ACCESS_KEY: ${BAIDU_OBS_ACCESS_KEY:-your-access-key}
  BAIDU_OBS_ENDPOINT: ${BAIDU_OBS_ENDPOINT:-your-server-url}
  SUPABASE_BUCKET_NAME: ${SUPABASE_BUCKET_NAME:-your-bucket-name}
  SUPABASE_API_KEY: ${SUPABASE_API_KEY:-your-access-key}
  SUPABASE_URL: ${SUPABASE_URL:-your-server-url}
  VECTOR_STORE: ${VECTOR_STORE:-weaviate}
  VECTOR_INDEX_NAME_PREFIX: ${VECTOR_INDEX_NAME_PREFIX:-Vector_index}
  WEAVIATE_ENDPOINT: ${WEAVIATE_ENDPOINT:-http://weaviate:8080}
  WEAVIATE_API_KEY: ${WEAVIATE_API_KEY:-WVF5YThaHlkYwhGUSmCRgsX3tD5ngdN8pkih}
  QDRANT_URL: ${QDRANT_URL:-http://qdrant:6333}
  QDRANT_API_KEY: ${QDRANT_API_KEY:-difyai123456}
  QDRANT_CLIENT_TIMEOUT: ${QDRANT_CLIENT_TIMEOUT:-20}
  QDRANT_GRPC_ENABLED: ${QDRANT_GRPC_ENABLED:-false}
  QDRANT_GRPC_PORT: ${QDRANT_GRPC_PORT:-6334}
  QDRANT_REPLICATION_FACTOR: ${QDRANT_REPLICATION_FACTOR:-1}
  MILVUS_URI: ${MILVUS_URI:-http://host.docker.internal:19530}
  MILVUS_DATABASE: ${MILVUS_DATABASE:-}
  MILVUS_TOKEN: ${MILVUS_TOKEN:-}
  MILVUS_USER: ${MILVUS_USER:-}
  MILVUS_PASSWORD: ${MILVUS_PASSWORD:-}
  MILVUS_ENABLE_HYBRID_SEARCH: ${MILVUS_ENABLE_HYBRID_SEARCH:-False}
  MILVUS_ANALYZER_PARAMS: ${MILVUS_ANALYZER_PARAMS:-}
  MYSCALE_HOST: ${MYSCALE_HOST:-myscale}
  MYSCALE_PORT: ${MYSCALE_PORT:-8123}
  MYSCALE_USER: ${MYSCALE_USER:-default}
  MYSCALE_PASSWORD: ${MYSCALE_PASSWORD:-}
  MYSCALE_DATABASE: ${MYSCALE_DATABASE:-dify}
  MYSCALE_FTS_PARAMS: ${MYSCALE_FTS_PARAMS:-}
  COUCHBASE_CONNECTION_STRING: ${COUCHBASE_CONNECTION_STRING:-couchbase://couchbase-server}
  COUCHBASE_USER: ${COUCHBASE_USER:-Administrator}
  COUCHBASE_PASSWORD: ${COUCHBASE_PASSWORD:-password}
  COUCHBASE_BUCKET_NAME: ${COUCHBASE_BUCKET_NAME:-Embeddings}
  COUCHBASE_SCOPE_NAME: ${COUCHBASE_SCOPE_NAME:-_default}
  PGVECTOR_HOST: ${PGVECTOR_HOST:-pgvector}
  PGVECTOR_PORT: ${PGVECTOR_PORT:-5432}
  PGVECTOR_USER: ${PGVECTOR_USER:-postgres}
  PGVECTOR_PASSWORD: ${PGVECTOR_PASSWORD:-difyai123456}
  PGVECTOR_DATABASE: ${PGVECTOR_DATABASE:-dify}
  PGVECTOR_MIN_CONNECTION: ${PGVECTOR_MIN_CONNECTION:-1}
  PGVECTOR_MAX_CONNECTION: ${PGVECTOR_MAX_CONNECTION:-5}
  PGVECTOR_PG_BIGM: ${PGVECTOR_PG_BIGM:-false}
  PGVECTOR_PG_BIGM_VERSION: ${PGVECTOR_PG_BIGM_VERSION:-1.2-20240606}
  VASTBASE_HOST: ${VASTBASE_HOST:-vastbase}
  VASTBASE_PORT: ${VASTBASE_PORT:-5432}
  VASTBASE_USER: ${VASTBASE_USER:-dify}
  VASTBASE_PASSWORD: ${VASTBASE_PASSWORD:-Difyai123456}
  VASTBASE_DATABASE: ${VASTBASE_DATABASE:-dify}
  VASTBASE_MIN_CONNECTION: ${VASTBASE_MIN_CONNECTION:-1}
  VASTBASE_MAX_CONNECTION: ${VASTBASE_MAX_CONNECTION:-5}
  PGVECTO_RS_HOST: ${PGVECTO_RS_HOST:-pgvecto-rs}
  PGVECTO_RS_PORT: ${PGVECTO_RS_PORT:-5432}
  PGVECTO_RS_USER: ${PGVECTO_RS_USER:-postgres}
  PGVECTO_RS_PASSWORD: ${PGVECTO_RS_PASSWORD:-difyai123456}
  PGVECTO_RS_DATABASE: ${PGVECTO_RS_DATABASE:-dify}
  ANALYTICDB_KEY_ID: ${ANALYTICDB_KEY_ID:-your-ak}
  ANALYTICDB_KEY_SECRET: ${ANALYTICDB_KEY_SECRET:-your-sk}
  ANALYTICDB_REGION_ID: ${ANALYTICDB_REGION_ID:-cn-hangzhou}
  ANALYTICDB_INSTANCE_ID: ${ANALYTICDB_INSTANCE_ID:-gp-ab123456}
  ANALYTICDB_ACCOUNT: ${ANALYTICDB_ACCOUNT:-testaccount}
  ANALYTICDB_PASSWORD: ${ANALYTICDB_PASSWORD:-testpassword}
  ANALYTICDB_NAMESPACE: ${ANALYTICDB_NAMESPACE:-dify}
  ANALYTICDB_NAMESPACE_PASSWORD: ${ANALYTICDB_NAMESPACE_PASSWORD:-difypassword}
  ANALYTICDB_HOST: ${ANALYTICDB_HOST:-gp-test.aliyuncs.com}
  ANALYTICDB_PORT: ${ANALYTICDB_PORT:-5432}
  ANALYTICDB_MIN_CONNECTION: ${ANALYTICDB_MIN_CONNECTION:-1}
  ANALYTICDB_MAX_CONNECTION: ${ANALYTICDB_MAX_CONNECTION:-5}
  TIDB_VECTOR_HOST: ${TIDB_VECTOR_HOST:-tidb}
  TIDB_VECTOR_PORT: ${TIDB_VECTOR_PORT:-4000}
  TIDB_VECTOR_USER: ${TIDB_VECTOR_USER:-}
  TIDB_VECTOR_PASSWORD: ${TIDB_VECTOR_PASSWORD:-}
  TIDB_VECTOR_DATABASE: ${TIDB_VECTOR_DATABASE:-dify}
  MATRIXONE_HOST: ${MATRIXONE_HOST:-matrixone}
  MATRIXONE_PORT: ${MATRIXONE_PORT:-6001}
  MATRIXONE_USER: ${MATRIXONE_USER:-dump}
  MATRIXONE_PASSWORD: ${MATRIXONE_PASSWORD:-111}
  MATRIXONE_DATABASE: ${MATRIXONE_DATABASE:-dify}
  TIDB_ON_QDRANT_URL: ${TIDB_ON_QDRANT_URL:-http://127.0.0.1}
  TIDB_ON_QDRANT_API_KEY: ${TIDB_ON_QDRANT_API_KEY:-dify}
  TIDB_ON_QDRANT_CLIENT_TIMEOUT: ${TIDB_ON_QDRANT_CLIENT_TIMEOUT:-20}
  TIDB_ON_QDRANT_GRPC_ENABLED: ${TIDB_ON_QDRANT_GRPC_ENABLED:-false}
  TIDB_ON_QDRANT_GRPC_PORT: ${TIDB_ON_QDRANT_GRPC_PORT:-6334}
  TIDB_PUBLIC_KEY: ${TIDB_PUBLIC_KEY:-dify}
  TIDB_PRIVATE_KEY: ${TIDB_PRIVATE_KEY:-dify}
  TIDB_API_URL: ${TIDB_API_URL:-http://127.0.0.1}
  TIDB_IAM_API_URL: ${TIDB_IAM_API_URL:-http://127.0.0.1}
  TIDB_REGION: ${TIDB_REGION:-regions/aws-us-east-1}
  TIDB_PROJECT_ID: ${TIDB_PROJECT_ID:-dify}
  TIDB_SPEND_LIMIT: ${TIDB_SPEND_LIMIT:-100}
  CHROMA_HOST: ${CHROMA_HOST:-127.0.0.1}
  CHROMA_PORT: ${CHROMA_PORT:-8000}
  CHROMA_TENANT: ${CHROMA_TENANT:-default_tenant}
  CHROMA_DATABASE: ${CHROMA_DATABASE:-default_database}
  CHROMA_AUTH_PROVIDER: ${CHROMA_AUTH_PROVIDER:-chromadb.auth.token_authn.TokenAuthClientProvider}
  CHROMA_AUTH_CREDENTIALS: ${CHROMA_AUTH_CREDENTIALS:-}
  ORACLE_USER: ${ORACLE_USER:-dify}
  ORACLE_PASSWORD: ${ORACLE_PASSWORD:-dify}
  ORACLE_DSN: ${ORACLE_DSN:-oracle:1521/FREEPDB1}
  ORACLE_CONFIG_DIR: ${ORACLE_CONFIG_DIR:-/app/api/storage/wallet}
  ORACLE_WALLET_LOCATION: ${ORACLE_WALLET_LOCATION:-/app/api/storage/wallet}
  ORACLE_WALLET_PASSWORD: ${ORACLE_WALLET_PASSWORD:-dify}
  ORACLE_IS_AUTONOMOUS: ${ORACLE_IS_AUTONOMOUS:-false}
  RELYT_HOST: ${RELYT_HOST:-db}
  RELYT_PORT: ${RELYT_PORT:-5432}
  RELYT_USER: ${RELYT_USER:-postgres}
  RELYT_PASSWORD: ${RELYT_PASSWORD:-difyai123456}
  RELYT_DATABASE: ${RELYT_DATABASE:-postgres}
  OPENSEARCH_HOST: ${OPENSEARCH_HOST:-opensearch}
  OPENSEARCH_PORT: ${OPENSEARCH_PORT:-9200}
  OPENSEARCH_SECURE: ${OPENSEARCH_SECURE:-true}
  OPENSEARCH_VERIFY_CERTS: ${OPENSEARCH_VERIFY_CERTS:-true}
  OPENSEARCH_AUTH_METHOD: ${OPENSEARCH_AUTH_METHOD:-basic}
  OPENSEARCH_USER: ${OPENSEARCH_USER:-admin}
  OPENSEARCH_PASSWORD: ${OPENSEARCH_PASSWORD:-admin}
  OPENSEARCH_AWS_REGION: ${OPENSEARCH_AWS_REGION:-ap-southeast-1}
  OPENSEARCH_AWS_SERVICE: ${OPENSEARCH_AWS_SERVICE:-aoss}
  TENCENT_VECTOR_DB_URL: ${TENCENT_VECTOR_DB_URL:-http://127.0.0.1}
  TENCENT_VECTOR_DB_API_KEY: ${TENCENT_VECTOR_DB_API_KEY:-dify}
  TENCENT_VECTOR_DB_TIMEOUT: ${TENCENT_VECTOR_DB_TIMEOUT:-30}
  TENCENT_VECTOR_DB_USERNAME: ${TENCENT_VECTOR_DB_USERNAME:-dify}
  TENCENT_VECTOR_DB_DATABASE: ${TENCENT_VECTOR_DB_DATABASE:-dify}
  TENCENT_VECTOR_DB_SHARD: ${TENCENT_VECTOR_DB_SHARD:-1}
  TENCENT_VECTOR_DB_REPLICAS: ${TENCENT_VECTOR_DB_REPLICAS:-2}
  TENCENT_VECTOR_DB_ENABLE_HYBRID_SEARCH: ${TENCENT_VECTOR_DB_ENABLE_HYBRID_SEARCH:-false}
  ELASTICSEARCH_HOST: ${ELASTICSEARCH_HOST:-0.0.0.0}
  ELASTICSEARCH_PORT: ${ELASTICSEARCH_PORT:-9200}
  ELASTICSEARCH_USERNAME: ${ELASTICSEARCH_USERNAME:-elastic}
  ELASTICSEARCH_PASSWORD: ${ELASTICSEARCH_PASSWORD:-elastic}
  KIBANA_PORT: ${KIBANA_PORT:-5601}
  ELASTICSEARCH_USE_CLOUD: ${ELASTICSEARCH_USE_CLOUD:-false}
  ELASTICSEARCH_CLOUD_URL: ${ELASTICSEARCH_CLOUD_URL:-YOUR-ELASTICSEARCH_CLOUD_URL}
  ELASTICSEARCH_API_KEY: ${ELASTICSEARCH_API_KEY:-YOUR-ELASTICSEARCH_API_KEY}
  ELASTICSEARCH_VERIFY_CERTS: ${ELASTICSEARCH_VERIFY_CERTS:-False}
  ELASTICSEARCH_CA_CERTS: ${ELASTICSEARCH_CA_CERTS:-}
  ELASTICSEARCH_REQUEST_TIMEOUT: ${ELASTICSEARCH_REQUEST_TIMEOUT:-100000}
  ELASTICSEARCH_RETRY_ON_TIMEOUT: ${ELASTICSEARCH_RETRY_ON_TIMEOUT:-True}
  ELASTICSEARCH_MAX_RETRIES: ${ELASTICSEARCH_MAX_RETRIES:-10}
  BAIDU_VECTOR_DB_ENDPOINT: ${BAIDU_VECTOR_DB_ENDPOINT:-http://127.0.0.1:5287}
  BAIDU_VECTOR_DB_CONNECTION_TIMEOUT_MS: ${BAIDU_VECTOR_DB_CONNECTION_TIMEOUT_MS:-30000}
  BAIDU_VECTOR_DB_ACCOUNT: ${BAIDU_VECTOR_DB_ACCOUNT:-root}
  BAIDU_VECTOR_DB_API_KEY: ${BAIDU_VECTOR_DB_API_KEY:-dify}
  BAIDU_VECTOR_DB_DATABASE: ${BAIDU_VECTOR_DB_DATABASE:-dify}
  BAIDU_VECTOR_DB_SHARD: ${BAIDU_VECTOR_DB_SHARD:-1}
  BAIDU_VECTOR_DB_REPLICAS: ${BAIDU_VECTOR_DB_REPLICAS:-3}
  VIKINGDB_ACCESS_KEY: ${VIKINGDB_ACCESS_KEY:-your-ak}
  VIKINGDB_SECRET_KEY: ${VIKINGDB_SECRET_KEY:-your-sk}
  VIKINGDB_REGION: ${VIKINGDB_REGION:-cn-shanghai}
  VIKINGDB_HOST: ${VIKINGDB_HOST:-api-vikingdb.xxx.volces.com}
  VIKINGDB_SCHEMA: ${VIKINGDB_SCHEMA:-http}
  VIKINGDB_CONNECTION_TIMEOUT: ${VIKINGDB_CONNECTION_TIMEOUT:-30}
  VIKINGDB_SOCKET_TIMEOUT: ${VIKINGDB_SOCKET_TIMEOUT:-30}
  LINDORM_URL: ${LINDORM_URL:-http://lindorm:30070}
  LINDORM_USERNAME: ${LINDORM_USERNAME:-lindorm}
  LINDORM_PASSWORD: ${LINDORM_PASSWORD:-lindorm}
  LINDORM_QUERY_TIMEOUT: ${LINDORM_QUERY_TIMEOUT:-1}
  OCEANBASE_VECTOR_HOST: ${OCEANBASE_VECTOR_HOST:-oceanbase}
  OCEANBASE_VECTOR_PORT: ${OCEANBASE_VECTOR_PORT:-2881}
  OCEANBASE_VECTOR_USER: ${OCEANBASE_VECTOR_USER:-root@test}
  OCEANBASE_VECTOR_PASSWORD: ${OCEANBASE_VECTOR_PASSWORD:-difyai123456}
  OCEANBASE_VECTOR_DATABASE: ${OCEANBASE_VECTOR_DATABASE:-test}
  OCEANBASE_CLUSTER_NAME: ${OCEANBASE_CLUSTER_NAME:-difyai}
  OCEANBASE_MEMORY_LIMIT: ${OCEANBASE_MEMORY_LIMIT:-6G}
  OCEANBASE_ENABLE_HYBRID_SEARCH: ${OCEANBASE_ENABLE_HYBRID_SEARCH:-false}
  OPENGAUSS_HOST: ${OPENGAUSS_HOST:-opengauss}
  OPENGAUSS_PORT: ${OPENGAUSS_PORT:-6600}
  OPENGAUSS_USER: ${OPENGAUSS_USER:-postgres}
  OPENGAUSS_PASSWORD: ${OPENGAUSS_PASSWORD:-Dify@123}
  OPENGAUSS_DATABASE: ${OPENGAUSS_DATABASE:-dify}
  OPENGAUSS_MIN_CONNECTION: ${OPENGAUSS_MIN_CONNECTION:-1}
  OPENGAUSS_MAX_CONNECTION: ${OPENGAUSS_MAX_CONNECTION:-5}
  OPENGAUSS_ENABLE_PQ: ${OPENGAUSS_ENABLE_PQ:-false}
  HUAWEI_CLOUD_HOSTS: ${HUAWEI_CLOUD_HOSTS:-https://127.0.0.1:9200}
  HUAWEI_CLOUD_USER: ${HUAWEI_CLOUD_USER:-admin}
  HUAWEI_CLOUD_PASSWORD: ${HUAWEI_CLOUD_PASSWORD:-admin}
  UPSTASH_VECTOR_URL: ${UPSTASH_VECTOR_URL:-https://xxx-vector.upstash.io}
  UPSTASH_VECTOR_TOKEN: ${UPSTASH_VECTOR_TOKEN:-dify}
  TABLESTORE_ENDPOINT: ${TABLESTORE_ENDPOINT:-https://instance-name.cn-hangzhou.ots.aliyuncs.com}
  TABLESTORE_INSTANCE_NAME: ${TABLESTORE_INSTANCE_NAME:-instance-name}
  TABLESTORE_ACCESS_KEY_ID: ${TABLESTORE_ACCESS_KEY_ID:-xxx}
  TABLESTORE_ACCESS_KEY_SECRET: ${TABLESTORE_ACCESS_KEY_SECRET:-xxx}
  TABLESTORE_NORMALIZE_FULLTEXT_BM25_SCORE: ${TABLESTORE_NORMALIZE_FULLTEXT_BM25_SCORE:-false}
  CLICKZETTA_USERNAME: ${CLICKZETTA_USERNAME:-}
  CLICKZETTA_PASSWORD: ${CLICKZETTA_PASSWORD:-}
  CLICKZETTA_INSTANCE: ${CLICKZETTA_INSTANCE:-}
  CLICKZETTA_SERVICE: ${CLICKZETTA_SERVICE:-api.clickzetta.com}
  CLICKZETTA_WORKSPACE: ${CLICKZETTA_WORKSPACE:-quick_start}
  CLICKZETTA_VCLUSTER: ${CLICKZETTA_VCLUSTER:-default_ap}
  CLICKZETTA_SCHEMA: ${CLICKZETTA_SCHEMA:-dify}
  CLICKZETTA_BATCH_SIZE: ${CLICKZETTA_BATCH_SIZE:-100}
  CLICKZETTA_ENABLE_INVERTED_INDEX: ${CLICKZETTA_ENABLE_INVERTED_INDEX:-true}
  CLICKZETTA_ANALYZER_TYPE: ${CLICKZETTA_ANALYZER_TYPE:-chinese}
  CLICKZETTA_ANALYZER_MODE: ${CLICKZETTA_ANALYZER_MODE:-smart}
  CLICKZETTA_VECTOR_DISTANCE_FUNCTION: ${CLICKZETTA_VECTOR_DISTANCE_FUNCTION:-cosine_distance}
  UPLOAD_FILE_SIZE_LIMIT: ${UPLOAD_FILE_SIZE_LIMIT:-15}
  UPLOAD_FILE_BATCH_LIMIT: ${UPLOAD_FILE_BATCH_LIMIT:-5}
  ETL_TYPE: ${ETL_TYPE:-dify}
  UNSTRUCTURED_API_URL: ${UNSTRUCTURED_API_URL:-}
  UNSTRUCTURED_API_KEY: ${UNSTRUCTURED_API_KEY:-}
  SCARF_NO_ANALYTICS: ${SCARF_NO_ANALYTICS:-true}
  PROMPT_GENERATION_MAX_TOKENS: ${PROMPT_GENERATION_MAX_TOKENS:-512}
  CODE_GENERATION_MAX_TOKENS: ${CODE_GENERATION_MAX_TOKENS:-1024}
  PLUGIN_BASED_TOKEN_COUNTING_ENABLED: ${PLUGIN_BASED_TOKEN_COUNTING_ENABLED:-false}
  MULTIMODAL_SEND_FORMAT: ${MULTIMODAL_SEND_FORMAT:-base64}
  UPLOAD_IMAGE_FILE_SIZE_LIMIT: ${UPLOAD_IMAGE_FILE_SIZE_LIMIT:-10}
  UPLOAD_VIDEO_FILE_SIZE_LIMIT: ${UPLOAD_VIDEO_FILE_SIZE_LIMIT:-100}
  UPLOAD_AUDIO_FILE_SIZE_LIMIT: ${UPLOAD_AUDIO_FILE_SIZE_LIMIT:-50}
  SENTRY_DSN: ${SENTRY_DSN:-}
  API_SENTRY_DSN: ${API_SENTRY_DSN:-}
  API_SENTRY_TRACES_SAMPLE_RATE: ${API_SENTRY_TRACES_SAMPLE_RATE:-1.0}
  API_SENTRY_PROFILES_SAMPLE_RATE: ${API_SENTRY_PROFILES_SAMPLE_RATE:-1.0}
  WEB_SENTRY_DSN: ${WEB_SENTRY_DSN:-}
  NOTION_INTEGRATION_TYPE: ${NOTION_INTEGRATION_TYPE:-public}
  NOTION_CLIENT_SECRET: ${NOTION_CLIENT_SECRET:-}
  NOTION_CLIENT_ID: ${NOTION_CLIENT_ID:-}
  NOTION_INTERNAL_SECRET: ${NOTION_INTERNAL_SECRET:-}
  MAIL_TYPE: ${MAIL_TYPE:-resend}
  MAIL_DEFAULT_SEND_FROM: ${MAIL_DEFAULT_SEND_FROM:-}
  RESEND_API_URL: ${RESEND_API_URL:-https://api.resend.com}
  RESEND_API_KEY: ${RESEND_API_KEY:-your-resend-api-key}
  SMTP_SERVER: ${SMTP_SERVER:-}
  SMTP_PORT: ${SMTP_PORT:-465}
  SMTP_USERNAME: ${SMTP_USERNAME:-}
  SMTP_PASSWORD: ${SMTP_PASSWORD:-}
  SMTP_USE_TLS: ${SMTP_USE_TLS:-true}
  SMTP_OPPORTUNISTIC_TLS: ${SMTP_OPPORTUNISTIC_TLS:-false}
  SENDGRID_API_KEY: ${SENDGRID_API_KEY:-}
  INDEXING_MAX_SEGMENTATION_TOKENS_LENGTH: ${INDEXING_MAX_SEGMENTATION_TOKENS_LENGTH:-4000}
  INVITE_EXPIRY_HOURS: ${INVITE_EXPIRY_HOURS:-72}
  RESET_PASSWORD_TOKEN_EXPIRY_MINUTES: ${RESET_PASSWORD_TOKEN_EXPIRY_MINUTES:-5}
  CHANGE_EMAIL_TOKEN_EXPIRY_MINUTES: ${CHANGE_EMAIL_TOKEN_EXPIRY_MINUTES:-5}
  OWNER_TRANSFER_TOKEN_EXPIRY_MINUTES: ${OWNER_TRANSFER_TOKEN_EXPIRY_MINUTES:-5}
  CODE_EXECUTION_ENDPOINT: ${CODE_EXECUTION_ENDPOINT:-http://sandbox:8194}
  CODE_EXECUTION_API_KEY: ${CODE_EXECUTION_API_KEY:-dify-sandbox}
  CODE_MAX_NUMBER: ${CODE_MAX_NUMBER:-9223372036854775807}
  CODE_MIN_NUMBER: ${CODE_MIN_NUMBER:--9223372036854775808}
  CODE_MAX_DEPTH: ${CODE_MAX_DEPTH:-5}
  CODE_MAX_PRECISION: ${CODE_MAX_PRECISION:-20}
  CODE_MAX_STRING_LENGTH: ${CODE_MAX_STRING_LENGTH:-80000}
  CODE_MAX_STRING_ARRAY_LENGTH: ${CODE_MAX_STRING_ARRAY_LENGTH:-30}
  CODE_MAX_OBJECT_ARRAY_LENGTH: ${CODE_MAX_OBJECT_ARRAY_LENGTH:-30}
  CODE_MAX_NUMBER_ARRAY_LENGTH: ${CODE_MAX_NUMBER_ARRAY_LENGTH:-1000}
  CODE_EXECUTION_CONNECT_TIMEOUT: ${CODE_EXECUTION_CONNECT_TIMEOUT:-10}
  CODE_EXECUTION_READ_TIMEOUT: ${CODE_EXECUTION_READ_TIMEOUT:-60}
  CODE_EXECUTION_WRITE_TIMEOUT: ${CODE_EXECUTION_WRITE_TIMEOUT:-10}
  TEMPLATE_TRANSFORM_MAX_LENGTH: ${TEMPLATE_TRANSFORM_MAX_LENGTH:-80000}
  WORKFLOW_MAX_EXECUTION_STEPS: ${WORKFLOW_MAX_EXECUTION_STEPS:-500}
  WORKFLOW_MAX_EXECUTION_TIME: ${WORKFLOW_MAX_EXECUTION_TIME:-1200}
  WORKFLOW_CALL_MAX_DEPTH: ${WORKFLOW_CALL_MAX_DEPTH:-5}
  MAX_VARIABLE_SIZE: ${MAX_VARIABLE_SIZE:-204800}
  WORKFLOW_PARALLEL_DEPTH_LIMIT: ${WORKFLOW_PARALLEL_DEPTH_LIMIT:-3}
  WORKFLOW_FILE_UPLOAD_LIMIT: ${WORKFLOW_FILE_UPLOAD_LIMIT:-10}
  WORKFLOW_NODE_EXECUTION_STORAGE: ${WORKFLOW_NODE_EXECUTION_STORAGE:-rdbms}
  CORE_WORKFLOW_EXECUTION_REPOSITORY: ${CORE_WORKFLOW_EXECUTION_REPOSITORY:-core.repositories.sqlalchemy_workflow_execution_repository.SQLAlchemyWorkflowExecutionRepository}
  CORE_WORKFLOW_NODE_EXECUTION_REPOSITORY: ${CORE_WORKFLOW_NODE_EXECUTION_REPOSITORY:-core.repositories.sqlalchemy_workflow_node_execution_repository.SQLAlchemyWorkflowNodeExecutionRepository}
  API_WORKFLOW_RUN_REPOSITORY: ${API_WORKFLOW_RUN_REPOSITORY:-repositories.sqlalchemy_api_workflow_run_repository.DifyAPISQLAlchemyWorkflowRunRepository}
  API_WORKFLOW_NODE_EXECUTION_REPOSITORY: ${API_WORKFLOW_NODE_EXECUTION_REPOSITORY:-repositories.sqlalchemy_api_workflow_node_execution_repository.DifyAPISQLAlchemyWorkflowNodeExecutionRepository}
  WORKFLOW_LOG_CLEANUP_ENABLED: ${WORKFLOW_LOG_CLEANUP_ENABLED:-false}
  WORKFLOW_LOG_RETENTION_DAYS: ${WORKFLOW_LOG_RETENTION_DAYS:-30}
  WORKFLOW_LOG_CLEANUP_BATCH_SIZE: ${WORKFLOW_LOG_CLEANUP_BATCH_SIZE:-100}
  HTTP_REQUEST_NODE_MAX_BINARY_SIZE: ${HTTP_REQUEST_NODE_MAX_BINARY_SIZE:-10485760}
  HTTP_REQUEST_NODE_MAX_TEXT_SIZE: ${HTTP_REQUEST_NODE_MAX_TEXT_SIZE:-1048576}
  HTTP_REQUEST_NODE_SSL_VERIFY: ${HTTP_REQUEST_NODE_SSL_VERIFY:-True}
  RESPECT_XFORWARD_HEADERS_ENABLED: ${RESPECT_XFORWARD_HEADERS_ENABLED:-false}
  SSRF_PROXY_HTTP_URL: ${SSRF_PROXY_HTTP_URL:-http://ssrf_proxy:3128}
  SSRF_PROXY_HTTPS_URL: ${SSRF_PROXY_HTTPS_URL:-http://ssrf_proxy:3128}
  LOOP_NODE_MAX_COUNT: ${LOOP_NODE_MAX_COUNT:-100}
  MAX_TOOLS_NUM: ${MAX_TOOLS_NUM:-10}
  MAX_PARALLEL_LIMIT: ${MAX_PARALLEL_LIMIT:-10}
  MAX_ITERATIONS_NUM: ${MAX_ITERATIONS_NUM:-99}
  TEXT_GENERATION_TIMEOUT_MS: ${TEXT_GENERATION_TIMEOUT_MS:-60000}
  ALLOW_UNSAFE_DATA_SCHEME: ${ALLOW_UNSAFE_DATA_SCHEME:-false}
  MAX_TREE_DEPTH: ${MAX_TREE_DEPTH:-50}
  POSTGRES_USER: ${POSTGRES_USER:-${DB_USERNAME}}
  POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-${DB_PASSWORD}}
  POSTGRES_DB: ${POSTGRES_DB:-${DB_DATABASE}}
  PGDATA: ${PGDATA:-/var/lib/postgresql/data/pgdata}
  SANDBOX_API_KEY: ${SANDBOX_API_KEY:-dify-sandbox}
  SANDBOX_GIN_MODE: ${SANDBOX_GIN_MODE:-release}
  SANDBOX_WORKER_TIMEOUT: ${SANDBOX_WORKER_TIMEOUT:-15}
  SANDBOX_ENABLE_NETWORK: ${SANDBOX_ENABLE_NETWORK:-true}
  SANDBOX_HTTP_PROXY: ${SANDBOX_HTTP_PROXY:-http://ssrf_proxy:3128}
  SANDBOX_HTTPS_PROXY: ${SANDBOX_HTTPS_PROXY:-http://ssrf_proxy:3128}
  SANDBOX_PORT: ${SANDBOX_PORT:-8194}
  WEAVIATE_PERSISTENCE_DATA_PATH: ${WEAVIATE_PERSISTENCE_DATA_PATH:-/var/lib/weaviate}
  WEAVIATE_QUERY_DEFAULTS_LIMIT: ${WEAVIATE_QUERY_DEFAULTS_LIMIT:-25}
  WEAVIATE_AUTHENTICATION_ANONYMOUS_ACCESS_ENABLED: ${WEAVIATE_AUTHENTICATION_ANONYMOUS_ACCESS_ENABLED:-true}
  WEAVIATE_DEFAULT_VECTORIZER_MODULE: ${WEAVIATE_DEFAULT_VECTORIZER_MODULE:-none}
  WEAVIATE_CLUSTER_HOSTNAME: ${WEAVIATE_CLUSTER_HOSTNAME:-node1}
  WEAVIATE_AUTHENTICATION_APIKEY_ENABLED: ${WEAVIATE_AUTHENTICATION_APIKEY_ENABLED:-true}
  WEAVIATE_AUTHENTICATION_APIKEY_ALLOWED_KEYS: ${WEAVIATE_AUTHENTICATION_APIKEY_ALLOWED_KEYS:-WVF5YThaHlkYwhGUSmCRgsX3tD5ngdN8pkih}
  WEAVIATE_AUTHENTICATION_APIKEY_USERS: ${WEAVIATE_AUTHENTICATION_APIKEY_USERS:[email protected]}
  WEAVIATE_AUTHORIZATION_ADMINLIST_ENABLED: ${WEAVIATE_AUTHORIZATION_ADMINLIST_ENABLED:-true}
  WEAVIATE_AUTHORIZATION_ADMINLIST_USERS: ${WEAVIATE_AUTHORIZATION_ADMINLIST_USERS:[email protected]}
  CHROMA_SERVER_AUTHN_CREDENTIALS: ${CHROMA_SERVER_AUTHN_CREDENTIALS:-difyai123456}
  CHROMA_SERVER_AUTHN_PROVIDER: ${CHROMA_SERVER_AUTHN_PROVIDER:-chromadb.auth.token_authn.TokenAuthenticationServerProvider}
  CHROMA_IS_PERSISTENT: ${CHROMA_IS_PERSISTENT:-TRUE}
  ORACLE_PWD: ${ORACLE_PWD:-Dify123456}
  ORACLE_CHARACTERSET: ${ORACLE_CHARACTERSET:-AL32UTF8}
  ETCD_AUTO_COMPACTION_MODE: ${ETCD_AUTO_COMPACTION_MODE:-revision}
  ETCD_AUTO_COMPACTION_RETENTION: ${ETCD_AUTO_COMPACTION_RETENTION:-1000}
  ETCD_QUOTA_BACKEND_BYTES: ${ETCD_QUOTA_BACKEND_BYTES:-4294967296}
  ETCD_SNAPSHOT_COUNT: ${ETCD_SNAPSHOT_COUNT:-50000}
  MINIO_ACCESS_KEY: ${MINIO_ACCESS_KEY:-minioadmin}
  MINIO_SECRET_KEY: ${MINIO_SECRET_KEY:-minioadmin}
  ETCD_ENDPOINTS: ${ETCD_ENDPOINTS:-etcd:2379}
  MINIO_ADDRESS: ${MINIO_ADDRESS:-minio:9000}
  MILVUS_AUTHORIZATION_ENABLED: ${MILVUS_AUTHORIZATION_ENABLED:-true}
  PGVECTOR_PGUSER: ${PGVECTOR_PGUSER:-postgres}
  PGVECTOR_POSTGRES_PASSWORD: ${PGVECTOR_POSTGRES_PASSWORD:-difyai123456}
  PGVECTOR_POSTGRES_DB: ${PGVECTOR_POSTGRES_DB:-dify}
  PGVECTOR_PGDATA: ${PGVECTOR_PGDATA:-/var/lib/postgresql/data/pgdata}
  OPENSEARCH_DISCOVERY_TYPE: ${OPENSEARCH_DISCOVERY_TYPE:-single-node}
  OPENSEARCH_BOOTSTRAP_MEMORY_LOCK: ${OPENSEARCH_BOOTSTRAP_MEMORY_LOCK:-true}
  OPENSEARCH_JAVA_OPTS_MIN: ${OPENSEARCH_JAVA_OPTS_MIN:-512m}
  OPENSEARCH_JAVA_OPTS_MAX: ${OPENSEARCH_JAVA_OPTS_MAX:-1024m}
  OPENSEARCH_INITIAL_ADMIN_PASSWORD: ${OPENSEARCH_INITIAL_ADMIN_PASSWORD:-Qazwsxedc!@#123}
  OPENSEARCH_MEMLOCK_SOFT: ${OPENSEARCH_MEMLOCK_SOFT:--1}
  OPENSEARCH_MEMLOCK_HARD: ${OPENSEARCH_MEMLOCK_HARD:--1}
  OPENSEARCH_NOFILE_SOFT: ${OPENSEARCH_NOFILE_SOFT:-65536}
  OPENSEARCH_NOFILE_HARD: ${OPENSEARCH_NOFILE_HARD:-65536}
  NGINX_SERVER_NAME: ${NGINX_SERVER_NAME:-_}
  NGINX_HTTPS_ENABLED: ${NGINX_HTTPS_ENABLED:-false}
  NGINX_PORT: ${NGINX_PORT:-80}
  NGINX_SSL_PORT: ${NGINX_SSL_PORT:-443}
  NGINX_SSL_CERT_FILENAME: ${NGINX_SSL_CERT_FILENAME:-dify.crt}
  NGINX_SSL_CERT_KEY_FILENAME: ${NGINX_SSL_CERT_KEY_FILENAME:-dify.key}
  NGINX_SSL_PROTOCOLS: ${NGINX_SSL_PROTOCOLS:-TLSv1.1 TLSv1.2 TLSv1.3}
  NGINX_WORKER_PROCESSES: ${NGINX_WORKER_PROCESSES:-auto}
  NGINX_CLIENT_MAX_BODY_SIZE: ${NGINX_CLIENT_MAX_BODY_SIZE:-100M}
  NGINX_KEEPALIVE_TIMEOUT: ${NGINX_KEEPALIVE_TIMEOUT:-65}
  NGINX_PROXY_READ_TIMEOUT: ${NGINX_PROXY_READ_TIMEOUT:-3600s}
  NGINX_PROXY_SEND_TIMEOUT: ${NGINX_PROXY_SEND_TIMEOUT:-3600s}
  NGINX_ENABLE_CERTBOT_CHALLENGE: ${NGINX_ENABLE_CERTBOT_CHALLENGE:-false}
  CERTBOT_EMAIL: ${CERTBOT_EMAIL:[email protected]}
  CERTBOT_DOMAIN: ${CERTBOT_DOMAIN:-your_domain.com}
  CERTBOT_OPTIONS: ${CERTBOT_OPTIONS:-}
  SSRF_HTTP_PORT: ${SSRF_HTTP_PORT:-3128}
  SSRF_COREDUMP_DIR: ${SSRF_COREDUMP_DIR:-/var/spool/squid}
  SSRF_REVERSE_PROXY_PORT: ${SSRF_REVERSE_PROXY_PORT:-8194}
  SSRF_SANDBOX_HOST: ${SSRF_SANDBOX_HOST:-sandbox}
  SSRF_DEFAULT_TIME_OUT: ${SSRF_DEFAULT_TIME_OUT:-5}
  SSRF_DEFAULT_CONNECT_TIME_OUT: ${SSRF_DEFAULT_CONNECT_TIME_OUT:-5}
  SSRF_DEFAULT_READ_TIME_OUT: ${SSRF_DEFAULT_READ_TIME_OUT:-5}
  SSRF_DEFAULT_WRITE_TIME_OUT: ${SSRF_DEFAULT_WRITE_TIME_OUT:-5}
  EXPOSE_NGINX_PORT: ${EXPOSE_NGINX_PORT:-80}
  EXPOSE_NGINX_SSL_PORT: ${EXPOSE_NGINX_SSL_PORT:-443}
  POSITION_TOOL_PINS: ${POSITION_TOOL_PINS:-}
  POSITION_TOOL_INCLUDES: ${POSITION_TOOL_INCLUDES:-}
  POSITION_TOOL_EXCLUDES: ${POSITION_TOOL_EXCLUDES:-}
  POSITION_PROVIDER_PINS: ${POSITION_PROVIDER_PINS:-}
  POSITION_PROVIDER_INCLUDES: ${POSITION_PROVIDER_INCLUDES:-}
  POSITION_PROVIDER_EXCLUDES: ${POSITION_PROVIDER_EXCLUDES:-}
  CSP_WHITELIST: ${CSP_WHITELIST:-}
  CREATE_TIDB_SERVICE_JOB_ENABLED: ${CREATE_TIDB_SERVICE_JOB_ENABLED:-false}
  MAX_SUBMIT_COUNT: ${MAX_SUBMIT_COUNT:-100}
  TOP_K_MAX_VALUE: ${TOP_K_MAX_VALUE:-10}
  DB_PLUGIN_DATABASE: ${DB_PLUGIN_DATABASE:-dify_plugin}
  EXPOSE_PLUGIN_DAEMON_PORT: ${EXPOSE_PLUGIN_DAEMON_PORT:-5002}
  PLUGIN_DAEMON_PORT: ${PLUGIN_DAEMON_PORT:-5002}
  PLUGIN_DAEMON_KEY: ${PLUGIN_DAEMON_KEY:-lYkiYYT6owG+71oLerGzA7GXCgOT++6ovaezWAjpCjf+Sjc3ZtU+qUEi}
  PLUGIN_DAEMON_URL: ${PLUGIN_DAEMON_URL:-http://plugin_daemon:5002}
  PLUGIN_MAX_PACKAGE_SIZE: ${PLUGIN_MAX_PACKAGE_SIZE:-52428800}
  PLUGIN_PPROF_ENABLED: ${PLUGIN_PPROF_ENABLED:-false}
  PLUGIN_DEBUGGING_HOST: ${PLUGIN_DEBUGGING_HOST:-0.0.0.0}
  PLUGIN_DEBUGGING_PORT: ${PLUGIN_DEBUGGING_PORT:-5003}
  EXPOSE_PLUGIN_DEBUGGING_HOST: ${EXPOSE_PLUGIN_DEBUGGING_HOST:-localhost}
  EXPOSE_PLUGIN_DEBUGGING_PORT: ${EXPOSE_PLUGIN_DEBUGGING_PORT:-5003}
  PLUGIN_DIFY_INNER_API_KEY: ${PLUGIN_DIFY_INNER_API_KEY:-QaHbTe77CtuXmsfyhR7+vRjI/+XbV1AaFy691iy+kGDv2Jvy0/eAh8Y1}
  PLUGIN_DIFY_INNER_API_URL: ${PLUGIN_DIFY_INNER_API_URL:-http://api:5001}
  ENDPOINT_URL_TEMPLATE: ${ENDPOINT_URL_TEMPLATE:-http://localhost/e/{hook_id}}
  MARKETPLACE_ENABLED: ${MARKETPLACE_ENABLED:-true}
  MARKETPLACE_API_URL: ${MARKETPLACE_API_URL:-https://marketplace.dify.ai}
  FORCE_VERIFYING_SIGNATURE: ${FORCE_VERIFYING_SIGNATURE:-true}
  PLUGIN_STDIO_BUFFER_SIZE: ${PLUGIN_STDIO_BUFFER_SIZE:-1024}
  PLUGIN_STDIO_MAX_BUFFER_SIZE: ${PLUGIN_STDIO_MAX_BUFFER_SIZE:-5242880}
  PLUGIN_PYTHON_ENV_INIT_TIMEOUT: ${PLUGIN_PYTHON_ENV_INIT_TIMEOUT:-120}
  PLUGIN_MAX_EXECUTION_TIMEOUT: ${PLUGIN_MAX_EXECUTION_TIMEOUT:-600}
  PIP_MIRROR_URL: ${PIP_MIRROR_URL:-}
  PLUGIN_STORAGE_TYPE: ${PLUGIN_STORAGE_TYPE:-local}
  PLUGIN_STORAGE_LOCAL_ROOT: ${PLUGIN_STORAGE_LOCAL_ROOT:-/app/storage}
  PLUGIN_WORKING_PATH: ${PLUGIN_WORKING_PATH:-/app/storage/cwd}
  PLUGIN_INSTALLED_PATH: ${PLUGIN_INSTALLED_PATH:-plugin}
  PLUGIN_PACKAGE_CACHE_PATH: ${PLUGIN_PACKAGE_CACHE_PATH:-plugin_packages}
  PLUGIN_MEDIA_CACHE_PATH: ${PLUGIN_MEDIA_CACHE_PATH:-assets}
  PLUGIN_STORAGE_OSS_BUCKET: ${PLUGIN_STORAGE_OSS_BUCKET:-}
  PLUGIN_S3_USE_AWS: ${PLUGIN_S3_USE_AWS:-false}
  PLUGIN_S3_USE_AWS_MANAGED_IAM: ${PLUGIN_S3_USE_AWS_MANAGED_IAM:-false}
  PLUGIN_S3_ENDPOINT: ${PLUGIN_S3_ENDPOINT:-}
  PLUGIN_S3_USE_PATH_STYLE: ${PLUGIN_S3_USE_PATH_STYLE:-false}
  PLUGIN_AWS_ACCESS_KEY: ${PLUGIN_AWS_ACCESS_KEY:-}
  PLUGIN_AWS_SECRET_KEY: ${PLUGIN_AWS_SECRET_KEY:-}
  PLUGIN_AWS_REGION: ${PLUGIN_AWS_REGION:-}
  PLUGIN_AZURE_BLOB_STORAGE_CONTAINER_NAME: ${PLUGIN_AZURE_BLOB_STORAGE_CONTAINER_NAME:-}
  PLUGIN_AZURE_BLOB_STORAGE_CONNECTION_STRING: ${PLUGIN_AZURE_BLOB_STORAGE_CONNECTION_STRING:-}
  PLUGIN_TENCENT_COS_SECRET_KEY: ${PLUGIN_TENCENT_COS_SECRET_KEY:-}
  PLUGIN_TENCENT_COS_SECRET_ID: ${PLUGIN_TENCENT_COS_SECRET_ID:-}
  PLUGIN_TENCENT_COS_REGION: ${PLUGIN_TENCENT_COS_REGION:-}
  PLUGIN_ALIYUN_OSS_REGION: ${PLUGIN_ALIYUN_OSS_REGION:-}
  PLUGIN_ALIYUN_OSS_ENDPOINT: ${PLUGIN_ALIYUN_OSS_ENDPOINT:-}
  PLUGIN_ALIYUN_OSS_ACCESS_KEY_ID: ${PLUGIN_ALIYUN_OSS_ACCESS_KEY_ID:-}
  PLUGIN_ALIYUN_OSS_ACCESS_KEY_SECRET: ${PLUGIN_ALIYUN_OSS_ACCESS_KEY_SECRET:-}
  PLUGIN_ALIYUN_OSS_AUTH_VERSION: ${PLUGIN_ALIYUN_OSS_AUTH_VERSION:-v4}
  PLUGIN_ALIYUN_OSS_PATH: ${PLUGIN_ALIYUN_OSS_PATH:-}
  PLUGIN_VOLCENGINE_TOS_ENDPOINT: ${PLUGIN_VOLCENGINE_TOS_ENDPOINT:-}
  PLUGIN_VOLCENGINE_TOS_ACCESS_KEY: ${PLUGIN_VOLCENGINE_TOS_ACCESS_KEY:-}
  PLUGIN_VOLCENGINE_TOS_SECRET_KEY: ${PLUGIN_VOLCENGINE_TOS_SECRET_KEY:-}
  PLUGIN_VOLCENGINE_TOS_REGION: ${PLUGIN_VOLCENGINE_TOS_REGION:-}
  ENABLE_OTEL: ${ENABLE_OTEL:-false}
  OTLP_TRACE_ENDPOINT: ${OTLP_TRACE_ENDPOINT:-}
  OTLP_METRIC_ENDPOINT: ${OTLP_METRIC_ENDPOINT:-}
  OTLP_BASE_ENDPOINT: ${OTLP_BASE_ENDPOINT:-http://localhost:4318}
  OTLP_API_KEY: ${OTLP_API_KEY:-}
  OTEL_EXPORTER_OTLP_PROTOCOL: ${OTEL_EXPORTER_OTLP_PROTOCOL:-}
  OTEL_EXPORTER_TYPE: ${OTEL_EXPORTER_TYPE:-otlp}
  OTEL_SAMPLING_RATE: ${OTEL_SAMPLING_RATE:-0.1}
  OTEL_BATCH_EXPORT_SCHEDULE_DELAY: ${OTEL_BATCH_EXPORT_SCHEDULE_DELAY:-5000}
  OTEL_MAX_QUEUE_SIZE: ${OTEL_MAX_QUEUE_SIZE:-2048}
  OTEL_MAX_EXPORT_BATCH_SIZE: ${OTEL_MAX_EXPORT_BATCH_SIZE:-512}
  OTEL_METRIC_EXPORT_INTERVAL: ${OTEL_METRIC_EXPORT_INTERVAL:-60000}
  OTEL_BATCH_EXPORT_TIMEOUT: ${OTEL_BATCH_EXPORT_TIMEOUT:-10000}
  OTEL_METRIC_EXPORT_TIMEOUT: ${OTEL_METRIC_EXPORT_TIMEOUT:-30000}
  ALLOW_EMBED: ${ALLOW_EMBED:-false}
  QUEUE_MONITOR_THRESHOLD: ${QUEUE_MONITOR_THRESHOLD:-200}
  QUEUE_MONITOR_ALERT_EMAILS: ${QUEUE_MONITOR_ALERT_EMAILS:-}
  QUEUE_MONITOR_INTERVAL: ${QUEUE_MONITOR_INTERVAL:-30}
  SWAGGER_UI_ENABLED: ${SWAGGER_UI_ENABLED:-true}
  SWAGGER_UI_PATH: ${SWAGGER_UI_PATH:-/swagger-ui.html}
  ENABLE_CLEAN_EMBEDDING_CACHE_TASK: ${ENABLE_CLEAN_EMBEDDING_CACHE_TASK:-false}
  ENABLE_CLEAN_UNUSED_DATASETS_TASK: ${ENABLE_CLEAN_UNUSED_DATASETS_TASK:-false}
  ENABLE_CREATE_TIDB_SERVERLESS_TASK: ${ENABLE_CREATE_TIDB_SERVERLESS_TASK:-false}
  ENABLE_UPDATE_TIDB_SERVERLESS_STATUS_TASK: ${ENABLE_UPDATE_TIDB_SERVERLESS_STATUS_TASK:-false}
  ENABLE_CLEAN_MESSAGES: ${ENABLE_CLEAN_MESSAGES:-false}
  ENABLE_MAIL_CLEAN_DOCUMENT_NOTIFY_TASK: ${ENABLE_MAIL_CLEAN_DOCUMENT_NOTIFY_TASK:-false}
  ENABLE_DATASETS_QUEUE_MONITOR: ${ENABLE_DATASETS_QUEUE_MONITOR:-false}
  ENABLE_CHECK_UPGRADABLE_PLUGIN_TASK: ${ENABLE_CHECK_UPGRADABLE_PLUGIN_TASK:-true}

services:
  # API service
  api:
    image: langgenius/dify-api:1.8.0
    restart: always
    environment:
      # Use the shared environment variables.
      <<: *shared-api-worker-env
      # Startup mode, 'api' starts the API server.
      MODE: api
      SENTRY_DSN: ${API_SENTRY_DSN:-}
      SENTRY_TRACES_SAMPLE_RATE: ${API_SENTRY_TRACES_SAMPLE_RATE:-1.0}
      SENTRY_PROFILES_SAMPLE_RATE: ${API_SENTRY_PROFILES_SAMPLE_RATE:-1.0}
      PLUGIN_REMOTE_INSTALL_HOST: ${EXPOSE_PLUGIN_DEBUGGING_HOST:-localhost}
      PLUGIN_REMOTE_INSTALL_PORT: ${EXPOSE_PLUGIN_DEBUGGING_PORT:-5003}
      PLUGIN_MAX_PACKAGE_SIZE: ${PLUGIN_MAX_PACKAGE_SIZE:-52428800}
      INNER_API_KEY_FOR_PLUGIN: ${PLUGIN_DIFY_INNER_API_KEY:-QaHbTe77CtuXmsfyhR7+vRjI/+XbV1AaFy691iy+kGDv2Jvy0/eAh8Y1}
    depends_on:
      db:
        condition: service_healthy
      redis:
        condition: service_started
    volumes:
      # Mount the storage directory to the container, for storing user files.
      - ./volumes/app/storage:/app/api/storage
    networks:
      - ssrf_proxy_network
      - default

  # worker service
  # The Celery worker for processing the queue.
  worker:
    image: langgenius/dify-api:1.8.0
    restart: always
    environment:
      # Use the shared environment variables.
      <<: *shared-api-worker-env
      # Startup mode, 'worker' starts the Celery worker for processing the queue.
      MODE: worker
      SENTRY_DSN: ${API_SENTRY_DSN:-}
      SENTRY_TRACES_SAMPLE_RATE: ${API_SENTRY_TRACES_SAMPLE_RATE:-1.0}
      SENTRY_PROFILES_SAMPLE_RATE: ${API_SENTRY_PROFILES_SAMPLE_RATE:-1.0}
      PLUGIN_MAX_PACKAGE_SIZE: ${PLUGIN_MAX_PACKAGE_SIZE:-52428800}
      INNER_API_KEY_FOR_PLUGIN: ${PLUGIN_DIFY_INNER_API_KEY:-QaHbTe77CtuXmsfyhR7+vRjI/+XbV1AaFy691iy+kGDv2Jvy0/eAh8Y1}
    depends_on:
      db:
        condition: service_healthy
      redis:
        condition: service_started
    volumes:
      # Mount the storage directory to the container, for storing user files.
      - ./volumes/app/storage:/app/api/storage
    networks:
      - ssrf_proxy_network
      - default

  # worker_beat service
  # Celery beat for scheduling periodic tasks.
  worker_beat:
    image: langgenius/dify-api:1.8.0
    restart: always
    environment:
      # Use the shared environment variables.
      <<: *shared-api-worker-env
      # Startup mode, 'worker_beat' starts the Celery beat for scheduling periodic tasks.
      MODE: beat
    depends_on:
      db:
        condition: service_healthy
      redis:
        condition: service_started
    networks:
      - ssrf_proxy_network
      - default

  # Frontend web application.
  web:
    image: langgenius/dify-web:1.8.0
    restart: always
    environment:
      CONSOLE_API_URL: ${CONSOLE_API_URL:-}
      APP_API_URL: ${APP_API_URL:-}
      SENTRY_DSN: ${WEB_SENTRY_DSN:-}
      NEXT_TELEMETRY_DISABLED: ${NEXT_TELEMETRY_DISABLED:-0}
      TEXT_GENERATION_TIMEOUT_MS: ${TEXT_GENERATION_TIMEOUT_MS:-60000}
      CSP_WHITELIST: ${CSP_WHITELIST:-}
      ALLOW_EMBED: ${ALLOW_EMBED:-false}
      ALLOW_UNSAFE_DATA_SCHEME: ${ALLOW_UNSAFE_DATA_SCHEME:-false}
      MARKETPLACE_API_URL: ${MARKETPLACE_API_URL:-https://marketplace.dify.ai}
      MARKETPLACE_URL: ${MARKETPLACE_URL:-https://marketplace.dify.ai}
      TOP_K_MAX_VALUE: ${TOP_K_MAX_VALUE:-}
      INDEXING_MAX_SEGMENTATION_TOKENS_LENGTH: ${INDEXING_MAX_SEGMENTATION_TOKENS_LENGTH:-}
      PM2_INSTANCES: ${PM2_INSTANCES:-2}
      LOOP_NODE_MAX_COUNT: ${LOOP_NODE_MAX_COUNT:-100}
      MAX_TOOLS_NUM: ${MAX_TOOLS_NUM:-10}
      MAX_PARALLEL_LIMIT: ${MAX_PARALLEL_LIMIT:-10}
      MAX_ITERATIONS_NUM: ${MAX_ITERATIONS_NUM:-99}
      MAX_TREE_DEPTH: ${MAX_TREE_DEPTH:-50}
      ENABLE_WEBSITE_JINAREADER: ${ENABLE_WEBSITE_JINAREADER:-true}
      ENABLE_WEBSITE_FIRECRAWL: ${ENABLE_WEBSITE_FIRECRAWL:-true}
      ENABLE_WEBSITE_WATERCRAWL: ${ENABLE_WEBSITE_WATERCRAWL:-true}
  # The postgres database.
  db:
    image: postgres:15-alpine
    restart: always
    environment:
      POSTGRES_USER: ${POSTGRES_USER:-postgres}
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-difyai123456}
      POSTGRES_DB: ${POSTGRES_DB:-dify}
      PGDATA: ${PGDATA:-/var/lib/postgresql/data/pgdata}
    command: >
      postgres -c 'max_connections=${POSTGRES_MAX_CONNECTIONS:-100}'
               -c 'shared_buffers=${POSTGRES_SHARED_BUFFERS:-128MB}'
               -c 'work_mem=${POSTGRES_WORK_MEM:-4MB}'
               -c 'maintenance_work_mem=${POSTGRES_MAINTENANCE_WORK_MEM:-64MB}'
               -c 'effective_cache_size=${POSTGRES_EFFECTIVE_CACHE_SIZE:-4096MB}'
    volumes:
      - ./volumes/db/data:/var/lib/postgresql/data
    healthcheck:
      test: [ 'CMD', 'pg_isready', '-h', 'db', '-U', '${PGUSER:-postgres}', '-d', '${POSTGRES_DB:-dify}' ]
      interval: 1s
      timeout: 3s
      retries: 60

  # The redis cache.
  redis:
    image: redis:6-alpine
    restart: always
    environment:
      REDISCLI_AUTH: ${REDIS_PASSWORD:-difyai123456}
    volumes:
      # Mount the redis data directory to the container.
      - ./volumes/redis/data:/data
    # Set the redis password when startup redis server.
    command: redis-server --requirepass ${REDIS_PASSWORD:-difyai123456}
    healthcheck:
      test: [ 'CMD', 'redis-cli', 'ping' ]

  # The DifySandbox
  sandbox:
    image: langgenius/dify-sandbox:0.2.12
    restart: always
    environment:
      # The DifySandbox configurations
      # Make sure you are changing this key for your deployment with a strong key.
      # You can generate a strong key using `openssl rand -base64 42`.
      API_KEY: ${SANDBOX_API_KEY:-dify-sandbox}
      GIN_MODE: ${SANDBOX_GIN_MODE:-release}
      WORKER_TIMEOUT: ${SANDBOX_WORKER_TIMEOUT:-15}
      ENABLE_NETWORK: ${SANDBOX_ENABLE_NETWORK:-true}
      HTTP_PROXY: ${SANDBOX_HTTP_PROXY:-http://ssrf_proxy:3128}
      HTTPS_PROXY: ${SANDBOX_HTTPS_PROXY:-http://ssrf_proxy:3128}
      SANDBOX_PORT: ${SANDBOX_PORT:-8194}
      PIP_MIRROR_URL: ${PIP_MIRROR_URL:-}
    volumes:
      - ./volumes/sandbox/dependencies:/dependencies
      - ./volumes/sandbox/conf:/conf
    healthcheck:
      test: [ 'CMD', 'curl', '-f', 'http://localhost:8194/health' ]
    networks:
      - ssrf_proxy_network

  # plugin daemon
  plugin_daemon:
    image: langgenius/dify-plugin-daemon:0.2.0-local
    restart: always
    environment:
      # Use the shared environment variables.
      <<: *shared-api-worker-env
      DB_DATABASE: ${DB_PLUGIN_DATABASE:-dify_plugin}
      SERVER_PORT: ${PLUGIN_DAEMON_PORT:-5002}
      SERVER_KEY: ${PLUGIN_DAEMON_KEY:-lYkiYYT6owG+71oLerGzA7GXCgOT++6ovaezWAjpCjf+Sjc3ZtU+qUEi}
      MAX_PLUGIN_PACKAGE_SIZE: ${PLUGIN_MAX_PACKAGE_SIZE:-52428800}
      PPROF_ENABLED: ${PLUGIN_PPROF_ENABLED:-false}
      DIFY_INNER_API_URL: ${PLUGIN_DIFY_INNER_API_URL:-http://api:5001}
      DIFY_INNER_API_KEY: ${PLUGIN_DIFY_INNER_API_KEY:-QaHbTe77CtuXmsfyhR7+vRjI/+XbV1AaFy691iy+kGDv2Jvy0/eAh8Y1}
      PLUGIN_REMOTE_INSTALLING_HOST: ${PLUGIN_DEBUGGING_HOST:-0.0.0.0}
      PLUGIN_REMOTE_INSTALLING_PORT: ${PLUGIN_DEBUGGING_PORT:-5003}
      PLUGIN_WORKING_PATH: ${PLUGIN_WORKING_PATH:-/app/storage/cwd}
      FORCE_VERIFYING_SIGNATURE: ${FORCE_VERIFYING_SIGNATURE:-true}
      PYTHON_ENV_INIT_TIMEOUT: ${PLUGIN_PYTHON_ENV_INIT_TIMEOUT:-120}
      PLUGIN_MAX_EXECUTION_TIMEOUT: ${PLUGIN_MAX_EXECUTION_TIMEOUT:-600}
      PLUGIN_STDIO_BUFFER_SIZE: ${PLUGIN_STDIO_BUFFER_SIZE:-1024}
      PLUGIN_STDIO_MAX_BUFFER_SIZE: ${PLUGIN_STDIO_MAX_BUFFER_SIZE:-5242880}
      PIP_MIRROR_URL: ${PIP_MIRROR_URL:-}
      PLUGIN_STORAGE_TYPE: ${PLUGIN_STORAGE_TYPE:-local}
      PLUGIN_STORAGE_LOCAL_ROOT: ${PLUGIN_STORAGE_LOCAL_ROOT:-/app/storage}
      PLUGIN_INSTALLED_PATH: ${PLUGIN_INSTALLED_PATH:-plugin}
      PLUGIN_PACKAGE_CACHE_PATH: ${PLUGIN_PACKAGE_CACHE_PATH:-plugin_packages}
      PLUGIN_MEDIA_CACHE_PATH: ${PLUGIN_MEDIA_CACHE_PATH:-assets}
      PLUGIN_STORAGE_OSS_BUCKET: ${PLUGIN_STORAGE_OSS_BUCKET:-}
      S3_USE_AWS_MANAGED_IAM: ${PLUGIN_S3_USE_AWS_MANAGED_IAM:-false}
      S3_USE_AWS: ${PLUGIN_S3_USE_AWS:-false}
      S3_ENDPOINT: ${PLUGIN_S3_ENDPOINT:-}
      S3_USE_PATH_STYLE: ${PLUGIN_S3_USE_PATH_STYLE:-false}
      AWS_ACCESS_KEY: ${PLUGIN_AWS_ACCESS_KEY:-}
      AWS_SECRET_KEY: ${PLUGIN_AWS_SECRET_KEY:-}
      AWS_REGION: ${PLUGIN_AWS_REGION:-}
      AZURE_BLOB_STORAGE_CONNECTION_STRING: ${PLUGIN_AZURE_BLOB_STORAGE_CONNECTION_STRING:-}
      AZURE_BLOB_STORAGE_CONTAINER_NAME: ${PLUGIN_AZURE_BLOB_STORAGE_CONTAINER_NAME:-}
      TENCENT_COS_SECRET_KEY: ${PLUGIN_TENCENT_COS_SECRET_KEY:-}
      TENCENT_COS_SECRET_ID: ${PLUGIN_TENCENT_COS_SECRET_ID:-}
      TENCENT_COS_REGION: ${PLUGIN_TENCENT_COS_REGION:-}
      ALIYUN_OSS_REGION: ${PLUGIN_ALIYUN_OSS_REGION:-}
      ALIYUN_OSS_ENDPOINT: ${PLUGIN_ALIYUN_OSS_ENDPOINT:-}
      ALIYUN_OSS_ACCESS_KEY_ID: ${PLUGIN_ALIYUN_OSS_ACCESS_KEY_ID:-}
      ALIYUN_OSS_ACCESS_KEY_SECRET: ${PLUGIN_ALIYUN_OSS_ACCESS_KEY_SECRET:-}
      ALIYUN_OSS_AUTH_VERSION: ${PLUGIN_ALIYUN_OSS_AUTH_VERSION:-v4}
      ALIYUN_OSS_PATH: ${PLUGIN_ALIYUN_OSS_PATH:-}
      VOLCENGINE_TOS_ENDPOINT: ${PLUGIN_VOLCENGINE_TOS_ENDPOINT:-}
      VOLCENGINE_TOS_ACCESS_KEY: ${PLUGIN_VOLCENGINE_TOS_ACCESS_KEY:-}
      VOLCENGINE_TOS_SECRET_KEY: ${PLUGIN_VOLCENGINE_TOS_SECRET_KEY:-}
      VOLCENGINE_TOS_REGION: ${PLUGIN_VOLCENGINE_TOS_REGION:-}
    ports:
      - "${EXPOSE_PLUGIN_DEBUGGING_PORT:-5003}:${PLUGIN_DEBUGGING_PORT:-5003}"
    volumes:
      - ./volumes/plugin_daemon:/app/storage
    depends_on:
      db:
        condition: service_healthy

  # ssrf_proxy server
  # for more information, please refer to
  # https://docs.dify.ai/learn-more/faq/install-faq#18-why-is-ssrf-proxy-needed%3F
  ssrf_proxy:
    image: ubuntu/squid:latest
    restart: always
    volumes:
      - ./ssrf_proxy/squid.conf.template:/etc/squid/squid.conf.template
      - ./ssrf_proxy/docker-entrypoint.sh:/docker-entrypoint-mount.sh
    entrypoint: [ 'sh', '-c', "cp /docker-entrypoint-mount.sh /docker-entrypoint.sh && sed -i 's/\r$$//' /docker-entrypoint.sh && chmod +x /docker-entrypoint.sh && /docker-entrypoint.sh" ]
    environment:
      # pls clearly modify the squid env vars to fit your network environment.
      HTTP_PORT: ${SSRF_HTTP_PORT:-3128}
      COREDUMP_DIR: ${SSRF_COREDUMP_DIR:-/var/spool/squid}
      REVERSE_PROXY_PORT: ${SSRF_REVERSE_PROXY_PORT:-8194}
      SANDBOX_HOST: ${SSRF_SANDBOX_HOST:-sandbox}
      SANDBOX_PORT: ${SANDBOX_PORT:-8194}
    networks:
      - ssrf_proxy_network
      - default

  # Certbot service
  # use `docker-compose --profile certbot up` to start the certbot service.
  certbot:
    image: certbot/certbot
    profiles:
      - certbot
    volumes:
      - ./volumes/certbot/conf:/etc/letsencrypt
      - ./volumes/certbot/www:/var/www/html
      - ./volumes/certbot/logs:/var/log/letsencrypt
      - ./volumes/certbot/conf/live:/etc/letsencrypt/live
      - ./certbot/update-cert.template.txt:/update-cert.template.txt
      - ./certbot/docker-entrypoint.sh:/docker-entrypoint.sh
    environment:
      - CERTBOT_EMAIL=${CERTBOT_EMAIL}
      - CERTBOT_DOMAIN=${CERTBOT_DOMAIN}
      - CERTBOT_OPTIONS=${CERTBOT_OPTIONS:-}
    entrypoint: [ '/docker-entrypoint.sh' ]
    command: [ 'tail', '-f', '/dev/null' ]

  # The nginx reverse proxy.
  # used for reverse proxying the API service and Web service.
  nginx:
    image: nginx:latest
    restart: always
    volumes:
      - ./nginx/nginx.conf.template:/etc/nginx/nginx.conf.template
      - ./nginx/proxy.conf.template:/etc/nginx/proxy.conf.template
      - ./nginx/https.conf.template:/etc/nginx/https.conf.template
      - ./nginx/conf.d:/etc/nginx/conf.d
      - ./nginx/docker-entrypoint.sh:/docker-entrypoint-mount.sh
      - ./nginx/ssl:/etc/ssl # cert dir (legacy)
      - ./volumes/certbot/conf/live:/etc/letsencrypt/live # cert dir (with certbot container)
      - ./volumes/certbot/conf:/etc/letsencrypt
      - ./volumes/certbot/www:/var/www/html
    entrypoint: [ 'sh', '-c', "cp /docker-entrypoint-mount.sh /docker-entrypoint.sh && sed -i 's/\r$$//' /docker-entrypoint.sh && chmod +x /docker-entrypoint.sh && /docker-entrypoint.sh" ]
    environment:
      NGINX_SERVER_NAME: ${NGINX_SERVER_NAME:-_}
      NGINX_HTTPS_ENABLED: ${NGINX_HTTPS_ENABLED:-false}
      NGINX_SSL_PORT: ${NGINX_SSL_PORT:-443}
      NGINX_PORT: ${NGINX_PORT:-80}
      # You're required to add your own SSL certificates/keys to the `./nginx/ssl` directory
      # and modify the env vars below in .env if HTTPS_ENABLED is true.
      NGINX_SSL_CERT_FILENAME: ${NGINX_SSL_CERT_FILENAME:-dify.crt}
      NGINX_SSL_CERT_KEY_FILENAME: ${NGINX_SSL_CERT_KEY_FILENAME:-dify.key}
      NGINX_SSL_PROTOCOLS: ${NGINX_SSL_PROTOCOLS:-TLSv1.1 TLSv1.2 TLSv1.3}
      NGINX_WORKER_PROCESSES: ${NGINX_WORKER_PROCESSES:-auto}
      NGINX_CLIENT_MAX_BODY_SIZE: ${NGINX_CLIENT_MAX_BODY_SIZE:-100M}
      NGINX_KEEPALIVE_TIMEOUT: ${NGINX_KEEPALIVE_TIMEOUT:-65}
      NGINX_PROXY_READ_TIMEOUT: ${NGINX_PROXY_READ_TIMEOUT:-3600s}
      NGINX_PROXY_SEND_TIMEOUT: ${NGINX_PROXY_SEND_TIMEOUT:-3600s}
      NGINX_ENABLE_CERTBOT_CHALLENGE: ${NGINX_ENABLE_CERTBOT_CHALLENGE:-false}
      CERTBOT_DOMAIN: ${CERTBOT_DOMAIN:-}
    depends_on:
      - api
      - web
    ports:
      - '${EXPOSE_NGINX_PORT:-80}:${NGINX_PORT:-80}'
      - '${EXPOSE_NGINX_SSL_PORT:-443}:${NGINX_SSL_PORT:-443}'

  # The Weaviate vector store.
  weaviate:
    image: semitechnologies/weaviate:1.19.0
    profiles:
      - ''
      - weaviate
    restart: always
    volumes:
      # Mount the Weaviate data directory to the con tainer.
      - ./volumes/weaviate:/var/lib/weaviate
    environment:
      # The Weaviate configurations
      # You can refer to the [Weaviate](https://weaviate.io/developers/weaviate/config-refs/env-vars) documentation for more information.
      PERSISTENCE_DATA_PATH: ${WEAVIATE_PERSISTENCE_DATA_PATH:-/var/lib/weaviate}
      QUERY_DEFAULTS_LIMIT: ${WEAVIATE_QUERY_DEFAULTS_LIMIT:-25}
      AUTHENTICATION_ANONYMOUS_ACCESS_ENABLED: ${WEAVIATE_AUTHENTICATION_ANONYMOUS_ACCESS_ENABLED:-false}
      DEFAULT_VECTORIZER_MODULE: ${WEAVIATE_DEFAULT_VECTORIZER_MODULE:-none}
      CLUSTER_HOSTNAME: ${WEAVIATE_CLUSTER_HOSTNAME:-node1}
      AUTHENTICATION_APIKEY_ENABLED: ${WEAVIATE_AUTHENTICATION_APIKEY_ENABLED:-true}
      AUTHENTICATION_APIKEY_ALLOWED_KEYS: ${WEAVIATE_AUTHENTICATION_APIKEY_ALLOWED_KEYS:-WVF5YThaHlkYwhGUSmCRgsX3tD5ngdN8pkih}
      AUTHENTICATION_APIKEY_USERS: ${WEAVIATE_AUTHENTICATION_APIKEY_USERS:[email protected]}
      AUTHORIZATION_ADMINLIST_ENABLED: ${WEAVIATE_AUTHORIZATION_ADMINLIST_ENABLED:-true}
      AUTHORIZATION_ADMINLIST_USERS: ${WEAVIATE_AUTHORIZATION_ADMINLIST_USERS:[email protected]}

  # Qdrant vector store.
  # (if used, you need to set VECTOR_STORE to qdrant in the api & worker service.)
  qdrant:
    image: langgenius/qdrant:v1.7.3
    profiles:
      - qdrant
    restart: always
    volumes:
      - ./volumes/qdrant:/qdrant/storage
    environment:
      QDRANT_API_KEY: ${QDRANT_API_KEY:-difyai123456}

  # The Couchbase vector store.
  couchbase-server:
    build: ./couchbase-server
    profiles:
      - couchbase
    restart: always
    environment:
      - CLUSTER_NAME=dify_search
      - COUCHBASE_ADMINISTRATOR_USERNAME=${COUCHBASE_USER:-Administrator}
      - COUCHBASE_ADMINISTRATOR_PASSWORD=${COUCHBASE_PASSWORD:-password}
      - COUCHBASE_BUCKET=${COUCHBASE_BUCKET_NAME:-Embeddings}
      - COUCHBASE_BUCKET_RAMSIZE=512
      - COUCHBASE_RAM_SIZE=2048
      - COUCHBASE_EVENTING_RAM_SIZE=512
      - COUCHBASE_INDEX_RAM_SIZE=512
      - COUCHBASE_FTS_RAM_SIZE=1024
    hostname: couchbase-server
    container_name: couchbase-server
    working_dir: /opt/couchbase
    stdin_open: true
    tty: true
    entrypoint: [ "" ]
    command: sh -c "/opt/couchbase/init/init-cbserver.sh"
    volumes:
      - ./volumes/couchbase/data:/opt/couchbase/var/lib/couchbase/data
    healthcheck:
      # ensure bucket was created before proceeding
      test: [ "CMD-SHELL", "curl -s -f -u Administrator:password http://localhost:8091/pools/default/buckets | grep -q '\\[{' || exit 1" ]
      interval: 10s
      retries: 10
      start_period: 30s
      timeout: 10s

  # The pgvector vector database.
  pgvector:
    image: pgvector/pgvector:pg16
    profiles:
      - pgvector
    restart: always
    environment:
      PGUSER: ${PGVECTOR_PGUSER:-postgres}
      # The password for the default postgres user.
      POSTGRES_PASSWORD: ${PGVECTOR_POSTGRES_PASSWORD:-difyai123456}
      # The name of the default postgres database.
      POSTGRES_DB: ${PGVECTOR_POSTGRES_DB:-dify}
      # postgres data directory
      PGDATA: ${PGVECTOR_PGDATA:-/var/lib/postgresql/data/pgdata}
      # pg_bigm module for full text search
      PG_BIGM: ${PGVECTOR_PG_BIGM:-false}
      PG_BIGM_VERSION: ${PGVECTOR_PG_BIGM_VERSION:-1.2-20240606}
    volumes:
      - ./volumes/pgvector/data:/var/lib/postgresql/data
      - ./pgvector/docker-entrypoint.sh:/docker-entrypoint.sh
    entrypoint: [ '/docker-entrypoint.sh' ]
    healthcheck:
      test: [ 'CMD', 'pg_isready' ]
      interval: 1s
      timeout: 3s
      retries: 30

  # get image from https://www.vastdata.com.cn/
  vastbase:
    image: vastdata/vastbase-vector
    profiles:
      - vastbase
    restart: always
    environment:
      - VB_DBCOMPATIBILITY=PG
      - VB_DB=dify
      - VB_USERNAME=dify
      - VB_PASSWORD=Difyai123456
    ports:
      - '5434:5432'
    volumes:
      - ./vastbase/lic:/home/vastbase/vastbase/lic
      - ./vastbase/data:/home/vastbase/data
      - ./vastbase/backup:/home/vastbase/backup
      - ./vastbase/backup_log:/home/vastbase/backup_log
    healthcheck:
      test: [ 'CMD', 'pg_isready' ]
      interval: 1s
      timeout: 3s
      retries: 30

  # pgvecto-rs vector store
  pgvecto-rs:
    image: tensorchord/pgvecto-rs:pg16-v0.3.0
    profiles:
      - pgvecto-rs
    restart: always
    environment:
      PGUSER: ${PGVECTOR_PGUSER:-postgres}
      # The password for the default postgres user.
      POSTGRES_PASSWORD: ${PGVECTOR_POSTGRES_PASSWORD:-difyai123456}
      # The name of the default postgres database.
      POSTGRES_DB: ${PGVECTOR_POSTGRES_DB:-dify}
      # postgres data directory
      PGDATA: ${PGVECTOR_PGDATA:-/var/lib/postgresql/data/pgdata}
    volumes:
      - ./volumes/pgvecto_rs/data:/var/lib/postgresql/data
    healthcheck:
      test: [ 'CMD', 'pg_isready' ]
      interval: 1s
      timeout: 3s
      retries: 30

  # Chroma vector database
  chroma:
    image: ghcr.io/chroma-core/chroma:0.5.20
    profiles:
      - chroma
    restart: always
    volumes:
      - ./volumes/chroma:/chroma/chroma
    environment:
      CHROMA_SERVER_AUTHN_CREDENTIALS: ${CHROMA_SERVER_AUTHN_CREDENTIALS:-difyai123456}
      CHROMA_SERVER_AUTHN_PROVIDER: ${CHROMA_SERVER_AUTHN_PROVIDER:-chromadb.auth.token_authn.TokenAuthenticationServerProvider}
      IS_PERSISTENT: ${CHROMA_IS_PERSISTENT:-TRUE}

  # OceanBase vector database
  oceanbase:
    image: oceanbase/oceanbase-ce:4.3.5-lts
    container_name: oceanbase
    profiles:
      - oceanbase
    restart: always
    volumes:
      - ./volumes/oceanbase/data:/root/ob
      - ./volumes/oceanbase/conf:/root/.obd/cluster
      - ./volumes/oceanbase/init.d:/root/boot/init.d
    environment:
      OB_MEMORY_LIMIT: ${OCEANBASE_MEMORY_LIMIT:-6G}
      OB_SYS_PASSWORD: ${OCEANBASE_VECTOR_PASSWORD:-difyai123456}
      OB_TENANT_PASSWORD: ${OCEANBASE_VECTOR_PASSWORD:-difyai123456}
      OB_CLUSTER_NAME: ${OCEANBASE_CLUSTER_NAME:-difyai}
      OB_SERVER_IP: 127.0.0.1
      MODE: mini
    ports:
      - "${OCEANBASE_VECTOR_PORT:-2881}:2881"
    healthcheck:
      test: [ 'CMD-SHELL', 'obclient -h127.0.0.1 -P2881 -uroot@test -p$${OB_TENANT_PASSWORD} -e "SELECT 1;"' ]
      interval: 10s
      retries: 30
      start_period: 30s
      timeout: 10s

  # Oracle vector database
  oracle:
    image: container-registry.oracle.com/database/free:latest
    profiles:
      - oracle
    restart: always
    volumes:
      - source: oradata
        type: volume
        target: /opt/oracle/oradata
      - ./startupscripts:/opt/oracle/scripts/startup
    environment:
      ORACLE_PWD: ${ORACLE_PWD:-Dify123456}
      ORACLE_CHARACTERSET: ${ORACLE_CHARACTERSET:-AL32UTF8}

  # Milvus vector database services
  etcd:
    container_name: milvus-etcd
    image: quay.io/coreos/etcd:v3.5.5
    profiles:
      - milvus
    environment:
      ETCD_AUTO_COMPACTION_MODE: ${ETCD_AUTO_COMPACTION_MODE:-revision}
      ETCD_AUTO_COMPACTION_RETENTION: ${ETCD_AUTO_COMPACTION_RETENTION:-1000}
      ETCD_QUOTA_BACKEND_BYTES: ${ETCD_QUOTA_BACKEND_BYTES:-4294967296}
      ETCD_SNAPSHOT_COUNT: ${ETCD_SNAPSHOT_COUNT:-50000}
    volumes:
      - ./volumes/milvus/etcd:/etcd
    command: etcd -advertise-client-urls=http://127.0.0.1:2379 -listen-client-urls http://0.0.0.0:2379 --data-dir /etcd
    healthcheck:
      test: [ 'CMD', 'etcdctl', 'endpoint', 'health' ]
      interval: 30s
      timeout: 20s
      retries: 3
    networks:
      - milvus

  minio:
    container_name: milvus-minio
    image: minio/minio:RELEASE.2023-03-20T20-16-18Z
    profiles:
      - milvus
    environment:
      MINIO_ACCESS_KEY: ${MINIO_ACCESS_KEY:-minioadmin}
      MINIO_SECRET_KEY: ${MINIO_SECRET_KEY:-minioadmin}
    volumes:
      - ./volumes/milvus/minio:/minio_data
    command: minio server /minio_data --console-address ":9001"
    healthcheck:
      test: [ 'CMD', 'curl', '-f', 'http://localhost:9000/minio/health/live' ]
      interval: 30s
      timeout: 20s
      retries: 3
    networks:
      - milvus

  milvus-standalone:
    container_name: milvus-standalone
    image: milvusdb/milvus:v2.5.15
    profiles:
      - milvus
    command: [ 'milvus', 'run', 'standalone' ]
    environment:
      ETCD_ENDPOINTS: ${ETCD_ENDPOINTS:-etcd:2379}
      MINIO_ADDRESS: ${MINIO_ADDRESS:-minio:9000}
      common.security.authorizationEnabled: ${MILVUS_AUTHORIZATION_ENABLED:-true}
    volumes:
      - ./volumes/milvus/milvus:/var/lib/milvus
    healthcheck:
      test: [ 'CMD', 'curl', '-f', 'http://localhost:9091/healthz' ]
      interval: 30s
      start_period: 90s
      timeout: 20s
      retries: 3
    depends_on:
      - etcd
      - minio
    ports:
      - 19530:19530
      - 9091:9091
    networks:
      - milvus

  # Opensearch vector database
  opensearch:
    container_name: opensearch
    image: opensearchproject/opensearch:latest
    profiles:
      - opensearch
    environment:
      discovery.type: ${OPENSEARCH_DISCOVERY_TYPE:-single-node}
      bootstrap.memory_lock: ${OPENSEARCH_BOOTSTRAP_MEMORY_LOCK:-true}
      OPENSEARCH_JAVA_OPTS: -Xms${OPENSEARCH_JAVA_OPTS_MIN:-512m} -Xmx${OPENSEARCH_JAVA_OPTS_MAX:-1024m}
      OPENSEARCH_INITIAL_ADMIN_PASSWORD: ${OPENSEARCH_INITIAL_ADMIN_PASSWORD:-Qazwsxedc!@#123}
    ulimits:
      memlock:
        soft: ${OPENSEARCH_MEMLOCK_SOFT:--1}
        hard: ${OPENSEARCH_MEMLOCK_HARD:--1}
      nofile:
        soft: ${OPENSEARCH_NOFILE_SOFT:-65536}
        hard: ${OPENSEARCH_NOFILE_HARD:-65536}
    volumes:
      - ./volumes/opensearch/data:/usr/share/opensearch/data
    networks:
      - opensearch-net

  opensearch-dashboards:
    container_name: opensearch-dashboards
    image: opensearchproject/opensearch-dashboards:latest
    profiles:
      - opensearch
    environment:
      OPENSEARCH_HOSTS: '["https://opensearch:9200"]'
    volumes:
      - ./volumes/opensearch/opensearch_dashboards.yml:/usr/share/opensearch-dashboards/config/opensearch_dashboards.yml
    networks:
      - opensearch-net
    depends_on:
      - opensearch

  # opengauss vector database.
  opengauss:
    image: opengauss/opengauss:7.0.0-RC1
    profiles:
      - opengauss
    privileged: true
    restart: always
    environment:
      GS_USERNAME: ${OPENGAUSS_USER:-postgres}
      GS_PASSWORD: ${OPENGAUSS_PASSWORD:-Dify@123}
      GS_PORT: ${OPENGAUSS_PORT:-6600}
      GS_DB: ${OPENGAUSS_DATABASE:-dify}
    volumes:
      - ./volumes/opengauss/data:/var/lib/opengauss/data
    healthcheck:
      test: [ "CMD-SHELL", "netstat -lntp | grep tcp6 > /dev/null 2>&1" ]
      interval: 10s
      timeout: 10s
      retries: 10
    ports:
      - ${OPENGAUSS_PORT:-6600}:${OPENGAUSS_PORT:-6600}

  # MyScale vector database
  myscale:
    container_name: myscale
    image: myscale/myscaledb:1.6.4
    profiles:
      - myscale
    restart: always
    tty: true
    volumes:
      - ./volumes/myscale/data:/var/lib/clickhouse
      - ./volumes/myscale/log:/var/log/clickhouse-server
      - ./volumes/myscale/config/users.d/custom_users_config.xml:/etc/clickhouse-server/users.d/custom_users_config.xml
    ports:
      - ${MYSCALE_PORT:-8123}:${MYSCALE_PORT:-8123}

  # Matrixone vector store.
  matrixone:
    hostname: matrixone
    image: matrixorigin/matrixone:2.1.1
    profiles:
      - matrixone
    restart: always
    volumes:
      - ./volumes/matrixone/data:/mo-data
    ports:
      - ${MATRIXONE_PORT:-6001}:${MATRIXONE_PORT:-6001}

  # https://www.elastic.co/guide/en/elasticsearch/reference/current/settings.html
  # https://www.elastic.co/guide/en/elasticsearch/reference/current/docker.html#docker-prod-prerequisites
  elasticsearch:
    image: docker.elastic.co/elasticsearch/elasticsearch:8.14.3
    container_name: elasticsearch
    profiles:
      - elasticsearch
      - elasticsearch-ja
    restart: always
    volumes:
      - ./elasticsearch/docker-entrypoint.sh:/docker-entrypoint-mount.sh
      - dify_es01_data:/usr/share/elasticsearch/data
    environment:
      ELASTIC_PASSWORD: ${ELASTICSEARCH_PASSWORD:-elastic}
      VECTOR_STORE: ${VECTOR_STORE:-}
      cluster.name: dify-es-cluster
      node.name: dify-es0
      discovery.type: single-node
      xpack.license.self_generated.type: basic
      xpack.security.enabled: 'true'
      xpack.security.enrollment.enabled: 'false'
      xpack.security.http.ssl.enabled: 'false'
    ports:
      - ${ELASTICSEARCH_PORT:-9200}:9200
    deploy:
      resources:
        limits:
          memory: 2g
    entrypoint: [ 'sh', '-c', "sh /docker-entrypoint-mount.sh" ]
    healthcheck:
      test: [ 'CMD', 'curl', '-s', 'http://localhost:9200/_cluster/health?pretty' ]
      interval: 30s
      timeout: 10s
      retries: 50

  # https://www.elastic.co/guide/en/kibana/current/docker.html
  # https://www.elastic.co/guide/en/kibana/current/settings.html
  kibana:
    image: docker.elastic.co/kibana/kibana:8.14.3
    container_name: kibana
    profiles:
      - elasticsearch
    depends_on:
      - elasticsearch
    restart: always
    environment:
      XPACK_ENCRYPTEDSAVEDOBJECTS_ENCRYPTIONKEY: d1a66dfd-c4d3-4a0a-8290-2abcb83ab3aa
      NO_PROXY: localhost,127.0.0.1,elasticsearch,kibana
      XPACK_SECURITY_ENABLED: 'true'
      XPACK_SECURITY_ENROLLMENT_ENABLED: 'false'
      XPACK_SECURITY_HTTP_SSL_ENABLED: 'false'
      XPACK_FLEET_ISAIRGAPPED: 'true'
      I18N_LOCALE: zh-CN
      SERVER_PORT: '5601'
      ELASTICSEARCH_HOSTS: http://elasticsearch:9200
    ports:
      - ${KIBANA_PORT:-5601}:5601
    healthcheck:
      test: [ 'CMD-SHELL', 'curl -s http://localhost:5601 >/dev/null || exit 1' ]
      interval: 30s
      timeout: 10s
      retries: 3

  # unstructured .
  # (if used, you need to set ETL_TYPE to Unstructured in the api & worker service.)
  unstructured:
    image: downloads.unstructured.io/unstructured-io/unstructured-api:latest
    profiles:
      - unstructured
    restart: always
    volumes:
      - ./volumes/unstructured:/app/data

networks:
  # create a network between sandbox, api and ssrf_proxy, and can not access outside.
  ssrf_proxy_network:
    driver: bridge
    internal: true
  milvus:
    driver: bridge
  opensearch-net:
    driver: bridge
    internal: true

volumes:
  oradata:
  dify_es01_data:

其实一个一个分析,它的结构和我们之前部署的docker项目是类似的,只不过一次性起了很多个容器。

我们这边可以先不管它,直接暴力拉起

docker compose up -d

我这边在公司,本来以为很快能拉好镜像,结果网非常的慢,我等不及就去吃中饭了,等到吃饭回来发现已经拉好了。

img

在这期间,如果决定要本地使用,不调用云端API的话,我们可以先把Ollama和本地的模型先下载起来。

安装Ollama(可选)

img

其实这个也可以用docker来装,但是既然给了安装版,我们就直接到官网下载即可。

什么是Ollama?

62dc7ef085dd48a06b4bcce9782a12c5.png

Ollama 是一个便于本地部署和运行大型语言模型(Large Language Models, LLMs)的工具。使用通俗的语言来说,如果你想在自己的电脑上运行如 GPT这样的大型人工智能模型,而不是通过互联网连接到它们,那么 Ollama 是一个实现这一目标的工具。

Ollama支持非常多的开源模型,比如:

img

更多支持的模型可以看这边:https://ollama.com/library

当然它还支持自定义模型,这边就不深入了,有兴趣的可以研究:https://github.com/ollama/ollama

装好之后,命令行运行:

ollama -v

查看到版本号说明安装好了。

接下来,比如我们下载一个llama3 8B的模型:

ollama run llama3

这边可能需要比较长的时间,取决于你的网速。

下载好了就可以进行交互了:

b8179cebba4cd58465fd233020035fc9.png

/? 可以查看帮助:

576b3e8c12d6561d8c9059e8b8504d14.png

7a9e6a8e285b4562c6a39c83a0c468b5.png

/bye 可以退出

f6b660f17b96db1219cff57b888ec428.png

其实现在已经搞定了,你可以让它帮你干活了,但是每次都要用命令行,有些人觉得不方便,而且也不能给别人用,下面我们就给它搞一个图形化界面,扩展一下功能,也能让局域网里的其他小伙伴也用上你的这个模型(注意多人同时访问会导致机器负载飙升,具体取决于你机器的性能和模型参数的大小)

配置Dify

等所有容器都拉取好了,我们就可以通过在浏览器地址栏输入:127.0.0.1来访问Dify了。

第一次登录会让你注册一个管理员账号,然后我们就可以登录了,

img

后台是这个样子的,

img

我们先来到设置,配置一下大模型,

f0ba80de97e161c2021d2cebc76c1306.png

这边可以看到很多的模型供应商,

img

我们本地部署,就用ollama,

img

点击安装,

img

安装好了之后,来添加模型,

img

这里的基础URL,填写:http://host.docker.internal:11434

img

模型名称的话,看看我们ollama里下载了什么模型,打开终端,输入

ollama list

可以看到我这边下载了很多模型,

img

我们就选择gpt最近刚开源的gpt-oss:20b

其他信息填写如图,

632a2fed26d697929b7faa2867d9895b.png

这边是支持函数调用的,选择是,不支持视觉,

81e6c15393c9cfc5032318734b6b51e4.png

这样我们就添加好一个模型啦。

img

如果你的本地电脑算力不够,也可以选择使用云端的模型,比如DeepSeek之类的,

添加方法也很简单,下载模型供应商,然后在这边点击配置,

img

填入你在DeepSeek官网拿到的API Key就行了。

OpenAI、ANTHROPIC也是类似的方法,填API Key就可以。

接着,我们就来创建一个空白应用,

img

这边选择最简单的,创建一个聊天助手,

img

创建的过程中,你可以调试,这边的自定义程度会高一些,

img

创建好之后,可以选择发布,或者点击探索,

img

就可以在这边调出使用了。

当然,这只是最简单的功能,dify的魅力在于降低AI应用开发的门槛,快速构建和部署生产级的生成式AI应用

它通过以下核心功能来实现这个目标:

  1. 简化开发流程:Dify是一个开源的大语言模型(LLM)应用开发平台,融合了后端即服务(BaaS)和LLMOps理念,提供可视化的Prompt编排、数据集管理、RAG(检索增强生成)引擎、Agent框架等功能,使开发者无需深入底层技术也能快速搭建AI应用。
  2. 支持低代码/无代码开发:通过直观的界面和拖拽操作,非技术人员也能参与AI应用的定义和数据运营,极大地降低了开发门槛。
  3. 灵活的模型支持:Dify支持多种主流大语言模型(如GPT、Claude、DeepSeek等)以及开源模型,开发者可根据需求灵活选择和切换模型。
  4. 高效的RAG和Agent功能:Dify的RAG技术通过结合外部知识库提升生成内容的准确性,而Agent框架赋予AI自主推理和任务执行能力,适用于复杂场景如智能客服、内容生成等。189.html)
  5. 企业级应用支持:Dify提供私有化部署、API集成、多租户隔离等功能,适合企业构建内部AI网关或快速将AI能力融入现有业务,助力AI转型。

总结来说,Dify通过提供一站式、易用的开发平台,帮助开发者、企业甚至非技术人员快速实现AI应用创意,节省开发时间,专注于创新和业务需求,特别适合从原型设计到生产部署的全流程管理。

大家可以自行探索一下Dify的高级玩法,我自己也在慢慢摸索学习,之后有机会可以和大家分享!

支持MCP,轻量又全面的记账软件——ezBookkeeping|好玩儿的Docker项目

2025-08-12 20:36:51

前阵子去欧洲玩了一段时间,鸽了挺久了,今天有点时间,立马来和大家分享好玩儿的Docker项目。

1. 介绍

ezBookkeeping 是一款轻量级的个人理财应用,你可以自己架设(自托管)。它界面简洁,用起来很顺手,记账功能也强大。

这款应用的设计核心就是简单便携。它部署起来毫不费力,上手快,而且对系统资源的占用极小。无论是微型服务器、NAS 设备,还是树莓派,都能轻松运行。

ezBookkeeping 支持全平台,对各种设备都很友好。在手机、平板和电脑上用,体验都一样流畅。它还支持 PWA(渐进式网页应用),你可以直接把它添加到手机主屏幕,像本地应用一样方便地使用。

1.1 功能特点

开源与自托管

  • 为你提供隐私和数据控制权

轻量又快速

  • 性能卓越,即使在低配置环境下也能流畅运行

安装简单

  • 支持 Docker 部署
  • 兼容 SQLite, MySQL, PostgreSQL 数据库
  • 跨平台运行(支持 Windows, macOS, Linux)
  • 支持多种处理器架构 (x86, amd64, ARM)

界面友好

  • 界面已针对移动和桌面设备优化
  • 支持 PWA,在手机上可获得类似原生应用的体验
  • 提供深色模式

AI 赋能

  • 支持 MCP (Model Context Protocol),可集成 AI 功能

强大的记账功能

  • 支持两级账户和分类
  • 可为交易添加图片附件
  • 具备地图位置追踪功能
  • 支持周期性(重复)交易
  • 提供高级筛选、搜索、数据可视化和分析功能

本地化与全球化

  • 支持多种语言和货币
  • 自动更新汇率
  • 支持多时区显示
  • 可自定义日期、数字和货币格式

安全保障

  • 支持双重身份验证 (2FA)
  • 登录频率限制
  • 应用锁定功能(支持 PIN 码 / WebAuthn)

数据导入/导出

  • 支持多种格式,包括 CSV, OFX, QFX, QIF, IIF, Camt.053, MT940, GnuCash, Firefly III, Beancount 等等

简单来说,这是一个记账的项目,然后它还可以支持MCP,可以搭配大语言模型一起食用。

fa0b25dbc1ebb8c3e364c5de96542aff.png

6cd6cae5e006175532d59840d5683924.png

2. 相关地址

官方GitHub地址:https://github.com/mayswind/ezbookkeeping (目前958个star,欢迎大家去给作者点星星!)

官方Demo:https://ezbookkeeping-demo.mayswind.net

3. 搭建环境

4. 搭建视频(有时间补充!)

4.1 YouTube

视频地址:

4.2 哔哩哔哩

哔哩哔哩:

5. 搭建方式

5.1 安装 Docker 与 Nginx Proxy Manager

可以直接参考这篇内容:

https://blog.laoda.de/archives/nginxproxymanager/

5.2 创建安装目录

创建一下安装的目录:

sudo -i

mkdir -p /root/data/docker_data/ezbookkeeping

cd ezbookkeeping

我们来简单修改一下作者提供的docker-compose.yml文件

vim docker-compose.yml

咕咕修改之后的:

services:
  ezbookkeeping:
    image: mayswind/ezbookkeeping
    container_name: ezbookkeeping
    restart: unless-stopped
    ports:
      - 8082:8080
    volumes:
      - /etc/localtime:/etc/localtime:ro
      - ./storage:/ezbookkeeping/storage
      - ./log:/ezbookkeeping/log
    #  - ./ezbookkeeping.ini:/ezbookkeeping/conf/ezbookkeeping.ini
    environment:
      - EBK_DATABASE_TYPE=mysql
      - EBK_DATABASE_HOST=mysql:3306
      - EBK_DATABASE_NAME=ezbookkeeping
      - EBK_DATABASE_USER=ezbookkeeping
      - EBK_DATABASE_PASSWD=ezbookkeeping
      - EBK_LOG_MODE=file
      - EBK_SECURITY_SECRET_KEY=its_should_be_a_random_string
      - EBK_MCP_ENABLE_MCP=true
    # depends_on:
    #  mysql:
    #    condition: service_healthy

  mysql:  
    image: mysql:8.0 
    container_name: ezbookkeeping-mysql
    restart: unless-stopped
    volumes:  
        - ./data:/var/lib/mysql
    environment:  
        - MYSQL_DATABASE=ezbookkeeping  
        - MYSQL_USER=ezbookkeeping  
        - MYSQL_PASSWORD=ezbookkeeping  
        - MYSQL_ROOT_PASSWORD=ezbookkeeping
    healthcheck:  
        test: ["CMD", "mysqladmin", "ping", "-p ezbookkeeping"]  
        retries: 3  
        timeout: 5s

修改完成之后,可以在英文输入法下,按 i 修改,完成之后,按一下 esc,然后 :wq 保存退出。

接着创建文件夹,赋予文件权限:

cd /root/data/docker_data/ezbookkeeping
mkdir ./{data,log,storage}
chmod a+rw {log,storage}

5.3 打开服务器防火墙(非必需)并访问网页

打开防火墙的端口 8082

举例,腾讯云打开方法如下(部分服务商没有自带的面板防火墙,就不用这步操作了):

image-20220630215240864image-20220630220546335

类似图中的,这边我们填 8082,示例填 ezbookkeeping ,确定即可(如果你在 docker-compose 文件里换了 9009,这边就需要填 9009,以此类推)

56a42aff23098af08c1ae587e19739ae.png

查看端口是否被占用(以 8082 为例),输入:

lsof -i:8082  #查看 8082 端口是否被占用,如果被占用,重新自定义一个端口

如果啥也没出现,表示端口未被占用,我们可以继续下面的操作了~

如果出现:

-bash: lsof: command not found

运行:

apt install lsof  #安装 lsof

如果端口没有被占用(被占用了就修改一下端口,比如改成 8381,注意 docker 命令行里和防火墙都要改)

5.4 启动 ezbookkeeping

cd /root/data/docker_data/ezbookkeeping

docker compose up -d   # 注意,老版本用户用 docker-compose up -d

等待拉取好镜像,出现 done的字样之后,

理论上我们就可以输入 http://ip:8082 访问了。

但是这边我们推荐先搞一下反向代理!

做反向代理前,你需要一个域名!

namesilo 上面 xyz 后缀的域名一年就 7 块钱,可以年抛。(冷知识,namesilo上 6位数字的xyz续费永远都是0.99美元 = =)

如果想要长期使用,还是建议买 com 后缀的域名,更加正规一些,可以输入 laodade 来获得 1 美元的优惠(不知道现在还有没有)

namesilo 自带隐私保护,咕咕一直在用这家,价格也是这些注册商里面比较低的,关键是他家不像其他家域名注册商,没有七七八八的套路!(就是后台界面有些 古老 = =)

【域名购买】Namesilo 优惠码和域名解析教程(附带服务器购买推荐和注意事项)

我们接着往下看!

6. 反向代理

6.1 利用 Nginx Proxy Manager

在添加反向代理之前,确保你已经完成了域名解析,不会的可以看这个:域名一枚,并做好解析到服务器上域名购买、域名解析 视频教程

4b00cb7fe121c71233685dcc787fdf32.png

之后,登陆 Nginx Proxy Manager(不会的看这个:安装 Nginx Proxy Manager相关教程))

注意:

Nginx Proxy Manager(以下简称 NPM)会用到 80443 端口,所以本机不能占用(比如原来就有 Nginx)

直接丢几张图:

9a07c1b059cf95aae62081a18f2ad5d8.pngc1fa9d7b7a32927f020093975c6fd8ea.png396509498ad5fd92b67f6a782cade133.pnge5362e20c7d6d271d1e8103b0511ac04.png

注意填写对应的 域名IP端口,按文章来的话,应该是 8082

IP 填写:

如果 Nginx Proxy Manager 和 ezbookkeeping 在同一台服务器上,可以在终端输入:

ip addr show docker0

查看对应的 Docker 容器内部 IP。

否则直接填 ezbookkeeping 所在的服务器 IP 就行。

6.2 利用宝塔面板

发现还是有不少小伙伴习惯用宝塔面板,这边也贴一个宝塔面板的反代配置:

直接新建一个站点,不要数据库,不要 php,纯静态即可。

然后打开下面的配置,修改 Nginx 的配置。

image-20220819150345725image-20220819150542867

代码如下:

location / {
      proxy_pass http://127.0.0.1:8082/;       # 注意改成你实际使用的端口
      rewrite ^/(.*)$ /$1 break;
      proxy_redirect off;
      proxy_set_header Host $host;
      proxy_set_header X-Forwarded-Proto $scheme;
      proxy_set_header X-Real-IP $remote_addr;
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header Upgrade-Insecure-Requests 1;
      proxy_set_header X-Forwarded-Proto https;
    }

此方法对 90% 的反向代理都能生效,然后就可以用域名来安装访问了。

有同学可能会问,为什么不直接用宝塔自带的反向代理功能。

image-20220819150730128

也可以,不过咕咕自己之前遇到过当有多个网站需要反代的时候,在这边设置会报错的情况 = =

所以后来就不用了,直接用上面的方法来操作了。

7. 使用教程

登录你的域名之后,可以看到首页:

7a03c1ab0e2dd10aa34612cba853e3ed.png

这个时候需要创建一个新账号:

826b774725884ccd0ba5d7bb5758c241.png

39679f5841b71f65fb9f2133518e24c5.png

这里的预设分类,可以选择打开:

5f1aacee44cf4f3e03d077634743e047.png

进入后台,结构很清晰:

694dcf2d58bfaadaa204d13269549e9d.png

我们先来添加一下账户:

3cefdb5bf5493e24f16be3df8c491cfe.png

比如,取名就叫做“咕咕的账本”:

b9869d80991a30d1f4e46bf18999a778.png

先来手动添加一笔试试看:

f3b17b3c3f41f5eb0e4f5521bbf1d214.png

可以正常添加:

e9f717d2e4a0fd9ef38bb95eb89a79bb.png

MCP配置

一开始我们就说了,这个账本支持MCP。

MCP(模型上下文协议)是由 Anthropic 开发的一种开放协议,它能让 AI 模型安全地连接到外部数据源和和工具。

简单来说,MCP 就像一座桥梁,它提供了一种通用的标准,让 AI 工具能安全地获取信息和执行操作,同时确保数据安全和用户可以掌控一切。

有了 MCP 协议,你就可以用自己喜欢的 AI 工具来:

  • 添加交易记录:比如,直接用自然语言(就是日常说话的方式)来创建交易,或者从不同的文件格式中批量导入交易记录。
  • 查询交易数据:比如,让你的 AI 工具帮你分析历史交易记录。
  • 以及做更多的事情

更多MCP相关介绍可以看这边:https://ezbookkeeping.mayswind.net/mcp

这边我们来看看怎么配置。

首先找到右上角的用户设置,

e66ee48541f398f0c84c40b839e68388.png

生成MCP令牌:

有两种形式,分别是普通的令牌和json配置:

7bcc4a9580e9e7d3c1fa1a74d0401b90.png

ab7a8343aff185cf6ab7475b925f0ea4.png

普通:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyVG9rZW5JZCI6IjMzOTQ1NTM3NTIyOTE5OTc4MzYiLCJqdGkiOiIzNzY4ODA2Njg4MjQ1NjbWUiOiJSb3kiLCJ0eXBlIjo1LCJpYXQiOjE3NTQ5ODc3NzcsImV4cCI6MTA5NzgzNTk4MTR9.7JL_4kzKhihatpfQxIkhD6Z_ibZ_vBYtcQ_D9UCV--0

JSON配置:

c5dfb5b8dfc24e1ca0e2303fece2cde2.png
{
    "mcpServers": {
        "ezbookkeeping-mcp": {
            "type": "streamable-http",
            "url": "http://localhost:8080/mcp",
            "headers": {
                "Authorization": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyVG9rZW5JZCI6IjMzOTQ1NTM3NTIyOTE5OTc4MzYiLCJqdGkiOiIzNzY4ODA2Njg4hbWUiOiJSb3kiLCJ0eXBlIjo1LCJpYXQiOjE3NTQ5ODc3NzcsImV4cCI6MTA5NzgzNTk4MTR9.7JL_4kzKhihatpfQxIkhD6Z_ibZ_vBYtcQ_D9UCV--0"
            }
        }
    }
}

这边可以保存下来,下次打开就看不到了。

29a8936f32b3247acb4510626a85c87b.png

Cherry Studio配置

这边以Cherry Studio为例,看看MCP怎么配置。

706dbf1ee98c6368863418e1a638da1c.png

配置情况如图:

57f3580946e4072cba358958444ff08f.png

  • 名称:主要用于识别,例如:ezBookkeeping
  • 类型:选择 streamableHttp 协议
  • URL:为 你的域名/mcp
  • 请求头: 为 Authorization=Bearer {token}

接着可以查看一下可以调用的工具:

c24978aa0964d06246f059399f92ee88.png

然后为了确保大模型能正确理解什么是今天,还需要加个时间MCP,这次我们选择json导入,

{
    "mcpServers": {
        "mcp-server-time": {
            "command": "uvx",
            "args": ["mcp-server-time"]
        }
    }
}

3a3ab3900b6dba588cbcdf54b8f47245.png

ca6653fe3ec6dfe069da60592b40b369.png

这下,你应该有两个MCP服务了。

8b12dc8711e6936375bb1d880271102a.png

查看一下时间工具的功能:

369abc91ad148e042f9e796c8580312e.png

接着,我们到Cherry Studio里新建一个助手,

399ab6071f945797e0fb61349d00cd16.png

选择启用这两个MCP服务:

4775185163eb58be74204ea756d6b915.png

测试一下,可以看到回答的时候,调用了MCP服务,

b65c160f578c98b0f083b0add6a749bb.png

这边提示错误,我没有说记录到哪个账本:

4f1fc419fafb5fc9f55764aca9b20b5d.png

900832a98c968a38f541aff971a5b140.png

还需要说明交易类别,

6cc43ba6b7f0df94f756c836bc1b5de4.png

后续,

fca2836dc485e298003061c20dd71ec3.png

记录成功!

756e050ca91dfb4f2a1f5b3020baa75c.png

不过这次似乎没有调用时间MCP,时间似乎有问题……

然后我尝试使用Deepseek,直接不调用MCP服务了,很奇怪。

8c18d8491e297ce50cc941024a31a3c2.png

后续一直没调用MCP服务,暂时还没解决,我的是Mac,有解决的小伙伴可以评论区分享一下。

7.1 更新 ezbookkeeping

cd /root/data/docker_data/ezbookkeeping

docker compose pull

docker compose up -d    # 请不要使用 docker compose stop 来停止容器,因为这么做需要额外的时间等待容器停止;docker compose up -d 直接升级容器时会自动停止并立刻重建新的容器,完全没有必要浪费那些时间。

docker image prune  # prune 命令用来删除不再使用的 docker 对象。删除所有未被 tag 标记和未被容器使用的镜像

提示:

WARNING! This will remove all dangling images.
Are you sure you want to continue? [y/N]

输入 y

利用 Docker 搭建的应用,更新非常容易~

7.2 卸载 ezbookkeeping

同样进入安装页面,先停止所有容器。

cd /root/data/docker_data/ezbookkeeping

docker compose down

cd ..

rm -rf /root/data/docker_data/ezbookkeeping  # 完全删除

可以卸载得很干净。

8. 常见问题及注意点

还是MCP调用的问题,不是非常稳定,暂时不确定是不是Cherry Studio的问题。

9. 结尾

祝大家用得开心,有问题可以去 GitHub 提 Issues,也可以在评论区互相交流探讨。

同时,项目处于初期,有能力给项目做贡献的同学,也欢迎积极加入到 [项目]https://github.com/mayswind/ezbookkeeping) 中来,贡献自己的一份力量!

最后,感谢开发人员们的辛苦付出,让我们能用到这么优秀的项目!也希望开源项目越来越好!

10. 参考资料

官方GitHub:https://github.com/mayswind/ezbookkeeping