十分钟搭建一个 AI 驱动的图表生成器——Next-AI-Draw.io|好玩儿的 Docker 项目

1. 唠嗑 好久没更新了,这周来和大家分享一个 AI 驱动的图表生成器——Next-AI-Draw.io 2. Next-AI-Draw.io 简介 Next-AI-Draw.io 是一个集成了 AI 功能的 Next.js 网页应用,与 draw.io 图表无缝结合。通过自然语言命令和 AI 辅助可视化来创建、修改和增强图表。 功能特性 LLM 驱动的图表创建:利用大语言模型通过自然语言命令直接创建和操作 draw.io 图表 基于图像的图表复制:上传现有图表或图像,让 AI 自动复制和增强 PDF 和文本文件上传:上传 PDF 文档和文本文件,提取内容并从现有文档生成图表 AI 推理过程显示:查看支持模型的 AI 思考过程(OpenAI o1/o3、Gemini、Claude 等) 图表历史记录:全面的版本控制,跟踪所有更改,允许您查看和恢复 AI 编辑前的图表版本 交互式聊天界面:与 AI 实时对话来完善您的图表 云架构图支持:专门支持生成云架构图(AWS、GCP、Azure) 动画连接器:在图表元素之间创建动态动画连接器,实现更好的可视化效果 3. 相关地址 官方 GitHub 地址:https://github.com/DayuanJiang/next-ai-draw-io (目前 13k 个 star,欢迎大家去给项目点星星!) Demo 地址:https://next-ai-drawio.jiang.jp/ 当然如果你体验完还想自己用 docker 搭建一个,那我们就继续往下! 4. 搭建环境 服务器:咕咕这边用的香港的 莱卡云服务器,建议服务器内存 1G 以上,当然你也可以选择其他 高性价比的服务器。 系统:Debian 11 (DD 脚本 非必需 DD,用原来的系统也 OK,之后教程都是用 Debian 或者 Ubuntu 搭建~) 安装好 Docker、Docker-compose(相关脚本) 【必需】域名一枚,并做好解析到服务器上(域名购买、域名解析 视频教程) 【非必需】提前安装好宝塔面板海外版本 aapanel,并安装好 Nginx(安装地址) 【非必需本教程选用】安装好 Nginx Proxy Manager(相关教程) 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/drawioai cd /root/data/docker_data/drawioai 接着我们来编辑下docker-compose.yml vim docker-compose.yml name: nextaidrawio services: next-ai-draw-io: ports: - 3001:3000 env_file: - .env image: ghcr.io/dayuanjiang/next-ai-draw-io:latest 其中的左边的3001可以改成服务器上没有用过的端口。 修改完成之后,可以在英文输入法下,按 i 修改,完成之后,按一下 esc,然后 :wq 保存退出。 接着我们来编辑下.env cd /root/data/docker_data/drawioai vim .env 粘贴如下内容: # AI Provider Configuration # AI_PROVIDER: Which provider to use # Options: bedrock, openai, anthropic, google, azure, ollama, openrouter, deepseek, siliconflow, gateway # Default: bedrock AI_PROVIDER=bedrock # AI_MODEL: The model ID for your chosen provider (REQUIRED) AI_MODEL=global.anthropic.claude-sonnet-4-5-20250929-v1:0 # AWS Bedrock Configuration # AWS_REGION=us-east-1 # AWS_ACCESS_KEY_ID=your-access-key-id # AWS_SECRET_ACCESS_KEY=your-secret-access-key # Note: Claude and Nova models support reasoning/extended thinking # BEDROCK_REASONING_BUDGET_TOKENS=12000 # Optional: Claude reasoning budget in tokens (1024-64000) # BEDROCK_REASONING_EFFORT=medium # Optional: Nova reasoning effort (low/medium/high) # OpenAI Configuration # OPENAI_API_KEY=sk-... # OPENAI_BASE_URL=https://api.openai.com/v1 # Optional: Custom OpenAI-compatible endpoint # OPENAI_ORGANIZATION=org-... # Optional # OPENAI_PROJECT=proj_... # Optional # Note: o1/o3/gpt-5 models automatically enable reasoning summary (default: detailed) # OPENAI_REASONING_EFFORT=low # Optional: Reasoning effort (minimal/low/medium/high) - for o1/o3/gpt-5 # OPENAI_REASONING_SUMMARY=detailed # Optional: Override reasoning summary (none/brief/detailed) # Anthropic (Direct) Configuration # ANTHROPIC_API_KEY=sk-ant-... # ANTHROPIC_BASE_URL=https://your-custom-anthropic/v1 # ANTHROPIC_THINKING_TYPE=enabled # Optional: Anthropic extended thinking (enabled) # ANTHROPIC_THINKING_BUDGET_TOKENS=12000 # Optional: Budget for extended thinking in tokens # Google Generative AI Configuration # GOOGLE_GENERATIVE_AI_API_KEY=... # GOOGLE_BASE_URL=https://generativelanguage.googleapis.com/v1beta # Optional: Custom endpoint # GOOGLE_CANDIDATE_COUNT=1 # Optional: Number of candidates to generate # GOOGLE_TOP_K=40 # Optional: Top K sampling parameter # GOOGLE_TOP_P=0.95 # Optional: Nucleus sampling parameter # Note: Gemini 2.5/3 models automatically enable reasoning display (includeThoughts: true) # GOOGLE_THINKING_BUDGET=8192 # Optional: Gemini 2.5 thinking budget in tokens (for more/less thinking) # GOOGLE_THINKING_LEVEL=high # Optional: Gemini 3 thinking level (low/high) # Azure OpenAI Configuration # Configure endpoint using ONE of these methods: # 1. AZURE_RESOURCE_NAME - SDK constructs: https://{name}.openai.azure.com/openai/v1{path} # 2. AZURE_BASE_URL - SDK appends /v1{path} to your URL # If both are set, AZURE_BASE_URL takes precedence. # AZURE_RESOURCE_NAME=your-resource-name # AZURE_API_KEY=... # AZURE_BASE_URL=https://your-resource.openai.azure.com/openai # Alternative: Custom endpoint # AZURE_REASONING_EFFORT=low # Optional: Azure reasoning effort (low, medium, high) # AZURE_REASONING_SUMMARY=detailed # Ollama (Local) Configuration # OLLAMA_BASE_URL=http://localhost:11434/api # Optional, defaults to localhost # OLLAMA_ENABLE_THINKING=true # Optional: Enable thinking for models that support it (e.g., qwen3) # OpenRouter Configuration # OPENROUTER_API_KEY=sk-or-v1-... # OPENROUTER_BASE_URL=https://openrouter.ai/api/v1 # Optional: Custom endpoint # DeepSeek Configuration # DEEPSEEK_API_KEY=sk-... # DEEPSEEK_BASE_URL=https://api.deepseek.com/v1 # Optional: Custom endpoint # SiliconFlow Configuration (OpenAI-compatible) # Base domain can be .com or .cn, defaults to https://api.siliconflow.com/v1 # SILICONFLOW_API_KEY=sk-... # SILICONFLOW_BASE_URL=https://api.siliconflow.com/v1 # Optional: switch to https://api.siliconflow.cn/v1 if needed # Vercel AI Gateway Configuration # Get your API key from: https://vercel.com/ai-gateway # Model format: "provider/model" e.g., "openai/gpt-4o", "anthropic/claude-sonnet-4-5" # AI_GATEWAY_API_KEY=... # Langfuse Observability (Optional) # Enable LLM tracing and analytics - https://langfuse.com # LANGFUSE_PUBLIC_KEY=pk-lf-... # LANGFUSE_SECRET_KEY=sk-lf-... # LANGFUSE_BASEURL=https://cloud.langfuse.com # EU region, use https://us.cloud.langfuse.com for US # Temperature (Optional) # Controls randomness in AI responses. Lower = more deterministic. # Leave unset for models that don't support temperature (e.g., GPT-5.1 reasoning models) # TEMPERATURE=0 # Access Control (Optional) # ACCESS_CODE_LIST=your-secret-code,another-code # Draw.io Configuration (Optional) # NEXT_PUBLIC_DRAWIO_BASE_URL=https://embed.diagrams.net # Default: https://embed.diagrams.net # Use this to point to a self-hosted draw.io instance # PDF Input Feature (Optional) # Enable PDF file upload to extract text and generate diagrams # Enabled by default. Set to "false" to disable. # ENABLE_PDF_INPUT=true # NEXT_PUBLIC_MAX_EXTRACTED_CHARS=150000 # Max characters for PDF/text extraction (default: 150000) 这里头有很多选项可以开启,当然你也可以不管它,到网页端输入,这样的话就保存在本地浏览器里了,如果在这边输入,所有知道这个网址的人都能用你的 AI 模型。 假设我们用的 OPEN AI 的,其实.env里面只要这仨: AI_PROVIDER=openai AI_MODEL=gpt-4o OPENAI_API_KEY=your_api_key your_api_key改成你的 API 密钥。 修改完成之后,可以在英文输入法下,按 i 修改,完成之后,按一下 esc,然后 :wq 保存退出。 6.3 查看端口是否被占用 查看端口是否被占用(以 3001 为例),输入: lsof -i:3001 #查看 3001 端口是否被占用,如果被占用,重新自定义一个端口 如果啥也没出现,表示端口未被占用,我们可以继续下面的操作了~ 如果出现: -bash: lsof: command not found 运行: apt install lsof #安装 lsof 如果端口没有被占用(被占用了就修改一下端口,比如改成 8381,注意 docker 命令行里和防火墙都要改) 6.4 启动 drawioai cd /root/data/docker_data/drawioai docker compose up -d # 注意,老版本用户用 docker-compose up -d 耐心等待拉取好镜像,出现 done的字样之后, 理论上我们就可以输入 http://ip:3001 访问了。 但是我们部署在公网一定要考虑使用反向代理工具配置 SSL! 做反向代理前,你需要一个域名! namesilo 上面 xyz 后缀的域名一年就 7 块钱,可以年抛。(冷知识,namesilo 上 6 位数字的 xyz 续费永远都是 0.99 美元 = =) 如果想要长期使用,还是建议买 com 后缀的域名,更加正规一些,可以输入 laodade 来获得 1 美元的优惠(不知道现在还有没有) namesilo 自带隐私保护,咕咕一直在用这家,价格也是这些注册商里面比较低的,关键是他家不像其他家域名注册商,没有七七八八的套路!(就是后台界面有些 丑 古老 = =) 【域名购买】Namesilo 优惠码和域名解析教程(附带服务器购买推荐和注意事项) 我们接着往下看! 7. 反向代理 7.1 利用 Nginx Proxy Manager 在添加反向代理之前,确保你已经完成了域名解析,不会的可以看这个:域名一枚,并做好解析到服务器上(域名购买、域名解析 视频教程) (名称改成你自己想要的域名前缀即可) 之后,登陆 Nginx Proxy Manager(不会的看这个:安装 Nginx Proxy Manager(相关教程)) 注意: Nginx Proxy Manager(以下简称 NPM)会用到 80、443 端口,所以本机不能占用(比如原来就有 Nginx) 直接丢几张图: 注意填写对应的 域名、IP 和 端口,按文章来的话,应该是 3001 IP 填写: 如果 Nginx Proxy Manager 和 drawioai 在同一台服务器上,可以在终端输入: ip addr show docker0 查看对应的 Docker 容器内部 IP。 否则直接填 drawioai 所在的服务器 IP 就行。 然后访问域名就可以访问了! 7.2 利用宝塔面板 发现还是有不少小伙伴习惯用宝塔面板,这边也贴一个宝塔面板的反代配置: 直接新建一个站点,不要数据库,不要 php,纯静态即可。 然后打开下面的配置,修改 Nginx 的配置。 代码如下: location / { proxy_pass http://127.0.0.1:3001/; # 注意改成你实际使用的端口 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% 的反向代理都能生效,然后就可以用域名来安装访问了。 有同学可能会问,为什么不直接用宝塔自带的反向代理功能。 也可以,不过咕咕自己之前遇到过当有多个网站需要反代的时候,在这边设置会报错的情况 = = 所以后来就不用了,直接用上面的方法来操作了。 8. 使用教程 非常简单,所见即所得。 登录页, 语言设置,改成中文, 简单展示 右边可以输入提示词,比如让它画一只猫猫, 画的熊猫不太像…… 当然你也可以隐藏掉这个提示词输入框,把它当成一个普通的画图软件来用, 如果用默认的,其实是用的项目作者的 API,速率可能会有限制,当然用自己的 API 就没有这个问题了,如果手上富裕,也可以考虑捐赠作者,支持开源项目长久发展。 8.1 更新 drawioai 这个项目后续会持续有更新,所以提供一个更新的方式。 cd /root/data/docker_data/drawioai 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 卸载 drawioai 同样进入安装页面,先停止所有容器。 cd /root/data/docker_data/drawioai docker compose down cd .. rm -rf /root/data/docker_data/drawioai # 完全删除 可以卸载得很干净。 9. 使用问题 那个保存按钮点了似乎没有任何反馈…… 不过画的图导出是没问题的。 大家使用上有什么心得或者问题,欢迎评论区交流~ 10. 结尾 祝大家用得开心,有问题可以去 GitHub 提 Issues,也可以在评论区互相交流探讨。 同时,有能力给项目做贡献的同学,也欢迎积极加入到 项目 中来,贡献自己的一份力量! 最后,感谢作者 @DayuanJiang 的辛苦付出,让我们能用到这么优秀的项目!欢迎大家都去给这个项目点个 star。 参考资料 官方 GitHub:https://github.com/DayuanJiang/next-ai-draw-io

2025/12/18
articleCard.readMore

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

1. 唠嗑 好久没更新了,这周来和大家分享一个好用的书签工具——Karakeep 2. karakeep 简介 Karakeep(前身为 Hoarder)是一款可自托管的「万物皆可存」书签应用,专为数据囤积爱好者打造,融入一丝 AI 魔法。 功能 🔗 书签链接、记录简单笔记,并存储图片和 PDF 文件。 ⬇️ 自动抓取链接标题、描述和预览图。 📋 将书签整理到不同列表中。 🔎 全文本搜索所有存储内容。 ✨ 基于 AI(类似 ChatGPT)自动打标签和生成摘要。支持使用 Ollama 运行本地模型! 🤖 规则引擎,实现自定义管理。 🎆 图像 OCR,提取图片中的文字。 🔖 Chrome 插件和 Firefox 扩展,快速添加书签。 📱 iOS 应用和 Android 应用。 📰 从 RSS 订阅源自动归档内容。 🔌 REST API 和多种客户端。 🌐 多语言支持。 🖍️ 标记并保存归档内容中的高亮片段。 🗄️ 完整页面归档(使用 monolith),防止链接失效。 ▶️ 使用 yt-dlp 自动归档视频。 ☑️ 支持批量操作。 🔐 支持 SSO 单点登录。 🌙 深色模式。 💾 优先支持自托管。 ⬇️ 从 Chrome、Pocket、Linkwarden、Omnivore、Tab Session Manager 导入书签。 🔄 通过 floccus 与浏览器书签自动同步。 [计划中] 移动端离线阅读、书签语义搜索,…… 3. 相关地址 官方 GitHub 地址:https://github.com/karakeep-app/karakeep (目前 21.1k 个 star,欢迎大家去给项目点星星!) Demo 地址:https://try.karakeep.app 默认账号密码: Email: demo@karakeep.app Password: demodemo 当然如果你体验完还想自己用 docker 搭建一个,那我们就继续往下! 4. 搭建环境 服务器:咕咕这边用的香港的 莱卡云服务器,建议服务器内存 1G 以上,当然你也可以选择其他 高性价比的服务器。 系统:Debian 11 (DD 脚本 非必需 DD,用原来的系统也 OK,之后教程都是用 Debian 或者 Ubuntu 搭建~) 安装好 Docker、Docker-compose(相关脚本) 【必需】域名一枚,并做好解析到服务器上(域名购买、域名解析 视频教程) 【非必需】提前安装好宝塔面板海外版本 aapanel,并安装好 Nginx(安装地址) 【非必需本教程选用】安装好 Nginx Proxy Manager(相关教程) 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_string和another_random_string需要我们自己生成。 我们可以先在命令行里面输入 openssl rand -base64 36 生成随机的字符,然后替代它们。 我需要放在.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 在添加反向代理之前,确保你已经完成了域名解析,不会的可以看这个:域名一枚,并做好解析到服务器上(域名购买、域名解析 视频教程) (名称改成你自己想要的域名前缀即可) 之后,登陆 Nginx Proxy Manager(不会的看这个:安装 Nginx Proxy Manager(相关教程)) 注意: Nginx Proxy Manager(以下简称 NPM)会用到 80、443 端口,所以本机不能占用(比如原来就有 Nginx) 直接丢几张图: 注意填写对应的 域名、IP 和 端口,按文章来的话,应该是 3030 IP 填写: 如果 Nginx Proxy Manager 和 karakeep 在同一台服务器上,可以在终端输入: ip addr show docker0 查看对应的 Docker 容器内部 IP。 否则直接填 karakeep 所在的服务器 IP 就行。 然后访问域名就可以访问了! 7.2 利用宝塔面板 发现还是有不少小伙伴习惯用宝塔面板,这边也贴一个宝塔面板的反代配置: 直接新建一个站点,不要数据库,不要 php,纯静态即可。 然后打开下面的配置,修改 Nginx 的配置。 代码如下: 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% 的反向代理都能生效,然后就可以用域名来安装访问了。 有同学可能会问,为什么不直接用宝塔自带的反向代理功能。 也可以,不过咕咕自己之前遇到过当有多个网站需要反代的时候,在这边设置会报错的情况 = = 所以后来就不用了,直接用上面的方法来操作了。 8. 使用教程 非常简单,所见即所得。 登录, 首先注册一个账号, 后台页面, 用户设置, 如果觉得英文不习惯,也可以改成中文, 输入一个网址,测试一下, 支持给你存下来的网页打标签, 服务器统计情况, Karakeep是支持浏览器插件的,这边可以直接下载浏览器插件,方便浏览网页的时候使用, 输入你搭建好的域名,然后登录即可, 使用 也支持下载完整页面, 还有一些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

2025/11/13
articleCard.readMore

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

1. 唠嗑 好久没更新了,这周来和大家分享一个阅后即焚工具,安全高效的一次性私密信息共享平台——OTS(One-Time-Secret) 2. OTS 简介 OTS 是一个一次性私密信息分享平台。私密信息在发送到服务器之前,会在浏览器中使用对称的 256 位 AES 加密进行加密。之后会生成一个包含私密信息的 ID 和密码的 URL。密码永远不会发送到服务器,因此服务器无法以合理的方式解密它所传递的私密信息。此外,私密信息在第一次读取后会立即被删除。 功能 私密信息在浏览器中通过 AES 256 位加密进行加密 服务器永远不会接收到明文私密信息 私密信息在第一次读取后即被删除 3. 相关地址 官方 GitHub 地址:https://github.com/Luzifer/ots (目前 638 个 star,欢迎大家去给项目点星星!) Demo 地址:https://ots.fyi/ 当然如果你看到这边还想自己用 docker 搭建一个,那我们就继续往下! 4. 搭建环境 服务器:咕咕这边用的香港的 莱卡云服务器,建议服务器内存 1G 以上,当然你也可以选择其他 高性价比的服务器。 系统:Debian 11 (DD 脚本 非必需 DD,用原来的系统也 OK,之后教程都是用 Debian 或者 Ubuntu 搭建~) 安装好 Docker、Docker-compose(相关脚本) 【必需】域名一枚,并做好解析到服务器上(域名购买、域名解析 视频教程) 【非必需】提前安装好宝塔面板海外版本 aapanel,并安装好 Nginx(安装地址) 【非必需本教程选用】安装好 Nginx Proxy Manager(相关教程) 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 在添加反向代理之前,确保你已经完成了域名解析,不会的可以看这个:域名一枚,并做好解析到服务器上(域名购买、域名解析 视频教程) (名称改成你自己想要的域名前缀即可) 之后,登陆 Nginx Proxy Manager(不会的看这个:安装 Nginx Proxy Manager(相关教程)) 注意: Nginx Proxy Manager(以下简称 NPM)会用到 80、443 端口,所以本机不能占用(比如原来就有 Nginx) 直接丢几张图: 注意填写对应的 域名、IP 和 端口,按文章来的话,应该是 3003 IP 填写: 如果 Nginx Proxy Manager 和 OTS 在同一台服务器上,可以在终端输入: ip addr show docker0 查看对应的 Docker 容器内部 IP。 否则直接填 OTS 所在的服务器 IP 就行。 然后访问域名就可以访问了! 7.2 利用宝塔面板 发现还是有不少小伙伴习惯用宝塔面板,这边也贴一个宝塔面板的反代配置: 直接新建一个站点,不要数据库,不要 php,纯静态即可。 然后打开下面的配置,修改 Nginx 的配置。 代码如下: 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% 的反向代理都能生效,然后就可以用域名来安装访问了。 有同学可能会问,为什么不直接用宝塔自带的反向代理功能。 也可以,不过咕咕自己之前遇到过当有多个网站需要反代的时候,在这边设置会报错的情况 = = 所以后来就不用了,直接用上面的方法来操作了。 8. 使用教程 非常简单,所见即所得。 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

2025/10/22
articleCard.readMore

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

简介 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 链接PayPal, 我这边登录的是美区的PayPal, 选择接受优惠, 成功领取! 已经可以正常使用了! 如果担心被反薅,记得取消 Perplexity 自动续费订阅, 访问:https://www.perplexity.ai/account/details 取消订阅即可,不影响使用 同样的,Perplexity 还支持Mac桌面端,也可以用起来了! 注意点 这次似乎国区的PayPal也可以领取。 有不少网友评价Perplexity玩不起,之前三星的泄漏的一年优惠码,没用几天被收回了。 也有网友表示现在这次打开会提示开通过了。 You are already subscribed or have previously subscribed to Perplexity Pro. 还有一些一注册上就风控,即使美区也是,原先注册好的死活都不让领说领过了,换无数个邮箱尝试依旧如此,这个时候可以考虑换一个干净的IP再试试。

2025/9/4
articleCard.readMore

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

1. 唠嗑 这两三年来,我们搭建了不少好玩的Docker应用,其实一直陆陆续续有小伙伴在视频评论区和博客的评论区询问,怎么样才能让我的Docker应用更安全一点? 这一期,我们就来介绍这样一个工具,用最简单的方式来给我们的Docker应用加一层保险! 效果展示: 保存之后。 再次打开简历这个网页。 提示需要登录了。 输入账号密码,继续 进来了。 2. Tinyauth简介 Tinyauth 是个简单好用的认证中间件,能给你的 Docker 应用加个简洁的登录页面,或者支持 Google、GitHub 以及其他平台的 OAuth 认证。它跟主流代理比如 Nginx Proxy Manager、Traefik、Nginx 和 Caddy 都能无缝配合。 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. 搭建环境 服务器:这边强烈建议用非大陆的服务器,咕咕这边用的香港的莱卡云轻量应用服务器,建议服务器内存1G以上,当然你也可以选择其他高性价比的服务器。 系统:Debian 11 (DD 脚本 非必需 DD,用原来的系统也 OK,之后教程都是用 Debian 或者 Ubuntu 搭建~) 安装好 Docker、Docker-compose(相关脚本) 【必需】域名一枚,并做好解析到服务器上(域名购买、域名解析 视频教程) 【非必需】提前安装好宝塔面板海外版本 aapanel,并安装好 Nginx(安装地址) 【非必需本教程选用】安装好 Nginx Proxy Manager(相关教程) 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 为docker格式化输出这个,记得选yes(按住shift再按小键盘方向键就可以选) 原因是USERS这边在yaml文件里要做哈希转换(比如哈希中的 $ 需要正确转义为 $$,命令行的 Docker 格式会自动处理。),如果不格式化输出会有问题。 当然也支持多个用户,可以再打一遍代码,设置第二个用户, 如果是一个用户,我们直接贴到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 出现类似,代表成功。 这边我们先搞一下反向代理! 做反向代理前,你需要一个域名! namesilo 上面 xyz 后缀的域名一年就 7 块钱,可以年抛。(冷知识,namesilo上 6位数字的xyz续费永远都是0.99美元 = =) 如果想要长期使用,还是建议买 com 后缀的域名,更加正规一些,可以输入 laodade 来获得 1 美元的优惠(不知道现在还有没有) namesilo 自带隐私保护,咕咕一直在用这家,价格也是这些注册商里面比较低的,关键是他家不像其他家域名注册商,没有七七八八的套路!(就是后台界面有些 丑 古老 = =) 【域名购买】Namesilo 优惠码和域名解析教程(附带服务器购买推荐和注意事项) 我们接着往下看! 7. 反向代理 7.1 配置Tinyauth的反向代理 在添加反向代理之前,确保你已经完成了域名解析,不会的可以看这个:域名一枚,并做好解析到服务器上(域名购买、域名解析 视频教程) (名称改成你自己想要的域名前缀即可) 之后,登陆 Nginx Proxy Manager(不会的看这个:安装 Nginx Proxy Manager(相关教程)) 注意: Nginx Proxy Manager(以下简称 NPM)会用到 80、443 端口,所以本机不能占用(比如原来就有 Nginx) 直接丢几张图: 确保“阻止常见漏洞”(Bolck Common Exploits)选项是关掉的。如果这选项开了,Nginx 会把 URL 里的查询参数给拦下来,而 Tinyauth 得靠这些参数才能正常工作。 tinyauth这个是容器的名字,因为它和NPM在一个网络下,所以可以用容器名字来代替域名,3000是内部的端口,保持即可不要更改。 然后访问域名就可以访问了! 7.2 配置需要保护的应用的反向代理 我这边以之前介绍的简历应用(让写简历变得简单且智能!十分钟搭建一个在线简历编辑器——Magic Resume|好玩儿的Docker项目)为例子, 找到你需要添加登录页的应用的对应的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的域名即可。 保存之后。 再次打开简历这个网页。 提示需要登录了。 输入账号密码,继续 进来了。 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

2025/9/3
articleCard.readMore

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

前言 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/ 下载之后,就像安装普通软件一样,安装一下。 然后打开docker。 打开Mac的终端,输入docker -v,有版本号说明安装好了。 这边还会涉及docker换源,由于防火墙的原因,我们大陆可能无法访问docker的镜像仓库,建议大家换成中科大的源:https://docker.mirrors.ustc.edu.cn/ 改成这个: { "builder": { "gc": { "defaultKeepStorage": "20GB", "enabled": true } }, "experimental": false, "features": { "buildkit": true }, "registry-mirrors": [ "https://docker.mirrors.ustc.edu.cn" ] } 然后记得点击应用并重启。 使用如下命令查看Docker配置, docker info 就可以了。 安装Dify Docker安装好之后,接下来安装我们今天的主角——Dify。 文档地址:https://docs.dify.ai/en/introduction 这边一直关注咕咕的小伙伴可以很轻松的安装好。 Mac和Linux其实差不多,我们直接像操作VPS一样来就行。 mkdir ./data/docker_data cd data/docker_data 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 WEAVIATE_AUTHENTICATION_APIKEY_USERS=hello@dify.ai WEAVIATE_AUTHORIZATION_ADMINLIST_ENABLED=true WEAVIATE_AUTHORIZATION_ADMINLIST_USERS=hello@dify.ai # ------------------------------ # 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) CERTBOT_EMAIL=your_email@example.com # 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: test1@dify.ai,test2@dify.ai 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:-hello@dify.ai} WEAVIATE_AUTHORIZATION_ADMINLIST_ENABLED: ${WEAVIATE_AUTHORIZATION_ADMINLIST_ENABLED:-true} WEAVIATE_AUTHORIZATION_ADMINLIST_USERS: ${WEAVIATE_AUTHORIZATION_ADMINLIST_USERS:-hello@dify.ai} 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:-your_email@example.com} 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:-hello@dify.ai} AUTHORIZATION_ADMINLIST_ENABLED: ${WEAVIATE_AUTHORIZATION_ADMINLIST_ENABLED:-true} AUTHORIZATION_ADMINLIST_USERS: ${WEAVIATE_AUTHORIZATION_ADMINLIST_USERS:-hello@dify.ai} # 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 我这边在公司,本来以为很快能拉好镜像,结果网非常的慢,我等不及就去吃中饭了,等到吃饭回来发现已经拉好了。 在这期间,如果决定要本地使用,不调用云端API的话,我们可以先把Ollama和本地的模型先下载起来。 安装Ollama(可选) 其实这个也可以用docker来装,但是既然给了安装版,我们就直接到官网下载即可。 什么是Ollama? Ollama 是一个便于本地部署和运行大型语言模型(Large Language Models, LLMs)的工具。使用通俗的语言来说,如果你想在自己的电脑上运行如 GPT这样的大型人工智能模型,而不是通过互联网连接到它们,那么 Ollama 是一个实现这一目标的工具。 Ollama支持非常多的开源模型,比如: 更多支持的模型可以看这边:https://ollama.com/library 当然它还支持自定义模型,这边就不深入了,有兴趣的可以研究:https://github.com/ollama/ollama 装好之后,命令行运行: ollama -v 查看到版本号说明安装好了。 接下来,比如我们下载一个llama3 8B的模型: ollama run llama3 这边可能需要比较长的时间,取决于你的网速。 下载好了就可以进行交互了: /? 可以查看帮助: /bye 可以退出 其实现在已经搞定了,你可以让它帮你干活了,但是每次都要用命令行,有些人觉得不方便,而且也不能给别人用,下面我们就给它搞一个图形化界面,扩展一下功能,也能让局域网里的其他小伙伴也用上你的这个模型(注意多人同时访问会导致机器负载飙升,具体取决于你机器的性能和模型参数的大小) 配置Dify 等所有容器都拉取好了,我们就可以通过在浏览器地址栏输入:127.0.0.1来访问Dify了。 第一次登录会让你注册一个管理员账号,然后我们就可以登录了, 后台是这个样子的, 我们先来到设置,配置一下大模型, 这边可以看到很多的模型供应商, 我们本地部署,就用ollama, 点击安装, 安装好了之后,来添加模型, 这里的基础URL,填写:http://host.docker.internal:11434 模型名称的话,看看我们ollama里下载了什么模型,打开终端,输入 ollama list 可以看到我这边下载了很多模型, 我们就选择gpt最近刚开源的gpt-oss:20b 其他信息填写如图, 这边是支持函数调用的,选择是,不支持视觉, 这样我们就添加好一个模型啦。 如果你的本地电脑算力不够,也可以选择使用云端的模型,比如DeepSeek之类的, 添加方法也很简单,下载模型供应商,然后在这边点击配置, 填入你在DeepSeek官网拿到的API Key就行了。 OpenAI、ANTHROPIC也是类似的方法,填API Key就可以。 接着,我们就来创建一个空白应用, 这边选择最简单的,创建一个聊天助手, 创建的过程中,你可以调试,这边的自定义程度会高一些, 创建好之后,可以选择发布,或者点击探索, 就可以在这边调出使用了。 当然,这只是最简单的功能,dify的魅力在于降低AI应用开发的门槛,快速构建和部署生产级的生成式AI应用 它通过以下核心功能来实现这个目标: 简化开发流程:Dify是一个开源的大语言模型(LLM)应用开发平台,融合了后端即服务(BaaS)和LLMOps理念,提供可视化的Prompt编排、数据集管理、RAG(检索增强生成)引擎、Agent框架等功能,使开发者无需深入底层技术也能快速搭建AI应用。 支持低代码/无代码开发:通过直观的界面和拖拽操作,非技术人员也能参与AI应用的定义和数据运营,极大地降低了开发门槛。 灵活的模型支持:Dify支持多种主流大语言模型(如GPT、Claude、DeepSeek等)以及开源模型,开发者可根据需求灵活选择和切换模型。 高效的RAG和Agent功能:Dify的RAG技术通过结合外部知识库提升生成内容的准确性,而Agent框架赋予AI自主推理和任务执行能力,适用于复杂场景如智能客服、内容生成等。189.html) 企业级应用支持:Dify提供私有化部署、API集成、多租户隔离等功能,适合企业构建内部AI网关或快速将AI能力融入现有业务,助力AI转型。 总结来说,Dify通过提供一站式、易用的开发平台,帮助开发者、企业甚至非技术人员快速实现AI应用创意,节省开发时间,专注于创新和业务需求,特别适合从原型设计到生产部署的全流程管理。 大家可以自行探索一下Dify的高级玩法,我自己也在慢慢摸索学习,之后有机会可以和大家分享!

2025/8/28
articleCard.readMore

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

前阵子去欧洲玩了一段时间,鸽了挺久了,今天有点时间,立马来和大家分享好玩儿的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,可以搭配大语言模型一起食用。 2. 相关地址 官方GitHub地址:https://github.com/mayswind/ezbookkeeping (目前958个star,欢迎大家去给作者点星星!) 官方Demo:https://ezbookkeeping-demo.mayswind.net 3. 搭建环境 服务器:咕咕这边用的是莱卡云香港服务器,当然你也可以选择其他高性价比的服务器。内存1G以上即可,硬盘当然是越大越好啦。 系统:Debian 11 (DD 脚本 非必需 DD,用原来的系统也 OK,之后教程都是用 Debian 或者 Ubuntu 搭建~) 安装好 Docker、Docker-compose(相关脚本) 【必需】域名一枚,并做好解析到服务器上(域名购买、域名解析 视频教程) 【非必需】提前安装好宝塔面板海外版本 aapanel,并安装好 Nginx(安装地址) 【非必需本教程选用】安装好 Nginx Proxy Manager(相关教程) 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 举例,腾讯云打开方法如下(部分服务商没有自带的面板防火墙,就不用这步操作了): 类似图中的,这边我们填 8082,示例填 ezbookkeeping ,确定即可(如果你在 docker-compose 文件里换了 9009,这边就需要填 9009,以此类推) 查看端口是否被占用(以 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 在添加反向代理之前,确保你已经完成了域名解析,不会的可以看这个:域名一枚,并做好解析到服务器上(域名购买、域名解析 视频教程) 之后,登陆 Nginx Proxy Manager(不会的看这个:安装 Nginx Proxy Manager(相关教程)) 注意: Nginx Proxy Manager(以下简称 NPM)会用到 80、443 端口,所以本机不能占用(比如原来就有 Nginx) 直接丢几张图: 注意填写对应的 域名、IP 和 端口,按文章来的话,应该是 8082 IP 填写: 如果 Nginx Proxy Manager 和 ezbookkeeping 在同一台服务器上,可以在终端输入: ip addr show docker0 查看对应的 Docker 容器内部 IP。 否则直接填 ezbookkeeping 所在的服务器 IP 就行。 6.2 利用宝塔面板 发现还是有不少小伙伴习惯用宝塔面板,这边也贴一个宝塔面板的反代配置: 直接新建一个站点,不要数据库,不要 php,纯静态即可。 然后打开下面的配置,修改 Nginx 的配置。 代码如下: 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% 的反向代理都能生效,然后就可以用域名来安装访问了。 有同学可能会问,为什么不直接用宝塔自带的反向代理功能。 也可以,不过咕咕自己之前遇到过当有多个网站需要反代的时候,在这边设置会报错的情况 = = 所以后来就不用了,直接用上面的方法来操作了。 7. 使用教程 登录你的域名之后,可以看到首页: 这个时候需要创建一个新账号: 这里的预设分类,可以选择打开: 进入后台,结构很清晰: 我们先来添加一下账户: 比如,取名就叫做“咕咕的账本”: 先来手动添加一笔试试看: 可以正常添加: MCP配置 一开始我们就说了,这个账本支持MCP。 MCP(模型上下文协议)是由 Anthropic 开发的一种开放协议,它能让 AI 模型安全地连接到外部数据源和和工具。 简单来说,MCP 就像一座桥梁,它提供了一种通用的标准,让 AI 工具能安全地获取信息和执行操作,同时确保数据安全和用户可以掌控一切。 有了 MCP 协议,你就可以用自己喜欢的 AI 工具来: 添加交易记录:比如,直接用自然语言(就是日常说话的方式)来创建交易,或者从不同的文件格式中批量导入交易记录。 查询交易数据:比如,让你的 AI 工具帮你分析历史交易记录。 以及做更多的事情。 更多MCP相关介绍可以看这边:https://ezbookkeeping.mayswind.net/mcp 这边我们来看看怎么配置。 首先找到右上角的用户设置, 生成MCP令牌: 有两种形式,分别是普通的令牌和json配置: 普通: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyVG9rZW5JZCI6IjMzOTQ1NTM3NTIyOTE5OTc4MzYiLCJqdGkiOiIzNzY4ODA2Njg4MjQ1NjbWUiOiJSb3kiLCJ0eXBlIjo1LCJpYXQiOjE3NTQ5ODc3NzcsImV4cCI6MTA5NzgzNTk4MTR9.7JL_4kzKhihatpfQxIkhD6Z_ibZ_vBYtcQ_D9UCV--0 JSON配置: { "mcpServers": { "ezbookkeeping-mcp": { "type": "streamable-http", "url": "http://localhost:8080/mcp", "headers": { "Authorization": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyVG9rZW5JZCI6IjMzOTQ1NTM3NTIyOTE5OTc4MzYiLCJqdGkiOiIzNzY4ODA2Njg4hbWUiOiJSb3kiLCJ0eXBlIjo1LCJpYXQiOjE3NTQ5ODc3NzcsImV4cCI6MTA5NzgzNTk4MTR9.7JL_4kzKhihatpfQxIkhD6Z_ibZ_vBYtcQ_D9UCV--0" } } } } 这边可以保存下来,下次打开就看不到了。 Cherry Studio配置 这边以Cherry Studio为例,看看MCP怎么配置。 配置情况如图: 名称:主要用于识别,例如:ezBookkeeping 类型:选择 streamableHttp 协议 URL:为 你的域名/mcp 请求头: 为 Authorization=Bearer {token} 接着可以查看一下可以调用的工具: 然后为了确保大模型能正确理解什么是今天,还需要加个时间MCP,这次我们选择json导入, { "mcpServers": { "mcp-server-time": { "command": "uvx", "args": ["mcp-server-time"] } } } 这下,你应该有两个MCP服务了。 查看一下时间工具的功能: 接着,我们到Cherry Studio里新建一个助手, 选择启用这两个MCP服务: 测试一下,可以看到回答的时候,调用了MCP服务, 这边提示错误,我没有说记录到哪个账本: 还需要说明交易类别, 后续, 记录成功! 不过这次似乎没有调用时间MCP,时间似乎有问题…… 然后我尝试使用Deepseek,直接不调用MCP服务了,很奇怪。 后续一直没调用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

2025/8/12
articleCard.readMore

拒绝恶意收购,十分钟搭建AList的替代品——OpenList|好玩儿的Docker项目

最近事情比较多,鸽了好一阵子了。前阵子Alist被收购的事情,相信不少小伙伴可能已经有了解。 这边给还不清楚的小伙伴简单梳理一下。 1. 介绍 AList是一个广受欢迎的开源项目,支持多种云存储的统一管理和WebDAV功能,因其便捷性和强大的网盘聚合能力在开发者社区中积累了近5万星标。 咕咕在自己的博客里也介绍过这个项目——【好玩的Docker项目】目前最好用的网盘直链程序——AList,支持市面上几乎所有网盘!可以代替Olaindex! (突然发现已经是三年前的事情了 = =) 然而,2025年6月爆出的项目被出售事件引发了开源社区的激烈反响。 事件背景 项目出售:据多方消息,AList被原开发者Xhofe出售给贵州不够科技有限公司(BugoTech),交易过程未公开,缺乏社区通知。原开发者确认项目已交由公司运营,自己仅保留代码审查权,main分支启用PR审核和CI自动构建以确保透明性。 争议操作:新维护者(账号alist666)提交的PR #8633被发现包含收集用户设备信息并上传至私有服务器的代码,引发“供应链投毒”担忧,虽因社区压力撤回,但信任危机加剧。文档被大幅修改,移除原作者信息,新增商业化内容(如VIP技术支持和QQ群),官网域名从alist.nn.ci更换为alistgo.com,旧链接404。 收购方背景:不够科技此前收购Hutool、LNMP等项目,伴随权限争议和疑似“投毒”历史,社区对其声誉存疑。 社区反应 愤怒与失望: 信任崩塌:社区对原开发者Xhofe未提前公告的“暗箱操作”表示强烈不满,认为此举背叛了开源精神,伤害了用户和贡献者的信任。GitHub Issues区被大量批评淹没,新维护者删除质疑帖并移除反对者进一步激化矛盾。 隐私担忧:AList涉及网盘Token和Cookie等敏感数据,用户担心新版本可能泄露隐私或被植入恶意代码。社区建议锁定v3.40.0版本,解除网盘授权,并备份重要文件。 对收购方的质疑:不够科技的“黑历史”被广泛讨论,社区将其与此前LNMP、Oneinstack的闭源和投毒争议联系起来,称其为“傻逼公司”“bug科技”,对其动机和代码安全性高度警惕。 社区自救与分叉: 分叉项目:开发者迅速行动,创建了OpenList等分叉项目,移除不可信代码并审计近半年提交,短时间内获数千星标,显示社区对替代方案的热情。 替代方案:技术博客推荐Zdir、Cloudreve等私有网盘程序,鼓励用户迁移以规避风险。 安全建议:社区提出锁定版本、校验哈希、隔离网络、自行编译等措施,强调去中心化分发和社区监督的重要性。 对原开发者的复杂情绪: 理解与支持:部分开发者(如@DIYgod)表示理解Xhofe的决定,认为开源维护的长期孤独和无回报让变现成为合理选择,祝福其获得回报。贡献图显示Xhofe个人提交超90%代码,凸显其付出。 批评与指责:更多用户认为Xhofe将社区贡献和用户数据“卖给有前科的公司”是不道德的,称其“把用户当交易品”,损害了开源生态的信任。 评价 对原开发者的行为:Xhofe作为主要贡献者有权在MIT/AGPL-3.0许可证框架内转让项目,但未公开透明的做法违背了开源社区的信任契约。 虽然其后续承诺代码审查,但“悄然退出”和“配合移除贡献者痕迹”让社区感到被背叛,凸显了单一开发者主导项目的风险。 对收购方的操作:不够科技的历史记录和新代码的隐私收集行为引发合理担忧,其商业化导向(如VIP服务)与开源精神冲突。删除批评和接管仓库的“粗暴”操作进一步破坏信任,可能导致AList用户流失。 社区的应对:社区的激烈反应反映了对开源项目透明度和数据安全的重视。分叉项目和替代方案的迅速涌现展现了开源生态的韧性,但也暴露了国内开源项目变现难、社区监督机制不足的问题。 对开源生态的启示:AList事件敲响警钟,提醒用户关注项目维护的可持续性和开发者的稳定性。建议建立贡献者许可协议(CLA)和社区监督机制,防止类似“野蛮收购”。用户应谨慎选择涉及敏感数据的开源工具,优先考虑社区主导的项目。 结论 AList被收购事件引发了开源社区的信任危机,社区的愤怒源于对隐私安全和开源精神的双重担忧。尽管部分人理解原开发者的变现动机,但其隐秘操作和收购方的争议历史让事件成为“开源之耻”。社区通过分叉和替代方案展现了自救能力,但事件也暴露了国内开源生态在商业化与信任之间的矛盾。用户应保持警惕,优先选择透明、社区驱动的项目,同时推动更完善的开源治理机制。 这一期,我们就来分享一个Alist的开源替代——OpenList。 如果你之前安装过 Alist,其实只要在docker-compose.yml修改两处: 镜像名从 xhofe/alist 改为 openlistteam/openlist 映射的容器内的路径,由 /opt/alist/ 改为 /opt/openlist/(如果添加了本地存储,记得也修改一下根文件夹路径,其他网盘不影响) 运行之前,最好对原来的数据进行一次备份,运行之后,原来怎么使用,现在还是一样的。 2. 相关地址 官方GitHub地址:https://github.com/OpenListTeam/OpenList (目前10.6k个star,欢迎大家去给作者点星星!) 3. 搭建环境 服务器:咕咕这边用的是OVH的杜甫,当然你也可以选择其他高性价比的服务器。内存1G以上即可,硬盘当然是越大越好啦。 系统:Debian 11 (DD 脚本 非必需 DD,用原来的系统也 OK,之后教程都是用 Debian 或者 Ubuntu 搭建~) 安装好 Docker、Docker-compose(相关脚本) 【必需】域名一枚,并做好解析到服务器上(域名购买、域名解析 视频教程) 【非必需】提前安装好宝塔面板海外版本 aapanel,并安装好 Nginx(安装地址) 【非必需本教程选用】安装好 Nginx Proxy Manager(相关教程) 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/openlist cd openlist 我们来简单修改一下作者提供的docker-compose.yml文件 vim docker-compose.yml 咕咕修改之后的(其实就是修改了端口号和删除了version: "3.7"): services: openlist: image: 'openlistteam/openlist:latest' container_name: openlist volumes: - '/data:/opt/openlist/data' - './share:/opt/openlist/share' ports: - '5288:5244' environment: - PUID=0 - PGID=0 - UMASK=022 restart: unless-stopped 修改完成之后,可以在英文输入法下,按 i 修改,完成之后,按一下 esc,然后 :wq 保存退出。 5.3 打开服务器防火墙(非必需)并访问网页 打开防火墙的端口 5288 举例,腾讯云打开方法如下(部分服务商没有自带的面板防火墙,就不用这步操作了): 类似图中的,这边我们填 5288,示例填 openlist ,确定即可(如果你在 docker-compose 文件里换了 9009,这边就需要填 9009,以此类推) 查看端口是否被占用(以 5288 为例),输入: lsof -i:5288 #查看 5288 端口是否被占用,如果被占用,重新自定义一个端口 如果啥也没出现,表示端口未被占用,我们可以继续下面的操作了~ 如果出现: -bash: lsof: command not found 运行: apt install lsof #安装 lsof 如果端口没有被占用(被占用了就修改一下端口,比如改成 8381,注意 docker 命令行里和防火墙都要改) 5.4 启动 openlist cd /root/data/docker_data/openlist docker compose up -d # 注意,老版本用户用 docker-compose up -d 等待拉取好镜像,出现 done的字样之后, 理论上我们就可以输入 http://ip:5288 访问了。 但是这边我们推荐先搞一下反向代理! 做反向代理前,你需要一个域名! namesilo 上面 xyz 后缀的域名一年就 7 块钱,可以年抛。(冷知识,namesilo上 6位数字的xyz续费永远都是0.99美元 = =) 如果想要长期使用,还是建议买 com 后缀的域名,更加正规一些,可以输入 laodade 来获得 1 美元的优惠(不知道现在还有没有) namesilo 自带隐私保护,咕咕一直在用这家,价格也是这些注册商里面比较低的,关键是他家不像其他家域名注册商,没有七七八八的套路!(就是后台界面有些 丑 古老 = =) 【域名购买】Namesilo 优惠码和域名解析教程(附带服务器购买推荐和注意事项) 我们接着往下看! 6. 反向代理 6.1 利用 Nginx Proxy Manager 在添加反向代理之前,确保你已经完成了域名解析,不会的可以看这个:域名一枚,并做好解析到服务器上(域名购买、域名解析 视频教程) 之后,登陆 Nginx Proxy Manager(不会的看这个:安装 Nginx Proxy Manager(相关教程)) 注意: Nginx Proxy Manager(以下简称 NPM)会用到 80、443 端口,所以本机不能占用(比如原来就有 Nginx) 直接丢几张图: 注意填写对应的 域名、IP 和 端口,按文章来的话,应该是 5288 IP 填写: 如果 Nginx Proxy Manager 和 openlist 在同一台服务器上,可以在终端输入: ip addr show docker0 查看对应的 Docker 容器内部 IP。 否则直接填 openlist 所在的服务器 IP 就行。 6.2 利用宝塔面板 发现还是有不少小伙伴习惯用宝塔面板,这边也贴一个宝塔面板的反代配置: 直接新建一个站点,不要数据库,不要 php,纯静态即可。 然后打开下面的配置,修改 Nginx 的配置。 代码如下: location / { proxy_pass http://127.0.0.1:5288/; # 注意改成你实际使用的端口 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% 的反向代理都能生效,然后就可以用域名来安装访问了。 有同学可能会问,为什么不直接用宝塔自带的反向代理功能。 也可以,不过咕咕自己之前遇到过当有多个网站需要反代的时候,在这边设置会报错的情况 = = 所以后来就不用了,直接用上面的方法来操作了。 7. 使用教程 首先来输入命令: docker compose logs 查看一下初始的登录密码: 这边的密码是OVoPTw5B 打开域名登录: 默认用户名:admin OVoPTw5B 这个等下都可以自己修改。 登录之后发现是这样的,因为我们还没有添加任何的存储源: 点击首页下方的管理,来到后台。 我们来演示一下"添加存储"的操作, 这边先选择一个"本地存储", 挂载路径这边可以自己自定义, WebDAV策略选择“本地代理”就行, 根文件夹路径要填docker容器内部的路径,这边前面我们在docker-compose.yml里面映射了./share:/opt/openlist/share,所以其实这边填/opt/openlist/share即可。 其他的选项按需自己设置。 点击保存之后,再返回首页,就有显示了,后续可以自己把文件传到服务器,这边就会显示出来了。 当然,AList之所以火爆,就是因为他可以添加很多个网盘的索引, 因为不同的小伙伴用的网盘也不一样,具体的细节,大家可以参考官方的文档来添加:https://docs.oplist.org/zh/guide/drivers/common.html 7.1 更新 openlist cd /root/data/docker_data/openlist 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 卸载 openlist 同样进入安装页面,先停止所有容器。 cd /root/data/docker_data/openlist docker compose down cd .. rm -rf /root/data/docker_data/openlist # 完全删除 可以卸载得很干净。 8. 常见问题及注意点 目前 OpenList 已经发布了 4.0 正式版,但依然存在一些已知问题,不过大部分功能已可稳定使用,具体迁移进度可在 OpenList 迁移工作总结 中查看。 大家记得多多更新,使用最新版本的docker镜像。 目前项目的赞助页面还未建立:https://docs.oplist.org/zh/zh/guide/sponsor.html 后续建立了我也会支持,同时也希望有条件的小伙伴多多支持,赞赏开发者们一杯咖啡。这样也能让开源项目能够健康生存下去,少受商业的裹挟。 9. 结尾 祝大家用得开心,有问题可以去 GitHub 提 Issues,也可以在评论区互相交流探讨。 同时,项目处于初期,有能力给项目做贡献的同学,也欢迎积极加入到 [项目]https://github.com/OpenListTeam/OpenList) 中来,贡献自己的一份力量! 最后,感谢开发人员们的辛苦付出,让我们能用到这么优秀的项目!也希望开源项目越来越好! 10. 参考资料 官方GitHub:https://github.com/OpenListTeam/OpenList

2025/7/4
articleCard.readMore

保护图片隐私!十分钟搭建一个小而美的离线图片处理工具——mazanoke|好玩儿的Docker项目

1. 唠嗑 之前和大家分享过:一个本地化图片处理工具——Reubah 今天我们再来分享一个UI更简洁漂亮的支持docker自建的本地图像处理工具——mazanoke 2. mazanoke简介 MAZANOKE 是一个简单的图像优化工具,可以在你的浏览器中运行,离线工作,并且始终保持你的图像私密,是市面上那些宣传“免费”在线图片处理工具的替代品。 2.1 功能 🖼️ 在浏览器中优化图像 调整图像质量 设置目标文件大小 设置最大宽度/高度 从剪贴板粘贴图像 在 JPG、PNG、WebP 之间转换 从 HEIC、AVIF、GIF、SVG 转换 🔒 注重隐私 离线工作 设备内处理图像 删除 EXIF 数据(位置、日期等) 无追踪 可安装的网络应用程序 计划中的功能 一次上传多个文件 支持更多图像文件类型 最近添加了从:HEIC、AVIF、GIF、SVG → JPG/PNG/WebP 的转换 记住上次使用的设置 裁剪图片 2.2 使用 官方Demo地址:MAZANOKE.com 所见即所得,不多赘述。 其实,这个本质就是一个html页面,你可以直接点击右上角下载,这样就能离线使用了。 或者是在这边下载:https://github.com/civilblur/mazanoke/releases 然后打开里面的index.html也可以直接离线使用。 当然如果你看到这边还想自己用docker搭建一个,那我们就继续往下! 3. 相关地址 官方GitHub地址:https://github.com/civilblur/mazanoke (目前1K个star,欢迎大家去给项目点星星!) 4. 搭建环境 服务器:咕咕这边用的香港的莱卡云服务器,建议服务器内存1G以上,当然你也可以选择其他高性价比的服务器。 系统:Debian 11 (DD 脚本 非必需 DD,用原来的系统也 OK,之后教程都是用 Debian 或者 Ubuntu 搭建~) 安装好 Docker、Docker-compose(相关脚本) 【必需】域名一枚,并做好解析到服务器上(域名购买、域名解析 视频教程) 【非必需】提前安装好宝塔面板海外版本 aapanel,并安装好 Nginx(安装地址) 【非必需本教程选用】安装好 Nginx Proxy Manager(相关教程) 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/mazanoke cd /root/data/docker_data/mazanoke 接着我们来编辑下docker-compose.yml vim docker-compose.yml # Basic compose file for deploying MAZANOKE services: mazanoke: container_name: mazanoke image: ghcr.io/civilblur/mazanoke:latest ports: - "3474:80" restart: unless-stopped 其中的左边的3474可以改成服务器上没有用过的端口,记得修改自己的用户名和密码,修改完成之后,可以在英文输入法下,按 i 修改,完成之后,按一下 esc,然后 :wq 保存退出。 6.3 查看端口是否被占用 查看端口是否被占用(以 3474 为例),输入: lsof -i:3474 #查看 3474 端口是否被占用,如果被占用,重新自定义一个端口 如果啥也没出现,表示端口未被占用,我们可以继续下面的操作了~ 如果出现: -bash: lsof: command not found 运行: apt install lsof #安装 lsof 如果端口没有被占用(被占用了就修改一下端口,比如改成 8381,注意 docker 命令行里和防火墙都要改) 6.4 启动 mazanoke cd /root/data/docker_data/mazanoke docker compose up -d # 注意,老版本用户用 docker-compose up -d 耐心等待拉取好镜像,出现 done的字样之后, 理论上我们就可以输入 http://ip:3474 访问了。 但是这边这个服务必须先搞一下反向代理!http使用明文传输太危险,我们部署在公网一定要考虑使用反向代理工具配置SSL! 做反向代理前,你需要一个域名! namesilo 上面 xyz 后缀的域名一年就 7 块钱,可以年抛。(冷知识,namesilo上 6位数字的xyz续费永远都是0.99美元 = =) 如果想要长期使用,还是建议买 com 后缀的域名,更加正规一些,可以输入 laodade 来获得 1 美元的优惠(不知道现在还有没有) namesilo 自带隐私保护,咕咕一直在用这家,价格也是这些注册商里面比较低的,关键是他家不像其他家域名注册商,没有七七八八的套路!(就是后台界面有些 丑 古老 = =) 【域名购买】Namesilo 优惠码和域名解析教程(附带服务器购买推荐和注意事项) 我们接着往下看! 7. 反向代理 7.1 利用 Nginx Proxy Manager 在添加反向代理之前,确保你已经完成了域名解析,不会的可以看这个:域名一枚,并做好解析到服务器上(域名购买、域名解析 视频教程) (名称改成你自己想要的域名前缀即可) 之后,登陆 Nginx Proxy Manager(不会的看这个:安装 Nginx Proxy Manager(相关教程)) 注意: Nginx Proxy Manager(以下简称 NPM)会用到 80、443 端口,所以本机不能占用(比如原来就有 Nginx) 直接丢几张图: 注意填写对应的 域名、IP 和 端口,按文章来的话,应该是 3474 IP 填写: 如果 Nginx Proxy Manager 和 mazanoke 在同一台服务器上,可以在终端输入: ip addr show docker0 查看对应的 Docker 容器内部 IP。 否则直接填 mazanoke 所在的服务器 IP 就行。 然后访问域名就可以访问了! 7.2 利用宝塔面板 发现还是有不少小伙伴习惯用宝塔面板,这边也贴一个宝塔面板的反代配置: 直接新建一个站点,不要数据库,不要 php,纯静态即可。 然后打开下面的配置,修改 Nginx 的配置。 代码如下: location / { proxy_pass http://127.0.0.1:3474/; # 注意改成你实际使用的端口 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% 的反向代理都能生效,然后就可以用域名来安装访问了。 有同学可能会问,为什么不直接用宝塔自带的反向代理功能。 也可以,不过咕咕自己之前遇到过当有多个网站需要反代的时候,在这边设置会报错的情况 = = 所以后来就不用了,直接用上面的方法来操作了。 8. 使用教程 非常简单,所见即所得。 8.1 更新 mazanoke 这个项目后续应该也会有更新,所以提供一个更新的方式。 cd /root/data/docker_data/mazanoke 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 卸载 mazanoke 同样进入安装页面,先停止所有容器。 cd /root/data/docker_data/mazanoke docker compose down cd .. rm -rf /root/data/docker_data/mazanoke # 完全删除 可以卸载得很干净。 9. 常见问题及注意点 大家有问题欢迎评论区交流。 10. 结尾 祝大家用得开心,有问题可以去 GitHub 提 Issues,也可以在评论区互相交流探讨。 同时,有能力给项目做贡献的同学,也欢迎积极加入到 项目 中来,贡献自己的一份力量! 最后,感谢作者@civilblur的辛苦付出,让我们能用到这么优秀的项目!欢迎大家都去给这个项目点个 star ⭐️ 参考资料 官方GitHub:https://github.com/civilblur/mazanoke

2025/5/9
articleCard.readMore

10分钟搭建一个高颜值的在线开发工具箱—— jisuxiang|好玩儿的Docker项目

1. 唠嗑 之前和大家分享过【好玩儿的Docker项目】10分钟搭建一个高颜值的在线工具箱,用户体验很棒!, 功能很丰富,不过不支持中文。 这一期来介绍一个中文的,高颜值的在线开发工具箱。 2. jisuxiang简介 极速箱是一个高颜值的在线开发工具箱,提供各种程序员必备的开发工具,帮助开发者提升编程效率。本项目使用 Next.js 和 TailwindCSS 开发,拥有美观现代的界面设计。 在线演示: https://www.jisuxiang.com - 立即体验! 2.1 🚀 功能特点 多种分类工具:JSON处理、编码解码、网络测试等多种实用工具 响应式设计:适配各种设备尺寸,提供最佳用户体验 暗色主题:保护眼睛的界面设计,适合长时间使用 高效搜索:快速找到所需工具的强大搜索功能 收藏系统:保存常用工具,方便快速访问 多语言支持:支持中文和英文界面 2.2 🔧 包含工具 JSON格式化与验证 HTTP请求测试 时间戳转换 编码解码工具 正则表达式测试 加密解密工具 颜色选择与转换 代码格式化 JSON编辑器与转换器 IP地址查询 日期计算器 时区转换 文本统计 HTML/Markdown转换 图片压缩 二维码生成 CSS渐变生成器 更多实用工具... 2.3 使用 3. 相关地址 官方GitHub地址:https://github.com/star7th/jisuxiang (目前261个star,欢迎大家去给项目点星星!) 4. 搭建环境 服务器:咕咕这边用的香港的腾讯云轻量应用服务器,建议服务器内存1G以上,当然你也可以选择其他高性价比的服务器。 系统:Debian 11 (DD 脚本 非必需 DD,用原来的系统也 OK,之后教程都是用 Debian 或者 Ubuntu 搭建~) 安装好 Docker、Docker-compose(相关脚本) 【必需】域名一枚,并做好解析到服务器上(域名购买、域名解析 视频教程) 【非必需】提前安装好宝塔面板海外版本 aapanel,并安装好 Nginx(安装地址) 【非必需本教程选用】安装好 Nginx Proxy Manager(相关教程) 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/jisuxiang cd /root/data/docker_data/jisuxiang 接着我们来编辑下docker-compose.yml vim docker-compose.yml name: jisuxiang services: jisuxiang: container_name: jisuxiang restart: always ports: - 3001:3000 image: star7th/jisuxiang:latest 其中的左边的3001可以改成服务器上没有用过的端口,记得修改自己的用户名和密码,修改完成之后,可以在英文输入法下,按 i 修改,完成之后,按一下 esc,然后 :wq 保存退出。 6.3 查看端口是否被占用 查看端口是否被占用(以 3001 为例),输入: lsof -i:3001 #查看 3001 端口是否被占用,如果被占用,重新自定义一个端口 如果啥也没出现,表示端口未被占用,我们可以继续下面的操作了~ 如果出现: -bash: lsof: command not found 运行: apt install lsof #安装 lsof 如果端口没有被占用(被占用了就修改一下端口,比如改成 8381,注意 docker 命令行里和防火墙都要改) 6.4 启动 jisuxiang cd /root/data/docker_data/jisuxiang docker compose up -d # 注意,老版本用户用 docker-compose up -d 耐心等待拉取好镜像,出现 done的字样之后, 理论上我们就可以输入 http://ip:3001 访问了。 但是这边这个服务必须先搞一下反向代理!http使用明文传输太危险,我们部署在公网一定要考虑使用反向代理工具配置SSL! 做反向代理前,你需要一个域名! namesilo 上面 xyz 后缀的域名一年就 7 块钱,可以年抛。(冷知识,namesilo上 6位数字的xyz续费永远都是0.99美元 = =) 如果想要长期使用,还是建议买 com 后缀的域名,更加正规一些,可以输入 laodade 来获得 1 美元的优惠(不知道现在还有没有) namesilo 自带隐私保护,咕咕一直在用这家,价格也是这些注册商里面比较低的,关键是他家不像其他家域名注册商,没有七七八八的套路!(就是后台界面有些 丑 古老 = =) 【域名购买】Namesilo 优惠码和域名解析教程(附带服务器购买推荐和注意事项) 我们接着往下看! 7. 反向代理 7.1 利用 Nginx Proxy Manager 在添加反向代理之前,确保你已经完成了域名解析,不会的可以看这个:域名一枚,并做好解析到服务器上(域名购买、域名解析 视频教程) (名称改成你自己想要的域名前缀即可) 之后,登陆 Nginx Proxy Manager(不会的看这个:安装 Nginx Proxy Manager(相关教程)) 注意: Nginx Proxy Manager(以下简称 NPM)会用到 80、443 端口,所以本机不能占用(比如原来就有 Nginx) 直接丢几张图: 注意填写对应的 域名、IP 和 端口,按文章来的话,应该是 3001 IP 填写: 如果 Nginx Proxy Manager 和 jisuxiang 在同一台服务器上,可以在终端输入: ip addr show docker0 查看对应的 Docker 容器内部 IP。 否则直接填 jisuxiang 所在的服务器 IP 就行。 然后访问域名就可以访问了! 7.2 利用宝塔面板 发现还是有不少小伙伴习惯用宝塔面板,这边也贴一个宝塔面板的反代配置: 直接新建一个站点,不要数据库,不要 php,纯静态即可。 然后打开下面的配置,修改 Nginx 的配置。 代码如下: location / { proxy_pass http://127.0.0.1:3001/; # 注意改成你实际使用的端口 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% 的反向代理都能生效,然后就可以用域名来安装访问了。 有同学可能会问,为什么不直接用宝塔自带的反向代理功能。 也可以,不过咕咕自己之前遇到过当有多个网站需要反代的时候,在这边设置会报错的情况 = = 所以后来就不用了,直接用上面的方法来操作了。 8. 使用教程 非常简单,开箱即用。 8.1 更新 jisuxiang 这个项目后续应该也会有更新,所以提供一个更新的方式。 cd /root/data/docker_data/jisuxiang 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 卸载 jisuxiang 同样进入安装页面,先停止所有容器。 cd /root/data/docker_data/jisuxiang docker compose down cd .. rm -rf /root/data/docker_data/jisuxiang # 完全删除 可以卸载得很干净。 9. 常见问题及注意点 暂时没有。 10. 结尾 祝大家用得开心,有问题可以去 GitHub 提 Issues,也可以在评论区互相交流探讨。 同时,有能力给项目做贡献的同学,也欢迎积极加入到 项目 中来,贡献自己的一份力量! 最后,感谢作者@star7th的辛苦付出,让我们能用到这么优秀的项目!欢迎大家都去给这个项目点个 star ⭐️ 参考资料 官方GitHub:https://github.com/star7th/jisuxiang

2025/4/22
articleCard.readMore

Docker 一键部署网盘资源搜索与转存工具——CloudSaver|好玩儿的Docker项目

1. 唠嗑 最近事情比较多,很长时间没和大家分享好玩儿的Docker项目了,今天来分享一个网盘资源搜索与转存工具——CloudSaver 2. cloudsaver简介 🔍 多源资源搜索 支持多个资源订阅源搜索 支持关键词搜索与资源链接解析 支持豆瓣热门榜单展示 💾 网盘资源转存 支持 115 网盘,夸克网盘,天翼网盘 一键转存 支持转存文件夹展示与选择 👥 多用户系统 支持用户注册登录 支持管理员与普通用户权限区分 📱 响应式设计 支持 PC 端与移动端自适应布局 针对不同设备优化的交互体验 2.1 特别声明 本项目仅供学习交流使用,请勿用于非法用途 仅支持个人使用,不支持任何形式的商业使用 禁止在项目页面进行任何形式的广告宣传 所有搜索到的资源均来自第三方,本项目不对其真实性、合法性做出任何保证 2.2 使用 热门榜单 资源搜索 比如搜一个“甄嬛传” 转存 转存成功 当然如果你看到这边想自己搭建一个,那我们就继续往下看! 3. 相关地址 官方GitHub地址:https://github.com/jiangrui1994/cloudsaver (目前3.6K个star,欢迎大家去给项目点星星!) 4. 搭建环境 服务器:这边强烈建议用非大陆的服务器,不然必须要启用代理设置,否则会刷不到任何内容,咕咕这边用的香港的腾讯云轻量应用服务器,建议服务器内存1G以上,当然你也可以选择其他高性价比的服务器。 系统:Debian 11 (DD 脚本 非必需 DD,用原来的系统也 OK,之后教程都是用 Debian 或者 Ubuntu 搭建~) 安装好 Docker、Docker-compose(相关脚本) 【必需】域名一枚,并做好解析到服务器上(域名购买、域名解析 视频教程) 【非必需】提前安装好宝塔面板海外版本 aapanel,并安装好 Nginx(安装地址) 【非必需本教程选用】安装好 Nginx Proxy Manager(相关教程) 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/cloudsaver cd /root/data/docker_data/cloudsaver 接着我们来编辑下docker-compose.yml vim docker-compose.yml services: cloudsaver: image: jiangrui1994/cloudsaver:latest container_name: cloud-saver ports: - "8009:8008" volumes: - ./data:/app/data - ./config:/app/config restart: unless-stopped 其中的左边的8009可以改成服务器上没有用过的端口,记得修改自己的用户名和密码,修改完成之后,可以在英文输入法下,按 i 修改,完成之后,按一下 esc,然后 :wq 保存退出。 6.3 查看端口是否被占用 查看端口是否被占用(以 8009 为例),输入: lsof -i:8009 #查看 8009 端口是否被占用,如果被占用,重新自定义一个端口 如果啥也没出现,表示端口未被占用,我们可以继续下面的操作了~ 如果出现: -bash: lsof: command not found 运行: apt install lsof #安装 lsof 如果端口没有被占用(被占用了就修改一下端口,比如改成 8381,注意 docker 命令行里和防火墙都要改) 6.4 启动 cloudsaver cd /root/data/docker_data/cloudsaver docker compose up -d # 注意,老版本用户用 docker-compose up -d 耐心等待拉取好镜像,出现 done的字样之后, 理论上我们就可以输入 http://ip:8009 访问了。 但是这边这个服务必须先搞一下反向代理!http使用明文传输太危险,我们部署在公网一定要考虑使用反向代理工具配置SSL! 做反向代理前,你需要一个域名! namesilo 上面 xyz 后缀的域名一年就 7 块钱,可以年抛。(冷知识,namesilo上 6位数字的xyz续费永远都是0.99美元 = =) 如果想要长期使用,还是建议买 com 后缀的域名,更加正规一些,可以输入 laodade 来获得 1 美元的优惠(不知道现在还有没有) namesilo 自带隐私保护,咕咕一直在用这家,价格也是这些注册商里面比较低的,关键是他家不像其他家域名注册商,没有七七八八的套路!(就是后台界面有些 丑 古老 = =) 【域名购买】Namesilo 优惠码和域名解析教程(附带服务器购买推荐和注意事项) 我们接着往下看! 7. 反向代理 7.1 利用 Nginx Proxy Manager 在添加反向代理之前,确保你已经完成了域名解析,不会的可以看这个:域名一枚,并做好解析到服务器上(域名购买、域名解析 视频教程) (名称改成你自己想要的域名前缀即可) 之后,登陆 Nginx Proxy Manager(不会的看这个:安装 Nginx Proxy Manager(相关教程)) 注意: Nginx Proxy Manager(以下简称 NPM)会用到 80、443 端口,所以本机不能占用(比如原来就有 Nginx) 直接丢几张图: 注意填写对应的 域名、IP 和 端口,按文章来的话,应该是 8009 IP 填写: 如果 Nginx Proxy Manager 和 cloudsaver 在同一台服务器上,可以在终端输入: ip addr show docker0 查看对应的 Docker 容器内部 IP。 否则直接填 cloudsaver 所在的服务器 IP 就行。 然后访问域名就可以访问了! 7.2 利用宝塔面板 发现还是有不少小伙伴习惯用宝塔面板,这边也贴一个宝塔面板的反代配置: 直接新建一个站点,不要数据库,不要 php,纯静态即可。 然后打开下面的配置,修改 Nginx 的配置。 代码如下: location / { proxy_pass http://127.0.0.1:8009/; # 注意改成你实际使用的端口 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% 的反向代理都能生效,然后就可以用域名来安装访问了。 有同学可能会问,为什么不直接用宝塔自带的反向代理功能。 也可以,不过咕咕自己之前遇到过当有多个网站需要反代的时候,在这边设置会报错的情况 = = 所以后来就不用了,直接用上面的方法来操作了。 8. 使用教程 8.1 搜索与转存资源 登陆,开始注册。 默认注册码: 管理员:230713 普通用户:9527 我们是管理员就用230713 为了安全起见,登陆之后第一件事情就去更改一下默认的注册码。 8.2 115 网盘 cookie获取 用户配置,这边就是看你转存到哪个网盘, 这边我们以115网盘为例子: 从网页登录 115网盘; 按 F12 打开 开发者工具; 在Network –> Filter 中输入 get,找到 warning_get,就可以获取到 cookie 的值; 如果115网盘空间不够,可以扫码开通会员,年付158元,可以扩容至5T。 8.3 更新 cloudsaver 这个项目后续应该也会有更新,所以提供一个更新的方式。 cd /root/data/docker_data/cloudsaver 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.4 卸载 cloudsaver 同样进入安装页面,先停止所有容器。 cd /root/data/docker_data/cloudsaver docker compose down cd .. rm -rf /root/data/docker_data/cloudsaver # 完全删除 可以卸载得很干净。 9. 常见问题及注意点 咕咕实测,115资源最多,其他俩网盘有些资源可能失效。 另外,本项目仅供学习交流使用,请勿用于非法用途。 大家有问题欢迎评论区交流。 10. 结尾 祝大家用得开心,有问题可以去 GitHub 提 Issues,也可以在评论区互相交流探讨。 同时,有能力给项目做贡献的同学,也欢迎积极加入到 项目 中来,贡献自己的一份力量! 最后,感谢作者的辛苦付出,让我们能用到这么优秀的项目!欢迎大家都去给这个项目点个 star ⭐️ 参考资料 官方GitHub:https://github.com/jiangrui1994/cloudsaver

2025/4/16
articleCard.readMore

想用大厂的云服务器,如何省心又省钱?试试新加坡的云服务器代理商——Huichang Cloud

云服务器代理商是个啥? 简单来说,云服务器代理商就是帮你搞定云服务器的“中间人”。你想用阿里云、腾讯云这些大厂的服务器,但直接去官网买,可能觉得价格偏高,或者有些用户想要匿名购买或者是用加密货币或者美元购买。代理商呢,就相当于你的“云服务管家”,可以帮你选服务器、开账号、搞优惠,还能提供技术支持。省心省力,关键还能省钱!(他们虽然给你85折的充值优惠,但是由于走的渠道,你的账号是和他们关联的,他们还是有的赚!) 为啥选阿里云国际、腾讯云国际的服务器? 阿里云国际和腾讯云国际有啥优势? 全球覆盖,速度快:不管你的业务在亚洲、欧洲还是美洲,这两家都有遍布全球的数据中心。尤其是新加坡节点,延迟低到飞起,特别适合东南亚市场的朋友。 稳定如老狗:大厂的服务器,硬件和网络都比较靠谱,宕机的概率比你家Wi-Fi断网还低。 功能多到炸:从存储、计算到AI、大数据,啥都能干。想搭网站、跑应用、存数据,都能搞定。 安全性拉满:防火墙、DDoS防护、数据加密,为你的业务保驾护航。 代理开户的优势 用大厂的机器,基本上就是“稳中带快,啥都能干”。但直接买,可能有点烧钱,这时候找个靠谱代理就显得特别重要了。 代理开户的优势如下: 省钱第一名:代理商跟云厂商关系铁,能拿到大额折扣,即使扣除了他们自己赚的那部分,也比你自己官网充值便宜一大截。 省心省力:提供匿名账号,保护客户隐私,免实名,免绑卡,从注册账号到配置服务器,代理帮你一条龙搞定。 售后有保障:官网的客服有时候回复比较慢,代理商的响应速度快多了,随时帮你解决问题。 灵活选择:代理商通常能提供更灵活的套餐,甚至还能定制,满足你的各种奇葩需求。 一句话,找代理就像找了个“云服务经纪人”,可以让你少走一点弯路,直接享受VIP待遇。 认识一下Huichang Cloud,来自新加坡的代理! 新加坡的云服务器代理——Huichang Cloud 在圈子里口碑不错,服务覆盖阿里云国际、腾讯云国际、AWS、华为云等大牌。 为什么选他们? 折扣大 Huichang Cloud跟云厂商深度合作,折扣力度能低到5折!买同样的配置,别人花一万,你可能只要五千。尤其是对于云服务器大户,一年下来可以省不少钱。 账号稳 用过云服务器的朋友可能遇到过账号被封的糟心事。Huichang Cloud的代理渠道账号稳定,合规操作,基本不用担心突然“人间蒸发”。 从开户到售后,一站式服务 不管你是小白还是老手,他们从账号注册、服务器选配到后期维护,全程陪跑。遇到问题?直接找他们,效率更高。 原厂工程师坐镇 Huichang Cloud的技术团队里有不少来自云厂商原厂的工程师,经验老道。不管是优化服务器性能,还是处理突发故障,他们都能给你稳稳地解决。 想了解更多细节,或者直接上手试试? 可以通过Telegram/Whatsapp/QQ(QQ群:901579741),联系到Huichang Cloud,里面有客服随时答疑。 如果充值购买,联系客服报优惠码gugu,可以获得额外5%的充值优惠。 聊聊体验 我特意去试了试Huichang Cloud的服务,打算选个阿里云国际的香港节点服务器。 这边直接点击官网链接,通过Bot机器人充值((建议可以都先联系一下客服再充值), 或者联系客服充值,(可以通过Telegram/Whatsapp/QQ(QQ群:901579741),联系到Huichang Cloud客服) 之后会直接给到账户密码,用于直接在阿里云国际站官网登录。 登录: 选择通过邮箱认证: 然后登录邮箱查看验证码: 登录之后来到控制台,就可以开始选购服务了。 轻量云选购页面: 接下来就是正常和用阿里云一样使用就可以了。 当然,如果你有需求,也可以把账号绑定的手机号和邮箱改成自己的。 注意:更换手机号需要找客服拿到原来手机号的验证码并且只能更换同地区的手机号 全流程大概梳理如下: 通过Telegram、Whatsapp、qq,联系到Huichang Cloud——告诉Huichang Cloud需求(需要哪里的服务器)——付款(美元、USDT、RMB,这边会有相应的折扣)——Huichang Cloud 提供一个充值完成的成品账号,里面包含腾讯或者阿里的云服务器国际站官网的登录信息+对应绑定邮箱的登录信息(用于接收验证码)——用户利用该信息登录国际云的官网,进行服务器的购买操作(里面已经充值过了对应的金额)——后续用户可以根据自己的需求选择是否更换绑定的邮箱和手机号,更换手机号需要找客服拿到原来手机号的验证码并且只能更换同地区的手机号 总的来说,体验下来,Huichang Cloud还是比较“靠谱+省心”的。 最后 云服务器这玩意儿,选对了服务商,可以让你省不少事儿,少踩一堆坑。Huichang Cloud作为新加坡的实力派代理,折扣给力、服务贴心,挺值得一试。不管你是想搭个博客、跑个电商网站,还是搞点更复杂的业务,他们都能帮你安排得明明白白。国内小伙伴有需求的可以加入他们的QQ群:901579741 咨询更多细节。 海外小伙伴可以通过Telegram/Whatsapp,联系到Huichang Cloud,里面有客服随时答疑。

2025/4/13
articleCard.readMore

让写简历变得简单且智能!十分钟搭建一个在线简历编辑器——Magic Resume|好玩儿的Docker项目

1. 唠嗑 关注咕咕频道的有不少小伙伴还在大学念书,这一期我们带来一个实用的项目——帮助你轻松搞定一份简历! 2. magic-resume简介 现有特性 🚀 基于 Next.js 14+ 构建 💫 流畅的动画效果 (Framer Motion) 🎨 自定义主题支持 📱 响应式设计 🌙 深色模式 📤 导出为 PDF 🔄 实时预览 💾 自动保存 🔒 本地存储 后续升级路线 AI 辅助编写 多语言支持 支持更多简历模板 更多格式导出 自定义模型 智能一页 导入 PDF, Markdown 等 在线简历托管 使用 里面有常用的一些模版,可以选一个自己喜欢的,直接套用: 支持文件夹同步: AI 辅助编写的功能已经上线,模型目前支持豆包和deepseek: 简历的编辑页面是这样的: 功能非常丰富,所见即所得: 其实这个项目大家不用自己搭,可以直接使用作者搭好的Demo,Demo地址:https://magicv.art/app/dashboard/resumes 当然如果你看到这边想自己搭建一个,那我们就继续往下看! 3. 相关地址 官方GitHub地址:https://github.com/JOYCEQL/magic-resume (目前937个star,欢迎大家去给项目点星星!) 4. 搭建环境 服务器:这边强烈建议用非大陆的服务器,不然很多网站访问不了,咕咕这边用的香港的腾讯云轻量应用服务器,建议服务器内存1G以上,当然你也可以选择其他高性价比的服务器。 系统:Debian 11 (DD 脚本 非必需 DD,用原来的系统也 OK,之后教程都是用 Debian 或者 Ubuntu 搭建~) 安装好 Docker、Docker-compose(相关脚本) 【必需】域名一枚,并做好解析到服务器上(域名购买、域名解析 视频教程) 【非必需】提前安装好宝塔面板海外版本 aapanel,并安装好 Nginx(安装地址) 【非必需本教程选用】安装好 Nginx Proxy Manager(相关教程) 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/magic-resume cd /root/data/docker_data/magic-resume 接着我们来编辑下docker-compose.yml vim docker-compose.yml services: web: image: siyueqingchen/magic-resume:main ports: - "3000:3000" environment: - NODE_ENV=production restart: always 其中的左边的3000可以改成服务器上没有用过的端口,记得修改自己的用户名和密码,修改完成之后,可以在英文输入法下,按 i 修改,完成之后,按一下 esc,然后 :wq 保存退出。 6.3 查看端口是否被占用 查看端口是否被占用(以 3000 为例),输入: lsof -i:3000 #查看 3000 端口是否被占用,如果被占用,重新自定义一个端口 如果啥也没出现,表示端口未被占用,我们可以继续下面的操作了~ 如果出现: -bash: lsof: command not found 运行: apt install lsof #安装 lsof 如果端口没有被占用(被占用了就修改一下端口,比如改成 8381,注意 docker 命令行里和防火墙都要改) 6.4 启动 magic-resume cd /root/data/docker_data/magic-resume docker compose up -d # 注意,老版本用户用 docker-compose up -d 耐心等待拉取好镜像,出现 done的字样之后, 理论上我们就可以输入 http://ip:3000 访问了。 但是这边这个服务必须先搞一下反向代理!http使用明文传输太危险,我们部署在公网一定要考虑使用反向代理工具配置SSL! 做反向代理前,你需要一个域名! namesilo 上面 xyz 后缀的域名一年就 7 块钱,可以年抛。(冷知识,namesilo上 6位数字的xyz续费永远都是0.99美元 = =) 如果想要长期使用,还是建议买 com 后缀的域名,更加正规一些,可以输入 laodade 来获得 1 美元的优惠(不知道现在还有没有) namesilo 自带隐私保护,咕咕一直在用这家,价格也是这些注册商里面比较低的,关键是他家不像其他家域名注册商,没有七七八八的套路!(就是后台界面有些 丑 古老 = =) 【域名购买】Namesilo 优惠码和域名解析教程(附带服务器购买推荐和注意事项) 我们接着往下看! 7. 反向代理 7.1 利用 Nginx Proxy Manager 在添加反向代理之前,确保你已经完成了域名解析,不会的可以看这个:域名一枚,并做好解析到服务器上(域名购买、域名解析 视频教程) (名称改成你自己想要的域名前缀即可) 之后,登陆 Nginx Proxy Manager(不会的看这个:安装 Nginx Proxy Manager(相关教程)) 注意: Nginx Proxy Manager(以下简称 NPM)会用到 80、443 端口,所以本机不能占用(比如原来就有 Nginx) 直接丢几张图: 注意填写对应的 域名、IP 和 端口,按文章来的话,应该是 3000 IP 填写: 如果 Nginx Proxy Manager 和 magic-resume 在同一台服务器上,可以在终端输入: ip addr show docker0 查看对应的 Docker 容器内部 IP。 否则直接填 magic-resume 所在的服务器 IP 就行。 然后访问域名就可以访问了! 7.2 利用宝塔面板 发现还是有不少小伙伴习惯用宝塔面板,这边也贴一个宝塔面板的反代配置: 直接新建一个站点,不要数据库,不要 php,纯静态即可。 然后打开下面的配置,修改 Nginx 的配置。 代码如下: location / { proxy_pass http://127.0.0.1:3000/; # 注意改成你实际使用的端口 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% 的反向代理都能生效,然后就可以用域名来安装访问了。 有同学可能会问,为什么不直接用宝塔自带的反向代理功能。 也可以,不过咕咕自己之前遇到过当有多个网站需要反代的时候,在这边设置会报错的情况 = = 所以后来就不用了,直接用上面的方法来操作了。 8. 使用教程 8.1 编辑简历 见视频或者自己琢磨一下,很简单。 8.2 更新 magic-resume 这个项目后续应该也会有更新,所以提供一个更新的方式。 cd /root/data/docker_data/magic-resume 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.3 卸载 magic-resume 同样进入安装页面,先停止所有容器。 cd /root/data/docker_data/magic-resume docker compose down cd .. rm -rf /root/data/docker_data/magic-resume # 完全删除 可以卸载得很干净。 9. 常见问题及注意点 咕咕个人感觉完成度已经挺高了,AI模型目前暂时只支持豆包和deepseek,后续可以考虑加入自定义或者海外的几个模型,走向国际化! 大家有问题欢迎评论区交流。 10. 结尾 祝大家用得开心,有问题可以去 GitHub 提 Issues,也可以在评论区互相交流探讨。 同时,有能力给项目做贡献的同学,也欢迎积极加入到 项目 中来,贡献自己的一份力量! 最后,感谢作者@JOYCEQL的辛苦付出,让我们能用到这么优秀的项目!欢迎大家都去给这个项目点个 star ⭐️ 参考资料 官方GitHub:https://github.com/JOYCEQL/magic-resume

2025/3/14
articleCard.readMore

性价比神机!BandwagonHost 上新 MEGABOX PRO 套餐,AMD处理器 2T流量,三网线路优化!

2025年3月11日14:09分,已经卖完了 = = 今天搬瓦工推出了一款性价比非常高的机器,这边和大家分享一下。 📦 搬瓦工上新 MEGABOX PRO 限量套餐,位于美国洛杉矶(DC1)数据中心,当前回程为电信/联通 CN2 GIA 线路,移动 CMIN2 线路。 CPU: 2 AMD vCore 49.00/年(优惠后 45.68/年) BWHCGLUKKB (6.77%) https://gao.ee/megaboxpro 此前购买 BiggerBox Pro 的用户可后台补差价升级至该套餐。大家可以根据自己需要升级(直接升级貌似会贵2刀)或者再买一个。(之前的流量使用不到10%可以申请退款) 我已经购入一台: 服务器综合测试 测试脚本: export noninteractive=true && curl -L https://cdn.spiritlhl.net/https://raw.githubusercontent.com/oneclickvirt/ecs/master/goecs.sh -o goecs.sh && chmod +x goecs.sh && bash goecs.sh env && bash goecs.sh install && goecs 测试详情URL:https://paste.spiritlhl.net/#/show/NzPRc.txt

2025/3/11
articleCard.readMore

十分钟搭建一个带Web界面的yt-dlp视频下载器|好玩儿的Docker项目

1. 唠嗑 yt-dlp 是一款基于 youtube-dl 开发的开源命令行视频下载工具,支持从 1000+ 个平台获取内容。它不仅能下载 YouTube 视频,还支持包括 B站、网易云音乐、Vimeo、Twitter 等主流平台。 2. ytdlpwebui主要功能 这是一个基于 yt-dlp 的自托管 Web UI 和 RPC 服务项目,专为 NAS 和服务器环境设计。项目通过 Docker 容器提供轻量级部署(镜像体积仅 18MB),支持以下核心功能: 多平台视频下载:支持 YouTube、B站等 1000+ 平台的视频/音频下载,可自动选择最高画质或手动指定格式 任务队列管理:通过 --qs 参数控制并发下载数量(默认 2 个并行任务) 远程控制接口:提供 JSON-RPC 1.0 API 和 WebSocket 实时状态推送,支持 JWT 认证(需配置 --auth 参数) 定制化前端:允许替换默认 Material 风格界面,自定义前端只需符合指定目录结构即可加载 系统集成:提供 Docker Compose 部署模板和 Systemd 服务配置方案,支持 SQLite 数据库存储任务记录 典型应用场景包括 NAS 媒体库自动归档、直播流监控等,项目通过 --driver 参数可指定不同版本的 yt-dlp 执行文件,最新版本已适配 2025 年 YouTube 的 HDR10+ 格式下载需求。 3. 相关地址 官方GitHub地址:https://github.com/marcopiovanello/yt-dlp-web-ui (全新项目,目前1.1个star,欢迎大家去给项目点星星!) 4. 搭建环境 服务器:这边强烈建议用非大陆的服务器,不然很多网站访问不了,咕咕这边用的香港的腾讯云轻量应用服务器,建议服务器内存1G以上,当然你也可以选择其他高性价比的服务器。 系统:Debian 11 (DD 脚本 非必需 DD,用原来的系统也 OK,之后教程都是用 Debian 或者 Ubuntu 搭建~) 安装好 Docker、Docker-compose(相关脚本) 【必需】域名一枚,并做好解析到服务器上(域名购买、域名解析 视频教程) 【非必需】提前安装好宝塔面板海外版本 aapanel,并安装好 Nginx(安装地址) 【非必需本教程选用】安装好 Nginx Proxy Manager(相关教程) 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/ytdlpwebui cd /root/data/docker_data/ytdlpwebui mkdir config cd config vim config.yml 这边我们用最简单的认证方式(更多认证方式,可以参考官方的wiki),粘贴填入这些内容,其中your_username改成你自己的登录名字,your_password改成你的密码。 require_auth: true username: your_username password: your_password 完成之后,按一下 esc,然后 :wq 保存退出。 接着我们来编辑下docker-compose.yml cd .. vim docker-compose.yml services: yt-dlp-webui: image: marcobaobao/yt-dlp-webui ports: - 3035:3033 volumes: - ./downloads:/downloads # replace <your dir> with a directory on your host system - ./config:/config # directory where config.yml will be stored healthcheck: test: curl -f http://localhost:3033 || exit 1 restart: unless-stopped 其中的3035可以改成服务器上没有用过的端口,记得修改自己的用户名和密码,修改完成之后,可以在英文输入法下,按 i 修改,完成之后,按一下 esc,然后 :wq 保存退出。 6.3 查看端口是否被占用 查看端口是否被占用(以 3035 为例),输入: lsof -i:3035 #查看 3035 端口是否被占用,如果被占用,重新自定义一个端口 如果啥也没出现,表示端口未被占用,我们可以继续下面的操作了~ 如果出现: -bash: lsof: command not found 运行: apt install lsof #安装 lsof 如果端口没有被占用(被占用了就修改一下端口,比如改成 8381,注意 docker 命令行里和防火墙都要改) 6.4 启动 ytdlpwebui cd /root/data/docker_data/ytdlpwebui docker compose up -d # 注意,老版本用户用 docker-compose up -d 耐心等待拉取好镜像,出现 done的字样之后, 理论上我们就可以输入 http://ip:3035 访问了。 但是这边这个服务必须先搞一下反向代理!http使用明文传输太危险,我们部署在公网一定要考虑使用反向代理工具配置SSL! 做反向代理前,你需要一个域名! namesilo 上面 xyz 后缀的域名一年就 7 块钱,可以年抛。(冷知识,namesilo上 6位数字的xyz续费永远都是0.99美元 = =) 如果想要长期使用,还是建议买 com 后缀的域名,更加正规一些,可以输入 gugugu 来获得 1 美元的优惠(不知道现在还有没有) namesilo 自带隐私保护,咕咕一直在用这家,价格也是这些注册商里面比较低的,关键是他家不像其他家域名注册商,没有七七八八的套路!(就是后台界面有些 丑 古老 = =) 【域名购买】Namesilo 优惠码和域名解析教程(附带服务器购买推荐和注意事项) 我们接着往下看! 7. 反向代理 7.1 利用 Nginx Proxy Manager 在添加反向代理之前,确保你已经完成了域名解析,不会的可以看这个:域名一枚,并做好解析到服务器上(域名购买、域名解析 视频教程) (名称改成你自己想要的域名前缀即可) 之后,登陆 Nginx Proxy Manager(不会的看这个:安装 Nginx Proxy Manager(相关教程)) 注意: Nginx Proxy Manager(以下简称 NPM)会用到 80、443 端口,所以本机不能占用(比如原来就有 Nginx) 直接丢几张图: 注意填写对应的 域名、IP 和 端口,按文章来的话,应该是 3035 IP 填写: 如果 Nginx Proxy Manager 和 ytdlpwebui 在同一台服务器上,可以在终端输入: ip addr show docker0 查看对应的 Docker 容器内部 IP。 否则直接填 ytdlpwebui 所在的服务器 IP 就行。 7.2 利用宝塔面板 发现还是有不少小伙伴习惯用宝塔面板,这边也贴一个宝塔面板的反代配置: 直接新建一个站点,不要数据库,不要 php,纯静态即可。 然后打开下面的配置,修改 Nginx 的配置。 代码如下: location / { proxy_pass http://127.0.0.1:3035/; # 注意改成你实际使用的端口 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% 的反向代理都能生效,然后就可以用域名来安装访问了。 有同学可能会问,为什么不直接用宝塔自带的反向代理功能。 也可以,不过咕咕自己之前遇到过当有多个网站需要反代的时候,在这边设置会报错的情况 = = 所以后来就不用了,直接用上面的方法来操作了。 8. 使用教程 8.1 下载视频 见视频或者自己琢磨一下,很简单。 输入网址之后,提示需要登录才可以使用,输入我们前面设置的账号密码 首页是这个样子, 设置部分,支持把语言改成中文的, 选一个YouTube视频,可以尝试下载, 下载成功之后,可以选择点击观看或者下载到本地观看了。 8.2 更新 ytdlpwebui 这个项目后续应该也会有更新,所以提供一个更新的方式。 cd /root/data/docker_data/ytdlpwebui 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.3 卸载 ytdlpwebui 同样进入安装页面,先停止所有容器。 cd /root/data/docker_data/ytdlpwebui docker compose down cd .. rm -rf /root/data/docker_data/ytdlpwebui # 完全删除 可以卸载得很干净。 9. 常见问题及注意点 目前发现推特和哔哩哔哩的视频下载完成之后会显示0B, 大家有问题欢迎评论区交流。 10. 结尾 祝大家用得开心,有问题可以去 GitHub 提 Issues,也可以在评论区互相交流探讨。 同时,有能力给项目做贡献的同学,也欢迎积极加入到 项目 中来,贡献自己的一份力量! 最后,感谢开发人员们的辛苦付出,让我们能用到这么优秀的项目! 参考资料 官方GitHub:https://github.com/marcopiovanello/yt-dlp-web-ui

2025/2/20
articleCard.readMore

用M1 Max MacBook Pro私有化部署DeepSeek-R1

早在去年5月份,我们就和大家介绍过完全免费,离线可用!用LobeChat+Ollama搭建本地大模型 最近DeepSeek非常火,用的人太多,服务器负载过高,导致官方服务基本处于不可用状态…… 既然DeepSeek是开源模型,那么,我们也来本地化部署一个。 什么是 DeepSeek-R1 ? DeepSeek-R1 是 DeepSeek 的第一代推理模型,在数学、代码和推理任务中,其性能与 OpenAI-o1 相当(而OpenAI是闭源的),包括基于 Llama 和 Qwen 的六个从 DeepSeek-R1 蒸馏出的密集模型。 其中 671b 是教师模型(Teacher Model), 另外的 6 个蒸馏模型为学生模型(Student Model) 1.5b:全称是 DeepSeek-R1-Distill-Qwen-1.5B,蒸馏模型源自 Qwen-2.5 系列; 7b:是 DeepSeek-R1-Distill-Qwen-7B,蒸馏模型源自 Qwen-2.5 系列; 8b:是 DeepSeek-R1-Distill-Llama-8B,蒸馏模型源自 Llama3.1-8B-Base; 14b:是 DeepSeek-R1-Distill-Qwen-14B,蒸馏模型源自 Qwen-2.5 系列; 32b:是 DeepSeek-R1-Distill-Qwen-32B,蒸馏模型源自 Qwen-2.5 系列; 70b:是 DeepSeek-R1-Distill-Llama-70B,蒸馏模型源自 Llama3.3-70B-Instruct; 什么是蒸馏 ? 蒸馏技术(Distillation)是一种模型压缩和优化的方法,主要用于将一个大型、复杂的模型的知识转移到一个较小的模型中。这个过程通常被称为“知识蒸馏”(Knowledge Distillation) 模型选择 我们需要根据硬件的性能以及实际的需求来选择不同参数大小的模型: ollama run deepseek-r1:1.5b ollama run deepseek-r1:7b ollama run deepseek-r1:8b ollama run deepseek-r1:14b 没有配备专业级显卡的,推荐用14B以内的模型。 deepseek-r1:1.5b CPU: 任何现代CPU(10年内的型号) RAM: 最低8GB GPU: 不需要专用GPU 存储: 至少20GB可用空间,推荐SSD 这个模型对硬件要求最低,适合基础任务如简单写作和快速对话。 deepseek-r1:7b CPU: 4核或以上(如Intel i5/Ryzen 5) RAM: 至少16GB GPU: NVIDIA RTX 3070 8GB或更高 存储: 至少20GB可用空间,推荐SSD 适用于一般推理、较长文本生成和简单编码任务。 deepseek-r1:8b 硬件要求与7b模型相近: CPU: 4核或以上 RAM: 至少16GB GPU: NVIDIA RTX 3070 8GB或更高 存储: 至少20GB可用空间,推荐SSD deepseek-r1:14b CPU: 6核或以上(如Intel i7/Ryzen 7) RAM: 至少32GB GPU: NVIDIA RTX 3080 10GB或更高,推荐NVIDIA A4000 16GB 存储: 至少20GB可用空间,推荐SSD 这个模型适合更深入的推理、编码和研究任务。 ollama run deepseek-r1:32b ollama run deepseek-r1:70b ollama run deepseek-r1:671b 32b,70b,671b对机器的要求如下: DeepSeek-R1-Distill-Qwen-32B VRAM需求:约14.9GB 推荐GPU配置:NVIDIA RTX 4090 24GB RAM:建议至少32GB DeepSeek-R1-Distill-Llama-70B VRAM需求:约32.7GB 推荐GPU配置:NVIDIA RTX 4090 24GB × 2 RAM:建议48GB以上 DeepSeek-R1 671B(完整模型) VRAM需求:约1,342GB(使用FP16精度) 推荐GPU配置:多GPU设置,例如NVIDIA A100 80GB × 16 RAM:512GB以上 存储:500GB以上高速SSD 需要注意的是,对于671B模型: 通常需要企业级或数据中心级硬件来管理其巨大的内存和计算负载。 使用量化技术可以显著降低VRAM需求。例如,使用4位量化后,模型大小可降至约404GB。 使用动态量化技术,可以进一步降低硬件需求,将大部分参数量化到1.5-2.5位,使模型大小降至212GB-131GB之间。 对于本地部署,可能需要考虑使用多台高性能工作站或服务器,如使用多个Mac Studio(M2 Ultra,192GB RAM)来满足内存需求。 运行完整671B模型时,还需考虑功耗(可能高达10kW)和散热等问题。 总的来说,32B和70B模型可以在高端消费级硬件上运行,而671B模型则需要企业级或数据中心级的硬件配置。选择合适的硬件配置时,还需考虑具体的使用场景、性能需求和预算限制。 咕咕的Mac配置如下: 由于M系列MacBook采用统一内存架构,这意味着CPU和GPU可以共享同一内存池。这种设计减少了数据在不同处理单元之间传输的需要,从而可以显著提高大型数据集处理的速度和效率。 所以,理论上我可以在本地跑DeepSeek-R1-Distill-Qwen-32B,一会儿我们来试试! 下载安装Ollama 官方网站:https://ollama.com/ 其实这个也可以用Docker来装,但是既然给了安装版,我们就直接到官网下载即可。 什么是Ollama? Ollama 是一个便于本地部署和运行大型语言模型(Large Language Models, LLMs)的工具。使用通俗的语言来说,如果你想在自己的电脑上运行如 GPT-3 这样的大型人工智能模型,而不是通过互联网连接到它们,那么 Ollama 是一个实现这一目标的工具。 Ollama支持非常多的开源模型,比如: 更多支持的模型可以看这边:https://ollama.com/library 当然它还支持自定义模型,这边就不深入了,有兴趣的可以研究:https://github.com/ollama/ollama 装好之后,直接像打开APP一样打开, 或者命令行运行: ollama -v 查看到版本号说明安装好了。 接下来我们下载一个deepseek-r1:32b的模型:(这边大家按照自己电脑的实际配置情况,结合上面不同参数模型对应的电脑配置来选择合适大小参数的模型进行安装) ollama run deepseek-r1:32b 这边可能需要比较长的时间,取决于你的网速。 下载好了就可以进行交互了: /? 可以查看帮助: /bye 可以退出 我们来问几个其他问题。 在问问题之前,Ollama官方提供了计算推理速度的工具,只要在聊天窗口输入/set verbose就能使其在每次回复后自动输出运行速度。 emm,换个问题, 8.34 tokens/s 还是基本一个可用的状态, 但是32B显然还是不够犀利,贴一个满血版本的回答: 其实到这里,我们现在已经搞定了,你可以让它帮你干活了,但是每次都要用命令行,有些人觉得不方便,而且也不能给别人用,下面我们就给它搞一个图形化界面,扩展一下功能,也能让局域网里的其他小伙伴也用上你的这个模型(注意多人同时访问会导致机器负载飙升,具体取决于你机器的性能和模型参数的大小) 安装浏览器插件——Page Assist 除了在命令行里运行Ollama,我们可以使用一个名为Page Assist的浏览器插件,这款插件可以让我们能够在浏览器页面运行我们的本地大模型。 你可以通过访问Chrome插件链接直接安装, 也可以通过 Page Assist的GitHub界面所述的步骤进行安装。 安装好插件后,就可以设置下 Ollama 的模型, 设置好相应的地址后就可以保存了,这样就可以使用相应的模型进行问答了。 如果有很多的模型,也可以在管理模型中进行管理和添加。 为了更好的使用模型,我们也可以增加自己的知识库,在使用知识库之前需要进行RAG 设置。 我选择了snowflake-arctic-embed2的 embedded 模型, ollama pull snowflake-arctic-embed2 当然也可以选择推荐的模型,如果没有,可以到管理模型中添加。 完成后就可以通过管理知识进行知识库的添加。 然后就可以打开界面选择模型进行对话了。 Page Assist还有一些其他的功能,比如管理知识,管理提示词等等,大家可以自行研究一下,重要的是,现在我们使用起来更直观一些了! Page Assist侧边栏功能 在任意一个网页,选中 Page Assist 插件点右键菜单,启动 侧边栏 勾选 与当前页面聊天 可以向模型提问,比如让模型总结一下页面的内容, 7B还是不够聪明,我们换32B再试试看: 这个效果就好多了。 好了,那就简单介绍这么多,有兴趣的小伙伴可以动手尝试起来了!

2025/2/11
articleCard.readMore

十分钟搭建一个跨平台剪贴板同步方案—— SyncClipboard!支持Windows/Linux/macOS/Android/IOS|好玩儿的Docker项目

1. 唠嗑 咕咕目前主要用的都是苹果生态的设备,登录了同一个Apple账号之后,是可以实现电脑复制,手机粘贴内容的,反之亦然。相信安卓也有类似的功能。 但是仍有不少小伙伴是安卓和苹果混用的,甚至是windows和Linux混用的,有没有一个方案可以也实现跨设备之间也粘贴同步呢? 今天介绍的SyncClipboard就是要实现这个功能的,感谢@chin的推荐。 2. SyncClipboard主要功能( 抄 来自官方GitHub) 剪贴板同步,支持文字、图片和文件。服务器/客户端架构,可以使用客户端内置服务器、独立部署服务器,也可以使用支持WebDAV的网盘作为服务器 优化图片类型的剪贴板,功能有: 从任意位置复制图片时,可以直接向文件系统粘贴图片文件,反之亦然 从浏览器复制图片后,后台下载原图到本地,解决无法从浏览器拷贝动态图的问题(大多网站有认证,适用范围有限,支持bilibili动态图片) 从文件系统复制较新格式类型的图片文件时(webp/heic等),在剪贴板内储存gif或jpg格式,用于直接向支持图片的文本框粘贴图片 3. 相关地址 官方GitHub地址:https://github.com/Jeric-X/SyncClipboard (全新项目,目前1.9个star,欢迎大家去给项目点星星!) 4. 搭建环境 服务器:咕咕这边用的腾讯云轻量应用服务器,建议服务器内存1G以上,当然你也可以选择其他高性价比的服务器。 系统:Debian 11 (DD 脚本 非必需 DD,用原来的系统也 OK,之后教程都是用 Debian 或者 Ubuntu 搭建~) 安装好 Docker、Docker-compose(相关脚本) 【必需】域名一枚,并做好解析到服务器上(域名购买、域名解析 视频教程) 【非必需】提前安装好宝塔面板海外版本 aapanel,并安装好 Nginx(安装地址) 【非必需本教程选用】安装好 Nginx Proxy Manager(相关教程) 当然你也可以选择不自己搭服务器用客户端内置服务器(可能有小伙伴担心隐私问题),或者是WebDAV服务器。 可以使用支持WebDAV协议的网盘作为服务器 Nextcloud AList InfiniCLOUD aliyundrive-webdav 5. 搭建视频(过俩天补充 = =) 5.1 YouTube 视频地址:https://youtu.be/IR2FLA0skro 5.2 哔哩哔哩 哔哩哔哩:https://www.bilibili.com/video/BV1RPwjewEks/ 6. 搭建方式 6.1 安装 Docker 与 Nginx Proxy Manager 可以直接参考这篇内容: https://blog.laoda.de/archives/nginxproxymanager/ 6.2 创建安装目录 创建一下安装的目录: sudo -i mkdir -p /root/data/docker_data/syncclipboard cd /root/data/docker_data/syncclipboard 接着我们来编辑下docker-compose.yml vim docker-compose.yml services: syncclipboard-server: image: jericx/syncclipboard-server:latest container_name: syncclipboard-server restart: unless-stopped ports: - "5133:5033" # 左边的5133可以改成服务器上没有用过的其他端口 environment: - SYNCCLIPBOARD_USERNAME=这里改成你的英文的用户名 - SYNCCLIPBOARD_PASSWORD=这个改成你的密码 其中的5133可以改成服务器上没有用过的端口,记得修改自己的用户名和密码,修改完成之后,可以在英文输入法下,按 i 修改,完成之后,按一下 esc,然后 :wq 保存退出。 6.3 查看端口是否被占用 查看端口是否被占用(以 5133 为例),输入: lsof -i:5133 #查看 5133 端口是否被占用,如果被占用,重新自定义一个端口 如果啥也没出现,表示端口未被占用,我们可以继续下面的操作了~ 如果出现: -bash: lsof: command not found 运行: apt install lsof #安装 lsof 如果端口没有被占用(被占用了就修改一下端口,比如改成 8381,注意 docker 命令行里和防火墙都要改) 6.4 启动 syncclipboard cd /root/data/docker_data/syncclipboard docker compose up -d # 注意,老版本用户用 docker-compose up -d 耐心等待拉取好镜像,出现 done的字样之后, 理论上我们就可以输入 http://ip:5133 访问了。 但是这边这个服务必须先搞一下反向代理!http使用明文传输太危险,我们部署在公网一定要考虑使用反向代理工具配置SSL! 做反向代理前,你需要一个域名! namesilo 上面 xyz 后缀的域名一年就 7 块钱,可以年抛。(冷知识,namesilo上 6位数字的xyz续费永远都是0.99美元 = =) 如果想要长期使用,还是建议买 com 后缀的域名,更加正规一些,可以输入 laodade 来获得 1 美元的优惠(不知道现在还有没有) namesilo 自带隐私保护,咕咕一直在用这家,价格也是这些注册商里面比较低的,关键是他家不像其他家域名注册商,没有七七八八的套路!(就是后台界面有些 丑 古老 = =) 【域名购买】Namesilo 优惠码和域名解析教程(附带服务器购买推荐和注意事项) 我们接着往下看! 7. 反向代理 7.1 利用 Nginx Proxy Manager 在添加反向代理之前,确保你已经完成了域名解析,不会的可以看这个:域名一枚,并做好解析到服务器上(域名购买、域名解析 视频教程) (名称改成你自己想要的域名前缀即可) 之后,登陆 Nginx Proxy Manager(不会的看这个:安装 Nginx Proxy Manager(相关教程)) 注意: Nginx Proxy Manager(以下简称 NPM)会用到 80、443 端口,所以本机不能占用(比如原来就有 Nginx) 直接丢几张图: 注意填写对应的 域名、IP 和 端口,按文章来的话,应该是 5133 IP 填写: 如果 Nginx Proxy Manager 和 SyncClipboard 在同一台服务器上,可以在终端输入: ip addr show docker0 查看对应的 Docker 容器内部 IP。 否则直接填 syncclipboard 所在的服务器 IP 就行。 7.2 利用宝塔面板 发现还是有不少小伙伴习惯用宝塔面板,这边也贴一个宝塔面板的反代配置: 直接新建一个站点,不要数据库,不要 php,纯静态即可。 然后打开下面的配置,修改 Nginx 的配置。 代码如下: location / { proxy_pass http://127.0.0.1:5133/; # 注意改成你实际使用的端口 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% 的反向代理都能生效,然后就可以用域名来安装访问了。 有同学可能会问,为什么不直接用宝塔自带的反向代理功能。 也可以,不过咕咕自己之前遇到过当有多个网站需要反代的时候,在这边设置会报错的情况 = = 所以后来就不用了,直接用上面的方法来操作了。 8. 使用教程 8.1 登陆使用(以安卓和IOS为例子) 这边我手头没有window电脑,我演示一下安卓和IOS如何互通粘贴板。 安卓配置 安卓下载一个APP——HTTP Request Shortcuts 可以直接在谷歌应用商店搜索下载:https://play.google.com/store/apps/details?id=ch.rmy.android.http_shortcuts 也可以在F-Droid下载:https://f-droid.org/en/packages/ch.rmy.android.http_shortcuts/ 或者直接GitHub上下载:https://github.com/Waboodoo/HTTP-Shortcuts/releases HTTP Request Shortcuts的GitHub仓库:https://github.com/Waboodoo/HTTP-Shortcuts 手机上下载,导入这个配置文件, 这个是个压缩包,解压之后是个json文件,然后一会儿上传到HTTP Request Shortcuts里面即可。 不方便下载的,咕咕这边留一个网盘的地址,大家可以在这边下载:https://share.gugu.ovh/local/%E5%85%AC%E5%85%B1%E6%96%87%E4%BB%B6%E5%A4%B9/Docker%E9%A1%B9%E7%9B%AE/SyncClipboard json的内容是这个: { "categories": [ { "id": "accb6a5b-60a3-4ba5-921a-f9cd772067aa", "name": "快捷方式", "shortcuts": [ { "authentication": "basic", "bodyContent": "{\"File\":\"\",\"Clipboard\":\"{{76b1e948-84b3-497e-8ec5-b911d00f8f0f}}\",\"Type\":\"Text\"}", "codeOnSuccess": "showToast(\u0027已上传\u0027);", "contentType": "application/json", "description": "支持选中文字后分享", "iconName": "freepik_upload", "id": "d6a958cb-3fa6-4c79-b342-229008bfac8a", "method": "PUT", "name": "上传剪贴板", "password": "{{9421719b-086f-4799-8432-158b84b6e05a}}", "proxy": "", "quickSettingsTileShortcut": true, "responseHandling": { "successOutput": "none" }, "url": "{{136751b5-5f38-49fc-81dc-80a825804203}}/SyncClipboard.json", "username": "{{719f997c-6bf6-458f-a148-3c2a8ac5e405}}" }, { "authentication": "basic", "codeOnSuccess": "const profile \u003d JSON.parse(response.body)\r\nconst type \u003d profile.Type\r\n\r\nif (type \u003d\u003d \u0027Text\u0027) {\r\n const ClibboardText \u003d profile.Clipboard;\r\n copyToClipboard(ClibboardText);\r\n showToast(\u0027已拷贝\\n\u0027 + ClibboardText);\r\n\r\n const httpstr \u003d httpString(ClibboardText);\r\n\r\n if (httpstr) {\r\n if (confirm(\u0027包含网址,是否打开\u0027)) {\r\n openUrl(httpstr[0]);\r\n }\r\n }\r\n}\r\nelse if (profile.File \u0026\u0026 profile.File.length \u003e 0) {\r\n const downloadUrl \u003d getVariable(/*[variable]*/\"136751b5-5f38-49fc-81dc-80a825804203\"/*[/variable]*/) + \u0027/file/\u0027 + encodeURIComponent(profile.File)\r\n const inputPara \u003d { \u0027downloadUrl\u0027: downloadUrl }\r\n showToast(\u0027文件名已拷贝,正在下载\\n\u0027 + profile.File)\r\n copyToClipboard(profile.File)\r\n if (type \u003d\u003d \u0027Image\u0027 || isImageFile(profile.File)) {\r\n enqueueShortcut(/*[shortcut]*/\"1e693964-ab59-4e9c-902b-6b94b90ff2f0\"/*[/shortcut]*/, inputPara)\r\n } else {\r\n enqueueShortcut(/*[shortcut]*/\"1e693964-ab59-4e9c-902b-6b94b90ff2f0\"/*[/shortcut]*/, inputPara)\r\n }\r\n}\r\n\r\nfunction isImageFile(file) {\r\n const filename \u003d file.toLowerCase();\r\n const list \u003d [\r\n \u0027.png\u0027,\r\n \u0027.jpg\u0027,\r\n \u0027.jpeg\u0027,\r\n \u0027.gif\u0027,\r\n \u0027.bmp\u0027,\r\n \u0027.webp\u0027,\r\n ]\r\n let result \u003d false\r\n list.forEach(element \u003d\u003e {\r\n if (filename.endsWith(element)) {\r\n result \u003d true\r\n }\r\n })\r\n return result\r\n}\r\n\r\nfunction httpString(s) {\r\n var reg \u003d /(https?|http|ftp|file):\\/\\/[-A-Za-z0-9+\u0026@#/%?\u003d~_|!:,.;]+[-A-Za-z0-9+\u0026@#/%\u003d~_|]/g;\r\n s \u003d s.match(reg);\r\n return (s)\r\n}", "iconName": "freepik_download", "id": "91cf41c5-da0c-45b5-988c-9f636e135abd", "name": "下载剪贴板", "password": "{{9421719b-086f-4799-8432-158b84b6e05a}}", "proxy": "", "quickSettingsTileShortcut": true, "responseHandling": { "successOutput": "none" }, "url": "{{136751b5-5f38-49fc-81dc-80a825804203}}/SyncClipboard.json", "username": "{{719f997c-6bf6-458f-a148-3c2a8ac5e405}}" }, { "authentication": "basic", "bodyContent": "{\"File\":\"\",\"Clipboard\":\"{{76b1e948-84b3-497e-8ec5-b911d00f8f0f}}\",\"Type\":\"Text\"}", "codeOnPrepare": "setVariable(/*[variable]*/\"d12cab01-6d2b-44aa-a1fb-dfddc6fe7895\"/*[/variable]*/, selectedFiles[0].name);", "codeOnSuccess": "enqueueShortcut(\u0027上传文件 控制部分\u0027)", "contentType": "application/json", "description": "从分享菜单使用", "iconName": "freepik_upload", "id": "2b8e95a4-2ece-41a1-aace-f8f80c0497fb", "method": "PUT", "name": "上传文件", "password": "{{9421719b-086f-4799-8432-158b84b6e05a}}", "proxy": "", "requestBodyType": "file", "responseHandling": { "successOutput": "none" }, "url": "{{136751b5-5f38-49fc-81dc-80a825804203}}/file/{{d12cab01-6d2b-44aa-a1fb-dfddc6fe7895}}", "username": "{{719f997c-6bf6-458f-a148-3c2a8ac5e405}}" } ] }, { "id": "316553f3-4bb0-4e10-806b-0de26e10fb2a", "name": "基础组件", "shortcutClickBehavior": "edit", "shortcuts": [ { "authentication": "basic", "bodyContent": "{\"File\":\"{{d12cab01-6d2b-44aa-a1fb-dfddc6fe7895}}\",\"Clipboard\":\"\",\"Type\":\"File\"}", "codeOnSuccess": "showToast(\u0027已上传\u0027);", "contentType": "application/json", "iconName": "freepik_upload", "id": "2424dcac-6fa0-4ff9-849b-63a56d63c79f", "method": "PUT", "name": "上传文件 控制部分", "password": "{{9421719b-086f-4799-8432-158b84b6e05a}}", "proxy": "", "responseHandling": { "successOutput": "none" }, "url": "{{136751b5-5f38-49fc-81dc-80a825804203}}/SyncClipboard.json", "username": "{{719f997c-6bf6-458f-a148-3c2a8ac5e405}}" }, { "authentication": "basic", "bodyContent": "{\"File\":\"\",\"Clipboard\":\"{{76b1e948-84b3-497e-8ec5-b911d00f8f0f}}\",\"Type\":\"Text\"}", "contentType": "application/json", "description": "只支持2m以下文件", "iconName": "flat_color_folder", "id": "1e693964-ab59-4e9c-902b-6b94b90ff2f0", "name": "展示文件", "password": "{{9421719b-086f-4799-8432-158b84b6e05a}}", "proxy": "", "requestBodyType": "file", "responseHandling": { "actions": [ "share", "copy", "save" ] }, "url": "{{5989c421-2669-4424-80c3-69ba7995524a}}", "username": "{{719f997c-6bf6-458f-a148-3c2a8ac5e405}}" } ] } ], "compatibilityVersion": 71, "variables": [ { "id": "719f997c-6bf6-458f-a148-3c2a8ac5e405", "key": "UserName", "value": "ChangeIt" }, { "id": "9421719b-086f-4799-8432-158b84b6e05a", "key": "UserToken", "value": "ChangeIt" }, { "flags": 1, "id": "76b1e948-84b3-497e-8ec5-b911d00f8f0f", "jsonEncode": true, "key": "Clipboard", "type": "clipboard" }, { "id": "d12cab01-6d2b-44aa-a1fb-dfddc6fe7895", "jsonEncode": true, "key": "FileName", "value": "" }, { "id": "136751b5-5f38-49fc-81dc-80a825804203", "key": "url", "value": "ChangeIt" }, { "id": "5989c421-2669-4424-80c3-69ba7995524a", "key": "downloadUrl", "value": "" } ], "version": 75 } 修改变量中的UserName,UserToken,url, url不要以斜线分隔符/结尾。 HTTP Request Shortcuts支持从下拉菜单、桌面组件、桌面图标、分享菜单中使用。 IOS配置 官方给了很多选择: 使用快捷指令 手动同步,导入这个快捷指令,手动触发上传或下载 自动同步,导入这个快捷指令,运行后设备会自动在后台同步剪贴板内容,此快捷指令将执行无限时长,需要手动关闭,你还可以手动修改同步后是否发送系统通知、查询的间隔秒数 自动上传短信验证码,参考这个帖子中的视频教程 #60 我自己偏向于手动同步,所以导入了这个快捷指令,手动触发上传或下载。 记得修改一下这三个, 然后保持就可以了。 试试效果吧!亲测非常好用! WIndows, Linux, macOS客户端,Arch Linux还有其他安卓的方式,大家可以参考官方的文档:https://github.com/Jeric-X/SyncClipboard 为了避免有些小伙伴访问不了,我也粘贴一份在博客里: 桌面客户端(Windows/Linux/macOS)运行在后台时将自动同步剪贴板 Windows 下载地址:Release页面中的SyncClipboard.zip,解压缩后运行SyncClipboard.exe 依赖: .NET 6.0桌面运行时,未安装会弹窗提醒并跳转到微软官方下载页面 ASP.NET Core 6.0运行时,未安装会弹窗提醒并跳转到微软官方下载页面 Windows10 2004及以上 微软Segoe Fluent Icons图标字体,Windows11自带无需安装,Windows10需要手动下载安装(官方地址),否则界面图标会大范围出错 注意: 删除软件时,配置文件目录不会被删除,配置文件储存在%AppData%\SyncClipboard\,需要彻底删除软件时请手动删除整个目录 Linux, macOS 下载地址:SyncClipboard.Desktop,根据系统选择你需要的安装包 注意: 名称中带有no-self-contained:依赖.NET 6.0桌面运行时和ASP.NET Core 6.0运行时 名称中带有self-contained:通常可以直接运行 删除软件时,配置文件目录不会被删除,配置文件储存在~/.config/SyncClipboard/(Linux),~/Library/Application Support/SyncClipboard/(macOS),需要彻底删除软件时请手动删除整个目录 使用deb、rpm安装包时,每次更新版本需要先删除旧版,再安装新版,不支持直接更新 Linux: 快捷键在Wayland不可用 Linux: 无法自动识别语言,默认为英语 macOS: “SyncClipboard”已损坏,无法打开,在终端中执行sudo xattr -d com.apple.quarantine /Applications/SyncClipboard.app macOS: 快捷键依赖辅助功能权限(Accessibility),软件在需要时会弹窗提示(所有快捷键为空时则不需要),每个新版本需要重新授予权限 Arch Linux Arch Linux 用户可以直接从 AUR 安装: paru -Sy syncclipboard-desktop 安装后从菜单中启动即可,如果要从命令行中启动,请注意需要英文环境,即以 LANG=en_US.UTF-8 syncclipboard-desktop 来启动,启动后可以在软件内设置语言为中文。配置保存路径为:~/.config/SyncClipboard。 Android 使用HTTP Request Shortcuts 导入这个配置文件,修改变量中的UserName,UserToken,url, url不要以斜线分隔符/结尾。HTTP Request Shortcuts支持从下拉菜单、桌面组件、桌面图标、分享菜单中使用 使用Autox.js 自动同步,使用这个js文件。由于安卓系统限制,在安卓10及以上的系统应用无法在后台读取剪贴板,但可以使用基于Root权限的工具(Magisk/Xposed)解除应用后台读取剪贴版的权限,如Riru-ClipboardWhitelist、Clipboard Whitelist。由于在安卓13及以上的系统应用必须由用户手动授权才被允许访问系统日志(剪贴板),也可以使用Xposed自动为应用授权访问系统日志的权限,如DisableLogRequest/禁用日志访问请求 自动上传验证码,使用这个js文件,这个脚本运行在后台时将读取所有通知消息,在识别到验证码类信息时将证码上传到服务器 导入js文件、修改每个文件头部的用户配置后,手动点击运行,或者为每个js文件设置触发方式,例如:开机时触发 使用SmsForwarder 自动上传验证码, #109 使用Tasker https://github.com/forrestgao/taskerforSyncClipboard ,作者:forrestgao Tasker是一款安卓系统上非常强大的自动化工具软件,你可以根据SyncClipboard的API创建适合自己的配置文件,如果你认为你的配置文件非常通用并希望分享出来,欢迎联系我置于此处 客户端配置说明 全平台依赖三条必要配置(配置的拼写可能会有所不同,含义相同)。 user password url,格式为http(s)://ip(或者域名):port。使用WebDav服务器时,url需要具体到一个已存在的文件夹作为工作目录,例如https://domain.com/dav/folder1/working%20folder,特殊符号需要使用url转义字符代替,不要使用这个文件夹存储其他文件。不使用桌面客户端(Windows/Linux/macOS)时需在工作目录中再创建file文件夹以同步文件,桌面客户端会在设置服务器时自动创建file文件夹。url尽量不要以斜线分隔符/结尾,在部分客户端中会出现问题。 API API基于WebDAV,在独立服务器运行环境下设定环境变量ASPNETCORE_ENVIRONMENT为Development后运行服务器,或桌面客户端打开服务器并打开设置里的诊断模式后, 访问http://ip:端口/swagger/index.html可以打开API页面,以下是部分关键API 获取/上传剪贴板(文字) GET /SyncClipboard.json PUT /SyncClipboard.json 获取/上传剪贴板(图片/文件) GET /SyncClipboard.json HEAD /file/filename // optional GET /file/filename PUT /file/filename PUT /SyncClipboard.json SyncClipboard.json { "Type" : "Text" "Clipboard" : "Content", "File":"" } { "Type": "Image", // or "File", "Group" "Clipboard": "hash, optional", "File": "filename" } 8.2 更新 SyncClipboard 这个项目后续应该也会有更新,所以提供一个更新的方式。 cd /root/data/docker_data/syncclipboard 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.3 卸载 SyncClipboard 同样进入安装页面,先停止所有容器。 cd /root/data/docker_data/syncclipboard docker compose down cd .. rm -rf /root/data/docker_data/syncclipboard # 完全删除 可以卸载得很干净。 9. 常见问题及注意点 目前暂时没啥问题,大家有问题欢迎评论区交流。 10. 结尾 祝大家用得开心,有问题可以去 GitHub 提 Issues,也可以在评论区互相交流探讨。 同时,有能力给项目做贡献的同学,也欢迎积极加入到 项目 中来,贡献自己的一份力量! 最后,感谢开发人员们的辛苦付出,让我们能用到这么优秀的项目! 参考资料 官方GitHub:https://github.com/Jeric-X/SyncClipboard

2025/1/14
articleCard.readMore

更适合新手的 AI 口语对话练习应用—— BabelDuck |好玩儿的Docker项目

1. 唠嗑 随着国际形势的发展,英语的重要性越来越高,(比如开个美卡遇到问题和客服沟通都有问题) 听读能力我们普遍比较强,薄弱的往往是说写能力,而其中的”写“现在又可以用GPT来辅助了,所以这一期我们就来分享一个提高英语的“说“的能力的小工具——BabelDuck。 BabelDuck是一个面向各水平层次语言学习者的高度可定制化 AI 口语对话练习应用,并对初学者更友好,旨在将口语表达练习的门槛与心智负担降至最低。 2. babelduck主要功能( 抄 来自官方GitHub) 支持多对话管理、自定义系统提示词、流式响应等常见 AI 对话功能 可在不影响当前对话的前提下,向 AI 寻求语法、翻译或表达润色等建议,并提供可定制化的快捷指令 在对 AI 提供的建议有疑问时,可开启子对话进一步讨论,讨论结束后可无缝返回原对话 支持语音输入与语音输出,集成了浏览器内置文本转语音 以及 Azure TTS 集成多种 LLM AI 服务,支持自定义第三方 API 服务,可无缝切换(目前只支持OpenAI的API) 数据存储于本地,确保用户数据隐私安全 支持针对不同对话进行单独的偏好设置 提供多语言界面 内置使用教程 支持Docker部署,更新维护方便 🎯 未来规划 对话模板 复述练习模式 移动端适配 语音回放 支持多模态语音 接入更多 LLM/TTS/STT 服务 实时语音模式 更多指令类型 插件系统 3. 相关地址 官方GitHub地址:https://github.com/Orenoid/BabelDuck (全新项目,目前188个star,欢迎大家去给项目点星星!) 4. 搭建环境 服务器:咕咕这边用的莱卡云香港服务器,建议服务器内存1G以上,当然你也可以选择其他高性价比的服务器。 系统:Debian 11 (DD 脚本 非必需 DD,用原来的系统也 OK,之后教程都是用 Debian 或者 Ubuntu 搭建~) 安装好 Docker、Docker-compose(相关脚本) 【必需】域名一枚,并做好解析到服务器上(域名购买、域名解析 视频教程) 【非必需】提前安装好宝塔面板海外版本 aapanel,并安装好 Nginx(安装地址) 【非必需本教程选用】安装好 Nginx Proxy Manager(相关教程) 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/babelduck cd /root/data/docker_data/babelduck 接着我们来编辑下env文件 vim .env 输入下面的内容: # unforunately, the implementation of input handlers is coupled with openai at this time, # so openai or openai-compatible services are necessary here (json mode required), once we decouple it from openai (working on it), we can remove this OPENAI_CHAT_COMPLETION_URL= OPENAI_API_KEY= OPENAI_MODEL_NAME= # another unfortunate thing is that the stt feature is coupled with siliconflow for now, # so we need to provide the api url and api key as well, you can get the key from https://cloud.siliconflow.cn/account/ak # Also, once we decouple it from siliconflow (which has been on the roadmap), we can remove these two variables STT_API_URL=https://api.siliconflow.cn/v1/audio/transcriptions SILICONFLOW_API_KEY= 这边可以选择填入相应的API和模型,也可以选择直接保存退出,这样的话,后续在网页端自己填写相关API密钥,适合分享给其他人用。 我们这边就不填,一会儿去网页端填写。 接着我们来编辑下docker-compose.yml vim docker-compose.yml services: babel-duck: image: orenoid/babel-duck:latest container_name: babel-duck env_file: - .env ports: - "9001:9000" restart: unless-stopped 其中的9001可以改成服务器上没有用过的端口,修改完成之后,可以在英文输入法下,按 i 修改,完成之后,按一下 esc,然后 :wq 保存退出。 6.3 查看端口是否被占用 查看端口是否被占用(以 9001 为例),输入: lsof -i:9001 #查看 9001 端口是否被占用,如果被占用,重新自定义一个端口 如果啥也没出现,表示端口未被占用,我们可以继续下面的操作了~ 如果出现: -bash: lsof: command not found 运行: apt install lsof #安装 lsof 如果端口没有被占用(被占用了就修改一下端口,比如改成 8381,注意 docker 命令行里和防火墙都要改) 6.4 启动 babelduck cd /root/data/docker_data/babelduck docker compose up -d # 注意,老版本用户用 docker-compose up -d 耐心等待拉取好镜像,出现 done的字样之后, 理论上我们就可以输入 http://ip:9001 访问了。 但是这边这个服务必须先搞一下反向代理!不然会报错! 做反向代理前,你需要一个域名! namesilo 上面 xyz 后缀的域名一年就 7 块钱,可以年抛。(冷知识,namesilo上 6位数字的xyz续费永远都是0.99美元 = =) 如果想要长期使用,还是建议买 com 后缀的域名,更加正规一些,可以输入 laodade 来获得 1 美元的优惠(不知道现在还有没有) namesilo 自带隐私保护,咕咕一直在用这家,价格也是这些注册商里面比较低的,关键是他家不像其他家域名注册商,没有七七八八的套路!(就是后台界面有些 丑 古老 = =) 【域名购买】Namesilo 优惠码和域名解析教程(附带服务器购买推荐和注意事项) 我们接着往下看! 7. 反向代理 7.1 利用 Nginx Proxy Manager 在添加反向代理之前,确保你已经完成了域名解析,不会的可以看这个:域名一枚,并做好解析到服务器上(域名购买、域名解析 视频教程) (名称改成你自己想要的域名前缀即可) 之后,登陆 Nginx Proxy Manager(不会的看这个:安装 Nginx Proxy Manager(相关教程)) 注意: Nginx Proxy Manager(以下简称 NPM)会用到 80、443 端口,所以本机不能占用(比如原来就有 Nginx) 直接丢几张图: 注意填写对应的 域名、IP 和 端口,按文章来的话,应该是 9001 IP 填写: 如果 Nginx Proxy Manager 和 babelduck 在同一台服务器上,可以在终端输入: ip addr show docker0 查看对应的 Docker 容器内部 IP。 否则直接填 babelduck 所在的服务器 IP 就行。 7.2 利用宝塔面板 发现还是有不少小伙伴习惯用宝塔面板,这边也贴一个宝塔面板的反代配置: 直接新建一个站点,不要数据库,不要 php,纯静态即可。 然后打开下面的配置,修改 Nginx 的配置。 代码如下: location / { proxy_pass http://127.0.0.1:9001/; # 注意改成你实际使用的端口 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% 的反向代理都能生效,然后就可以用域名来安装访问了。 有同学可能会问,为什么不直接用宝塔自带的反向代理功能。 也可以,不过咕咕自己之前遇到过当有多个网站需要反代的时候,在这边设置会报错的情况 = = 所以后来就不用了,直接用上面的方法来操作了。 8. 使用教程 8.1 登陆使用 见视频或者自己摸索下 = = 这边logo裂开了...... 设置页面: 语音可以用浏览器内置TTS: 模型这边,可以填入自己的OpenAI API Key: 赶紧试试吧! 8.2 更新 babelduck 这个项目后续应该也会有更新,所以提供一个更新的方式。 cd /root/data/docker_data/babelduck 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.3 卸载 babelduck 同样进入安装页面,先停止所有容器。 cd /root/data/docker_data/babelduck docker compose down cd .. rm -rf /root/data/docker_data/babelduck # 完全删除 可以卸载得很干净。 9. 常见问题及注意点 logo的图片无法显示,暂时不知道啥情况 10. 结尾 祝大家用得开心,有问题可以去 GitHub 提 Issues,也可以在评论区互相交流探讨。 同时,有能力给项目做贡献的同学,也欢迎积极加入到 项目 中来,贡献自己的一份力量! 最后,感谢开发人员们的辛苦付出,让我们能用到这么优秀的项目! 参考资料 官方GitHub:https://github.com/Orenoid/BabelDuck

2024/12/17
articleCard.readMore

10分钟搭建一个本地化图片处理工具——Reubah,拒绝隐私泄露!|好玩儿的Docker项目

1. 唠嗑 日常工作的时候经常会遇到需要处理一些图片的问题(比如压缩图片,转换格式啊之类的),虽然网上随便一搜能搜索到很多可以直接使用的工具,但是会有小伙伴会担心隐私泄露。 这一期就和大家分享一个刚开发不久的可以自己搭建的方便处理文档/图片压缩,格式转换之类的小工具。 2. reubah主要功能 目前的功能特点: 开源免费,不存储你的数据 支持大多数的图片转换,压缩 Docker一键部署,方便升级和维护 支持部分文档的格式转换 支持批量处理 2.1 图片处理 1.11 MB压完之后是141.62 KB 压缩完的画质感觉差别不是很大: 背景去除的功能目前还在开发中, 2.2 文件处理 2.3 批量处理 3. 相关地址 官方GitHub地址:https://github.com/dendianugerah/reubah (全新项目,目前145个star,欢迎大家去给项目点星星!) 4. 搭建环境 服务器:咕咕这边用的莱卡云香港服务器,建议服务器内存1G以上,当然你也可以选择其他高性价比的服务器。 系统:Debian 11 (DD 脚本 非必需 DD,用原来的系统也 OK,之后教程都是用 Debian 或者 Ubuntu 搭建~) 安装好 Docker、Docker-compose(相关脚本) 【必需】域名一枚,并做好解析到服务器上(域名购买、域名解析 视频教程) 【非必需】提前安装好宝塔面板海外版本 aapanel,并安装好 Nginx(安装地址) 【非必需本教程选用】安装好 Nginx Proxy Manager(相关教程) 5. 搭建视频 5.1 YouTube 视频地址:https://youtu.be/NCQmIiiVRCE 5.2 哔哩哔哩 哔哩哔哩:https://www.bilibili.com/video/BV1fxkCYAERX/ 6. 搭建方式 6.1 安装 Docker 与 Nginx Proxy Manager 可以直接参考这篇内容: https://blog.laoda.de/archives/nginxproxymanager/ 6.2 创建安装目录 创建一下安装的目录: sudo -i mkdir -p /root/data/docker_data/reubah cd /root/data/docker_data/reubah 接着我们来编辑下docker-compose.yml vim docker-compose.yml services: reubah: image: ghcr.io/dendianugerah/reubah:latest ports: - "8082:8081" volumes: - ./tmp:/app/tmp - ./doc-temp:/tmp environment: - PORT=8081 restart: unless-stopped 8082可以改成服务器上没有用过的端口,修改完成之后,可以在英文输入法下,按 i 修改,完成之后,按一下 esc,然后 :wq 保存退出。 6.3 查看端口是否被占用 查看端口是否被占用(以 8082 为例),输入: lsof -i:8082 #查看 8082 端口是否被占用,如果被占用,重新自定义一个端口 如果啥也没出现,表示端口未被占用,我们可以继续下面的操作了~ 如果出现: -bash: lsof: command not found 运行: apt install lsof #安装 lsof 如果端口没有被占用(被占用了就修改一下端口,比如改成 8381,注意 docker 命令行里和防火墙都要改) 6.4 启动 reubah cd /root/data/docker_data/reubah docker compose up -d # 注意,老版本用户用 docker-compose up -d 这个镜像稍微有点大, 担心网络中断杀死任务,可以用我们之前介绍过的Screen这个工具——Linux实用工具 Screen ——再也不怕因为网络连接中断杀死任务了! 耐心等待拉取好镜像,出现 done的字样之后, 理论上我们就可以输入 http://ip:8082 访问了。 但是这边这个服务必须先搞一下反向代理!不然会报错! 做反向代理前,你需要一个域名! namesilo 上面 xyz 后缀的域名一年就 7 块钱,可以年抛。(冷知识,namesilo上 6位数字的xyz续费永远都是0.99美元 = =) 如果想要长期使用,还是建议买 com 后缀的域名,更加正规一些,可以输入 laodade 来获得 1 美元的优惠(不知道现在还有没有) namesilo 自带隐私保护,咕咕一直在用这家,价格也是这些注册商里面比较低的,关键是他家不像其他家域名注册商,没有七七八八的套路!(就是后台界面有些 丑 古老 = =) 【域名购买】Namesilo 优惠码和域名解析教程(附带服务器购买推荐和注意事项) 我们接着往下看! 7. 反向代理 7.1 利用 Nginx Proxy Manager 在添加反向代理之前,确保你已经完成了域名解析,不会的可以看这个:域名一枚,并做好解析到服务器上(域名购买、域名解析 视频教程) (名称改成你自己想要的域名前缀即可) 之后,登陆 Nginx Proxy Manager(不会的看这个:安装 Nginx Proxy Manager(相关教程)) 注意: Nginx Proxy Manager(以下简称 NPM)会用到 80、443 端口,所以本机不能占用(比如原来就有 Nginx) 直接丢几张图: 注意填写对应的 域名、IP 和 端口,按文章来的话,应该是 8082 IP 填写: 如果 Nginx Proxy Manager 和 reubah 在同一台服务器上,可以在终端输入: ip addr show docker0 查看对应的 Docker 容器内部 IP。 否则直接填 reubah 所在的服务器 IP 就行。 7.2 利用宝塔面板 发现还是有不少小伙伴习惯用宝塔面板,这边也贴一个宝塔面板的反代配置: 直接新建一个站点,不要数据库,不要 php,纯静态即可。 然后打开下面的配置,修改 Nginx 的配置。 代码如下: 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% 的反向代理都能生效,然后就可以用域名来安装访问了。 有同学可能会问,为什么不直接用宝塔自带的反向代理功能。 也可以,不过咕咕自己之前遇到过当有多个网站需要反代的时候,在这边设置会报错的情况 = = 所以后来就不用了,直接用上面的方法来操作了。 8. 使用教程 8.1 登陆使用 见视频 可以调整输出的图片格式: 也可以调整图片的质量: 分辨率也可以调整: 可以输出的文件格式: 把图片合并成PDF也可以: 8.2 更新 reubah 这个项目后续应该也会有更新,所以提供一个更新的方式。 cd /root/data/docker_data/reubah 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.3 卸载 reubah 同样进入安装页面,先停止所有容器。 cd /root/data/docker_data/reubah docker compose down cd .. rm -rf /root/data/docker_data/reubah # 完全删除 可以卸载得很干净。 9. 常见问题及注意点 去除背景的功能正常开放中,期待早日实现。 10. 结尾 祝大家用得开心,有问题可以去 GitHub 提 Issues,也可以在评论区互相交流探讨。 同时,有能力给项目做贡献的同学,也欢迎积极加入到 项目 中来,贡献自己的一份力量! 最后,感谢开发人员们的辛苦付出,让我们能用到这么优秀的项目! 参考资料 官方GitHub:https://github.com/dendianugerah/reubah

2024/12/12
articleCard.readMore

快速捕捉灵感!十分钟搭建一个轻量级笔记应用——Blinko|好玩儿的Docker项目

1. 唠嗑 今天和大家分享一个和之前的【好玩儿的Docker项目】10分钟搭建一个碎片化知识卡片管理工具——Memos 有点像的项目——Blinko。 官方介绍,Blinko 是一个创新的开源项目,旨在帮助那些希望快速捕捉和组织瞬间想法的个人。 无论你是在捕捉想法、记录会议笔记,还是规划日程,Blinko 都提供了一种简单高效的方式来管理这一切。 利用Blinko,你可以随时随地创建、编辑和分享笔记,确保不会丢失任何宝贵的想法。 在尝试了众多B后,作者意识到自己对笔记的需求其实非常简单: 快速创建 便捷的标签管理 批量操作 自动清理已审阅的想法 方便反思日常记录 最重要的是,能够快速找到特定的笔记,即使在积累了大量内容之后。这一洞察促成了Blinko的诞生。 Blinko的目标是帮助用户轻松捕捉和管理他们的想法,设计上分为两个核心部分:“Blinko”和“Notes”。 “Blinko(闪念)”部分旨在捕捉灵感闪现。用户可以即时记录突发奇想,而无需担心格式或复杂操作。这些记录可以设置为定期自动清除,以确保内容不会过度堆积,从而保持该部分整洁高效。 “Notes”部分提供更有组织性的管理系统,用户可以通过标签对笔记进行分类,并利用批量操作轻松整理和归类大量笔记。 为了帮助用户更有效地回顾和利用他们的笔记,Blinko还集成了一项AI驱动的搜索功能(目前仅支持OpenAI)。无论录入了多少内容,用户都可以依靠智能搜索在短时间内找到相关笔记,从而节省浏览时间。这不仅提高了信息查找效率,还根据关键词推荐相关记录,帮助用户发现其笔记中的隐藏联系和灵感。 Blinko设计背后的主要意图是简化笔记过程,让用户专注于内容本身,而不被繁琐的管理任务所困扰。无论是捕捉突如其来的灵感还是系统性地整理笔记,Blinko旨在提供一种智能、流畅的记录体验。 2. Blinko主要功能 目前的功能特点: AI 增强的笔记检索 🤖:借助 Blinko 先进的 AI 驱动的 RAG(检索增强生成),您可以使用自然语言查询快速搜索和访问您的笔记,使您轻松找到所需的内容。(目前只支持OpenAI的API) 数据所有权 🔒:您的隐私很重要。您所有的笔记和数据都安全地存储在您自托管的环境中,确保对您的信息完全控制。 高效且快速 🚀:即时捕捉想法并将其存储为纯文本,便于访问,支持完整的 Markdown 格式,便于快速格式化和无缝共享。 轻量级架构与重负载 💡: 基于 Next.js,Blinko 提供了一种流畅、轻量级的架构,能够在不牺牲速度或效率的情况下提供强大的性能。 开放合作 🔓:作为一个开源项目,Blinko 邀请社区的贡献。所有代码都是透明的,并且可以在 GitHub 上获取,促进了合作精神和持续改进。 完全免费 🎉:Blinko 是并将始终是免费的使用,没有隐藏费用或锁在付费墙后的高级功能。 后台概览: 每日回顾功能: 补充 RAG技术,全称为检索增强生成(Retrieval Augmented Generation),是一种用来改进大语言模型(如ChatGPT)输出质量的方法。用简单的语言来解释一下它是如何工作的: 知识库准备: 信息检索: 结合外部知识: 生成回答: RAG的主要优点包括: 更准确的回答:因为模型可以参考最新、最相关的信息。 减少"幻觉":大语言模型有时会产生看似合理但实际上并不正确的信息,RAG可以帮助减少这种情况。 知识更新:不需要重新训练整个模型,只需更新知识库就可以获取最新信息。 可追溯性:可以追踪答案的来源,知道信息是从哪里得来的。 简单来说,RAG就像是给AI配备了一个随时可查阅的"智能笔记本",让它在回答问题时能够参考更多、更新的信息,从而给出更好的回答。 3. 相关地址 官方GitHub地址:https://github.com/blinko-space/blinko (全新项目,目前20个star,欢迎大家去给项目点星星!) https://blinko-doc.vercel.app/intro.html https://blinko-demo.vercel.app/ 4. 搭建环境 服务器:咕咕这边用的莱卡云香港服务器,建议服务器内存1G以上,当然你也可以选择其他高性价比的服务器。 系统:Debian 11 (DD 脚本 非必需 DD,用原来的系统也 OK,之后教程都是用 Debian 或者 Ubuntu 搭建~) 安装好 Docker、Docker-compose(相关脚本) 【必需】域名一枚,并做好解析到服务器上(域名购买、域名解析 视频教程) 【非必需】提前安装好宝塔面板海外版本 aapanel,并安装好 Nginx(安装地址) 【非必需本教程选用】安装好 Nginx Proxy Manager(相关教程) 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/blinko cd /root/data/docker_data/blinko 接着我们来编辑下docker-compose.yml vim docker-compose.yml networks: blinko-network: driver: bridge services: blinko-website: image: blinkospace/blinko:latest container_name: blinko-website environment: NODE_ENV: production # NEXTAUTH_URL: http://localhost:1111 # IMPORTANT: If you want to use sso, you must set NEXTAUTH_URL to your own domain # NEXT_PUBLIC_BASE_URL: http://localhost:1111 # IMPORTANT: Replace this with your own secure secret key! NEXTAUTH_SECRET: RQhv8YZij5TibXCEicN80LoRO6J5NjbaZvKe7lYHhxQ= DATABASE_URL: postgresql://postgres:mysecretpassword@postgres:5432/postgres depends_on: postgres: condition: service_healthy # Make sure you have enough permissions. volumes: - ./.blinko:/app/.blinko restart: always logging: options: max-size: "10m" max-file: "3" ports: - 1111:1111 healthcheck: test: ["CMD", "wget", "--spider", "-q", "http://blinko-website:1111/"] interval: 30s timeout: 10s retries: 5 start_period: 30s networks: - blinko-network postgres: image: postgres:14 container_name: blinko-postgres restart: always ports: - 5435:5432 environment: POSTGRES_DB: postgres POSTGRES_USER: postgres POSTGRES_PASSWORD: mysecretpassword TZ: Asia/Shanghai # Persisting container data # Make sure you have enough permissions. volumes: - ./.db:/var/lib/postgresql/data healthcheck: test: ["CMD", "pg_isready", "-U", "postgres", "-d", "postgres"] interval: 5s timeout: 10s retries: 5 networks: - blinko-network NEXTAUTH_URL:指定应用程序的基本 URL,通常是已部署网站的根 URL,用于身份验证回调和重定向,一般保持默认http://localhost:1111即可 NEXT_PUBLIC_BASE_URL:定义应用程序的公共基础 URL,用作前端和 API 请求的基础路径。一般改成自己的最后访问的域名即可 NEXTAUTH_SECRET:用于加密会话和身份验证令牌的秘密密钥,确保用户数据安全。自己设置一个密码 DATABASE_URL:用于连接和访问blinko数据库的数据库连接URL。 同样,修改完成之后,可以在英文输入法下,按 i 修改,完成之后,按一下 esc,然后 :wq 保存退出。 6.3 查看端口是否被占用 查看端口是否被占用(以 3000 为例),输入: lsof -i:3000 #查看 3000 端口是否被占用,如果被占用,重新自定义一个端口 如果啥也没出现,表示端口未被占用,我们可以继续下面的操作了~ 如果出现: -bash: lsof: command not found 运行: apt install lsof #安装 lsof 如果端口没有被占用(被占用了就修改一下端口,比如改成 8381,注意 docker 命令行里和防火墙都要改) 6.4 启动 blinko cd /root/data/docker_data/blinko docker compose up -d # 注意,老版本用户用 docker-compose up -d 等待拉取好镜像,出现 done的字样之后, 理论上我们就可以输入 http://ip:3000 访问了。 但是这边这个服务必须先搞一下反向代理!不然会报错! 做反向代理前,你需要一个域名! namesilo 上面 xyz 后缀的域名一年就 7 块钱,可以年抛。(冷知识,namesilo上 6位数字的xyz续费永远都是0.99美元 = =) 如果想要长期使用,还是建议买 com 后缀的域名,更加正规一些,可以输入 laodade 来获得 1 美元的优惠(不知道现在还有没有) namesilo 自带隐私保护,咕咕一直在用这家,价格也是这些注册商里面比较低的,关键是他家不像其他家域名注册商,没有七七八八的套路!(就是后台界面有些 丑 古老 = =) 【域名购买】Namesilo 优惠码和域名解析教程(附带服务器购买推荐和注意事项) 我们接着往下看! 7. 反向代理 7.1 利用 Nginx Proxy Manager 在添加反向代理之前,确保你已经完成了域名解析,不会的可以看这个:域名一枚,并做好解析到服务器上(域名购买、域名解析 视频教程) (名称改成你自己想要的域名前缀即可) 之后,登陆 Nginx Proxy Manager(不会的看这个:安装 Nginx Proxy Manager(相关教程)) 注意: Nginx Proxy Manager(以下简称 NPM)会用到 80、443 端口,所以本机不能占用(比如原来就有 Nginx) 直接丢几张图: 注意填写对应的 域名、IP 和 端口,按文章来的话,应该是 3000 IP 填写: 如果 Nginx Proxy Manager 和 blinko 在同一台服务器上,可以在终端输入: ip addr show docker0 查看对应的 Docker 容器内部 IP。 否则直接填 blinko 所在的服务器 IP 就行。 7.2 利用宝塔面板 发现还是有不少小伙伴习惯用宝塔面板,这边也贴一个宝塔面板的反代配置: 直接新建一个站点,不要数据库,不要 php,纯静态即可。 然后打开下面的配置,修改 Nginx 的配置。 代码如下: location / { proxy_pass http://127.0.0.1:3000/; # 注意改成你实际使用的端口 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% 的反向代理都能生效,然后就可以用域名来安装访问了。 有同学可能会问,为什么不直接用宝塔自带的反向代理功能。 也可以,不过咕咕自己之前遇到过当有多个网站需要反代的时候,在这边设置会报错的情况 = = 所以后来就不用了,直接用上面的方法来操作了。 8. 使用教程 8.1 登录网页 登录页面, Sign Up, 成功登录, 切换语言, 闪念, 笔记, 资源, 有内容的情况: 手机端, 8.2 更新 blinko 这个项目后续应该也会有更新,所以提供一个更新的方式。 cd /root/data/docker_data/blinko 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.3 卸载 blinko 同样进入安装页面,先停止所有容器。 cd /root/data/docker_data/blinko docker compose down cd .. rm -rf /root/data/docker_data/blinko # 完全删除 可以卸载得很干净。 9. 常见问题及注意点 暂时没有禁止用户注册的功能。 10. 结尾 祝大家用得开心,有问题可以去 GitHub 提 Issues,也可以在评论区互相交流探讨。 同时,有能力给项目做贡献的同学,也欢迎积极加入到 项目 中来,贡献自己的一份力量! 最后,感谢开发人员们的辛苦付出,让我们能用到这么优秀的项目! 参考资料 官方GitHub:https://github.com/blinko-space/blinko

2024/11/11
articleCard.readMore