Docker Compose 部署 Dify + Ollama 全栈指南:从裸奔到安全可观测的 AI 应用实战
📌 摘要
本文以中国开发者视角出发,手把手教你用 Docker Compose 在本地或轻量云主机上部署 Dify + Ollama 组合栈,实现“安全、可观测、可扩展”的私有化 AI 应用平台。全文约 8 000 字,包含:
- 架构图、流程图、甘特图、思维导图等 6 种图表;
- 10+ 段可直接复制的 Python 示例代码;
- 5 大实战场景(RAG 知识库、代码助手、企业内部问答等);
- 常见 15 个“坑”及解决方案;
- 从裸奔到 HTTPS + Basic Auth + IP 白名单的完整安全加固方案。
读完即可在生产环境落地。
📖 目录
- 背景知识
- 整体架构
- 环境准备
- 一键部署
- 安全加固
- 可观测性
- 实战案例
- 常见问题 FAQ
- 扩展阅读
- 总结与展望
1️⃣ 背景知识 {#背景知识}
思维导图:为何选 Dify+Ollama?
mindmap root((选择 Dify+Ollama)) 数据不出内网 低成本 可插拔模型 社区活跃
2️⃣ 整体架构 {#整体架构}
2.1 逻辑架构图
#mermaid-svg-S1mAqkiJ8reOc7Y2 {font-family:\"trebuchet ms\",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-S1mAqkiJ8reOc7Y2 .error-icon{fill:#552222;}#mermaid-svg-S1mAqkiJ8reOc7Y2 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-S1mAqkiJ8reOc7Y2 .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-S1mAqkiJ8reOc7Y2 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-S1mAqkiJ8reOc7Y2 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-S1mAqkiJ8reOc7Y2 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-S1mAqkiJ8reOc7Y2 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-S1mAqkiJ8reOc7Y2 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-S1mAqkiJ8reOc7Y2 .marker.cross{stroke:#333333;}#mermaid-svg-S1mAqkiJ8reOc7Y2 svg{font-family:\"trebuchet ms\",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-S1mAqkiJ8reOc7Y2 .label{font-family:\"trebuchet ms\",verdana,arial,sans-serif;color:#333;}#mermaid-svg-S1mAqkiJ8reOc7Y2 .cluster-label text{fill:#333;}#mermaid-svg-S1mAqkiJ8reOc7Y2 .cluster-label span{color:#333;}#mermaid-svg-S1mAqkiJ8reOc7Y2 .label text,#mermaid-svg-S1mAqkiJ8reOc7Y2 span{fill:#333;color:#333;}#mermaid-svg-S1mAqkiJ8reOc7Y2 .node rect,#mermaid-svg-S1mAqkiJ8reOc7Y2 .node circle,#mermaid-svg-S1mAqkiJ8reOc7Y2 .node ellipse,#mermaid-svg-S1mAqkiJ8reOc7Y2 .node polygon,#mermaid-svg-S1mAqkiJ8reOc7Y2 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-S1mAqkiJ8reOc7Y2 .node .label{text-align:center;}#mermaid-svg-S1mAqkiJ8reOc7Y2 .node.clickable{cursor:pointer;}#mermaid-svg-S1mAqkiJ8reOc7Y2 .arrowheadPath{fill:#333333;}#mermaid-svg-S1mAqkiJ8reOc7Y2 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-S1mAqkiJ8reOc7Y2 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-S1mAqkiJ8reOc7Y2 .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-svg-S1mAqkiJ8reOc7Y2 .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-svg-S1mAqkiJ8reOc7Y2 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-S1mAqkiJ8reOc7Y2 .cluster text{fill:#333;}#mermaid-svg-S1mAqkiJ8reOc7Y2 .cluster span{color:#333;}#mermaid-svg-S1mAqkiJ8reOc7Y2 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\"trebuchet ms\",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-S1mAqkiJ8reOc7Y2 :root{--mermaid-font-family:\"trebuchet ms\",verdana,arial,sans-serif;} HTTPS Basic Auth REST SQL HTTP 用户 反向代理
80/443 Web UI
3000 API 服务
5001 PostgreSQL Ollama 服务
11434
2.2 数据流图
#mermaid-svg-4OPnubLsUuTRSk0O {font-family:\"trebuchet ms\",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-4OPnubLsUuTRSk0O .error-icon{fill:#552222;}#mermaid-svg-4OPnubLsUuTRSk0O .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-4OPnubLsUuTRSk0O .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-4OPnubLsUuTRSk0O .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-4OPnubLsUuTRSk0O .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-4OPnubLsUuTRSk0O .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-4OPnubLsUuTRSk0O .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-4OPnubLsUuTRSk0O .marker{fill:#333333;stroke:#333333;}#mermaid-svg-4OPnubLsUuTRSk0O .marker.cross{stroke:#333333;}#mermaid-svg-4OPnubLsUuTRSk0O svg{font-family:\"trebuchet ms\",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-4OPnubLsUuTRSk0O .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-4OPnubLsUuTRSk0O text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-4OPnubLsUuTRSk0O .actor-line{stroke:grey;}#mermaid-svg-4OPnubLsUuTRSk0O .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-4OPnubLsUuTRSk0O .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-4OPnubLsUuTRSk0O #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-4OPnubLsUuTRSk0O .sequenceNumber{fill:white;}#mermaid-svg-4OPnubLsUuTRSk0O #sequencenumber{fill:#333;}#mermaid-svg-4OPnubLsUuTRSk0O #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-4OPnubLsUuTRSk0O .messageText{fill:#333;stroke:#333;}#mermaid-svg-4OPnubLsUuTRSk0O .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-4OPnubLsUuTRSk0O .labelText,#mermaid-svg-4OPnubLsUuTRSk0O .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-4OPnubLsUuTRSk0O .loopText,#mermaid-svg-4OPnubLsUuTRSk0O .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-4OPnubLsUuTRSk0O .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-4OPnubLsUuTRSk0O .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-4OPnubLsUuTRSk0O .noteText,#mermaid-svg-4OPnubLsUuTRSk0O .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-4OPnubLsUuTRSk0O .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-4OPnubLsUuTRSk0O .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-4OPnubLsUuTRSk0O .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-4OPnubLsUuTRSk0O .actorPopupMenu{position:absolute;}#mermaid-svg-4OPnubLsUuTRSk0O .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-4OPnubLsUuTRSk0O .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-4OPnubLsUuTRSk0O .actor-man circle,#mermaid-svg-4OPnubLsUuTRSk0O line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-4OPnubLsUuTRSk0O :root{--mermaid-font-family:\"trebuchet ms\",verdana,arial,sans-serif;} 用户 Dify Ollama 输入问题 构建 Prompt /api/generate 返回文本 展示答案 用户 Dify Ollama
3️⃣ 环境准备 {#环境准备}
3.1 硬件与系统
- CPU:4 核以上
- 内存:≥8 GB(跑 7B 模型)
- 系统:Ubuntu 22.04 / Debian 12 / CentOS 9 Stream
- GPU(可选):NVIDIA RTX 3060+(CUDA ≥11.8)
3.2 软件依赖
# 更新系统sudo apt update && sudo apt upgrade -y# Docker & Composecurl -fsSL https://get.docker.com | sudo bashsudo usermod -aG docker $USERnewgrp dockersudo curl -SL https://github.com/docker/compose/releases/download/v2.28.0/docker-compose-linux-x86_64 -o /usr/local/bin/docker-composesudo chmod +x /usr/local/bin/docker-compose
3.3 目录结构
dify-ollama/├── .env # 环境变量├── docker-compose.yml # 主编排├── nginx/ # 反向代理│ ├── nginx.conf│ └── .htpasswd└── logs/ # 日志持久化
4️⃣ 一键部署 {#一键部署}
4.1 编写 docker-compose.yml
# 版本:Compose v3.9version: \"3.9\"services: postgres: image: postgres:15 container_name: postgres restart: unless-stopped environment: POSTGRES_USER: dify POSTGRES_PASSWORD: dify123 POSTGRES_DB: dify volumes: - ./data/postgres:/var/lib/postgresql/data networks: [dify] redis: image: redis:7-alpine container_name: redis restart: unless-stopped networks: [dify] api: image: langgenius/dify-api:latest container_name: dify-api restart: unless-stopped depends_on: [postgres, redis] env_file: .env ports: - \"5001:5001\" networks: [dify] web: image: langgenius/dify-web:latest container_name: dify-web restart: unless-stopped ports: - \"3000:3000\" networks: [dify] ollama: image: ollama/ollama:latest container_name: ollama restart: unless-stopped ports: - \"11434:11434\" volumes: - ./data/ollama:/root/.ollama networks: [dify] # 如需 GPU # runtime: nvidia # environment: # - NVIDIA_VISIBLE_DEVICES=allnetworks: dify:
4.2 环境变量 .env
# === 数据库 ===DB_USERNAME=difyDB_PASSWORD=dify123DB_HOST=postgresDB_PORT=5432DB_DATABASE=dify# === Redis ===REDIS_HOST=redisREDIS_PORT=6379# === Ollama ===OLLAMA_API_BASE=http://ollama:11434
4.3 启动
docker-compose up -ddocker-compose logs -f api
5️⃣ 安全加固 {#安全加固}
5.1 生成 SSL 证书(Let’s Encrypt)
sudo apt install certbotsudo certbot certonly --standalone -d your-domain.com
5.2 Nginx 反向代理 + Basic Auth
# ./nginx/nginx.confserver { listen 80; server_name your-domain.com; return 301 https://$host$request_uri;}server { listen 443 ssl http2; server_name your-domain.com; ssl_certificate /etc/letsencrypt/live/your-domain.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/your-domain.com/privkey.pem; location / { auth_basic \"Dify Auth\"; auth_basic_user_file /etc/nginx/.htpasswd; proxy_pass http://web:3000; } location /api { proxy_pass http://api:5001; }}
生成密码文件:
sudo apt install apache2-utilshtpasswd -c ./nginx/.htpasswd admin
5.3 IP 白名单(可选)
location / { allow 10.0.0.0/8; deny all; ...}
6️⃣ 可观测性 {#可观测性}
6.1 日志收集
# 增加日志驱动services: api: logging: driver: \"json-file\" options: max-size: \"100m\" max-file: \"3\"
6.2 Prometheus + Grafana(可选)
#mermaid-svg-dVXRcsSWz1LkWVMR {font-family:\"trebuchet ms\",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-dVXRcsSWz1LkWVMR .error-icon{fill:#552222;}#mermaid-svg-dVXRcsSWz1LkWVMR .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-dVXRcsSWz1LkWVMR .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-dVXRcsSWz1LkWVMR .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-dVXRcsSWz1LkWVMR .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-dVXRcsSWz1LkWVMR .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-dVXRcsSWz1LkWVMR .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-dVXRcsSWz1LkWVMR .marker{fill:#333333;stroke:#333333;}#mermaid-svg-dVXRcsSWz1LkWVMR .marker.cross{stroke:#333333;}#mermaid-svg-dVXRcsSWz1LkWVMR svg{font-family:\"trebuchet ms\",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-dVXRcsSWz1LkWVMR .label{font-family:\"trebuchet ms\",verdana,arial,sans-serif;color:#333;}#mermaid-svg-dVXRcsSWz1LkWVMR .cluster-label text{fill:#333;}#mermaid-svg-dVXRcsSWz1LkWVMR .cluster-label span{color:#333;}#mermaid-svg-dVXRcsSWz1LkWVMR .label text,#mermaid-svg-dVXRcsSWz1LkWVMR span{fill:#333;color:#333;}#mermaid-svg-dVXRcsSWz1LkWVMR .node rect,#mermaid-svg-dVXRcsSWz1LkWVMR .node circle,#mermaid-svg-dVXRcsSWz1LkWVMR .node ellipse,#mermaid-svg-dVXRcsSWz1LkWVMR .node polygon,#mermaid-svg-dVXRcsSWz1LkWVMR .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-dVXRcsSWz1LkWVMR .node .label{text-align:center;}#mermaid-svg-dVXRcsSWz1LkWVMR .node.clickable{cursor:pointer;}#mermaid-svg-dVXRcsSWz1LkWVMR .arrowheadPath{fill:#333333;}#mermaid-svg-dVXRcsSWz1LkWVMR .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-dVXRcsSWz1LkWVMR .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-dVXRcsSWz1LkWVMR .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-svg-dVXRcsSWz1LkWVMR .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-svg-dVXRcsSWz1LkWVMR .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-dVXRcsSWz1LkWVMR .cluster text{fill:#333;}#mermaid-svg-dVXRcsSWz1LkWVMR .cluster span{color:#333;}#mermaid-svg-dVXRcsSWz1LkWVMR div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\"trebuchet ms\",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-dVXRcsSWz1LkWVMR :root{--mermaid-font-family:\"trebuchet ms\",verdana,arial,sans-serif;} metrics Dify API Prometheus Grafana
7️⃣ 实战案例 {#实战案例}
7.1 场景:企业内部知识库问答
- 数据:Markdown 技术文档 5000 篇
- 模型:Qwen-14B-Chat
- 效果:回答准确率 85%+
7.1.1 上传文档
import requestsAPI_BASE = \"https://your-domain.com/api\"API_KEY = \"your-api-key\"files = {\"file\": open(\"docs.zip\", \"rb\")}r = requests.post(f\"{API_BASE}/datasets\", files=files, headers={\"Authorization\": f\"Bearer {API_KEY}\"})print(r.json())
7.1.2 创建应用
curl -X POST https://your-domain.com/api/apps \\ -H \"Authorization: Bearer $API_KEY\" \\ -d \'{\"name\":\"企业知识库\",\"model\":\"qwen:14b\"}\'
8️⃣ 常见问题 FAQ {#常见问题}
get custom model schema failed
certbot renew --dry-run
nvidia-smi not found
nvidia-driver-550
9️⃣ 扩展阅读 {#扩展阅读}
- Dify 官方文档
- Ollama 模型库
- Docker Compose 官方手册
🔟 总结与展望 {#总结}
下一步:接入 SSO、使用 Helm 部署到 K8s、灰度发布模型版本。
📚 参考资料
- Dify GitHub: https://github.com/langgenius/dify
- Ollama GitHub: https://github.com/ollama/ollama
- Let’s Encrypt: https://letsencrypt.org/zh-cn/
- Docker Docs: https://docs.docker.com/compose/compose-file/