Files
crm-ai/docker-compose.yml
T

251 lines
8.2 KiB
YAML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
name: crm-new
# 全新一套:LibreDesk(平台 + 内置 AI)+ Twenty(CRM)+ bridge(业务工具/集成)
# 与旧栈 crm/crm-ai-demo 完全隔离:独立 PG/Redis/端口/数据卷。
#
# 对外端口:
# LibreDesk http://localhost:9000
# Twenty http://localhost:3100
# bridge http://localhost:4100
# Postgres(宿主机) 127.0.0.1:5440
# Redis(宿主机) 127.0.0.1:6390
services:
postgres:
image: ${POSTGRES_IMAGE:-pgvector/pgvector:pg18}
container_name: crmnew-postgres
restart: unless-stopped
ports:
- "127.0.0.1:5440:5432"
environment:
POSTGRES_USER: ${POSTGRES_USER:-crmnew}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
POSTGRES_DB: ${POSTGRES_DB:-postgres}
volumes:
# PG18 官方镜像要求挂载 /var/lib/postgresql(数据在子目录)
- pg-data:/var/lib/postgresql
- ./infra/init-databases.sql:/docker-entrypoint-initdb.d/01-init-databases.sql:ro
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-crmnew} -d postgres"]
interval: 5s
timeout: 5s
retries: 20
redis:
image: ${REDIS_IMAGE:-redis:8.8-alpine}
container_name: crmnew-redis
restart: unless-stopped
command: ["redis-server", "--appendonly", "yes"]
ports:
- "127.0.0.1:6390:6379"
volumes:
- redis-data:/data
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 5s
timeout: 3s
retries: 20
# ---------------------------------------------------------------- LibreDesk
libredesk:
image: ${LIBREDESK_IMAGE:-libredesk/libredesk:v2.9.0-rc.10}
container_name: crmnew-libredesk
restart: unless-stopped
ports:
- "9000:9000"
environment:
LIBREDESK_SYSTEM_USER_PASSWORD: ${LIBREDESK_SYSTEM_USER_PASSWORD}
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_healthy
volumes:
- ./libredesk/uploads:/libredesk/uploads:rw
- ./libredesk/config/config.toml:/libredesk/config.toml:ro
command:
- sh
- -c
- >-
./libredesk --install --idempotent-install --yes --config /libredesk/config.toml &&
./libredesk --upgrade --yes --config /libredesk/config.toml &&
./libredesk --config /libredesk/config.toml
# ------------------------------------------------------------------- Twenty
twenty-server:
image: twentycrm/twenty:${TWENTY_TAG:-v2.30.1}
container_name: crmnew-twenty-server
restart: unless-stopped
ports:
- "3100:3000"
environment:
NODE_PORT: 3000
PG_DATABASE_URL: postgres://${POSTGRES_USER:-crmnew}:${POSTGRES_PASSWORD}@postgres:5432/twenty
SERVER_URL: ${TWENTY_SERVER_URL:-http://localhost:3100}
REDIS_URL: redis://redis:6379/1
DISABLE_DB_MIGRATIONS: "false"
DISABLE_CRON_JOBS_REGISTRATION: "false"
STORAGE_TYPE: local
ENCRYPTION_KEY: ${TWENTY_ENCRYPTION_KEY}
FALLBACK_ENCRYPTION_KEY: ${TWENTY_FALLBACK_ENCRYPTION_KEY}
APP_SECRET: ${TWENTY_APP_SECRET}
IS_BILLING_ENABLED: "false"
SIGN_IN_PREFILLED: "false"
EMAIL_DRIVER: logger
volumes:
- twenty-data:/app/packages/twenty-server/.local-storage
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_healthy
healthcheck:
test: ["CMD", "wget", "--spider", "-q", "http://localhost:3000/healthz"]
interval: 10s
timeout: 5s
retries: 30
start_period: 90s
twenty-worker:
image: twentycrm/twenty:${TWENTY_TAG:-v2.30.1}
container_name: crmnew-twenty-worker
restart: unless-stopped
command: ["yarn", "worker:prod"]
environment:
PG_DATABASE_URL: postgres://${POSTGRES_USER:-crmnew}:${POSTGRES_PASSWORD}@postgres:5432/twenty
SERVER_URL: ${TWENTY_SERVER_URL:-http://localhost:3100}
REDIS_URL: redis://redis:6379/1
DISABLE_DB_MIGRATIONS: "true"
DISABLE_CRON_JOBS_REGISTRATION: "true"
STORAGE_TYPE: local
ENCRYPTION_KEY: ${TWENTY_ENCRYPTION_KEY}
FALLBACK_ENCRYPTION_KEY: ${TWENTY_FALLBACK_ENCRYPTION_KEY}
APP_SECRET: ${TWENTY_APP_SECRET}
volumes:
- twenty-data:/app/packages/twenty-server/.local-storage
depends_on:
twenty-server:
condition: service_healthy
# IMAP ID 注入代理:LibreDesk 客户端不发 ID,163 会拒绝 SELECT
imap-proxy:
image: node:24-alpine
container_name: crmnew-imap-proxy
restart: unless-stopped
command: ["node", "/app/server.js"]
environment:
LISTEN_PORT: 1993
UPSTREAM_HOST: imap.163.com
UPSTREAM_PORT: 993
ports:
- "127.0.0.1:1993:1993"
volumes:
- ./services/imap-id-proxy:/app:ro
depends_on:
- libredesk
# 公网网关:仅暴露 WhatsApp webhook + 帮助中心,其余 404
public-gateway:
image: node:24-alpine
container_name: crmnew-public-gateway
restart: unless-stopped
command: ["node", "/app/server.js"]
environment:
PORT: 9001
UPSTREAM: http://libredesk:9000
volumes:
- ./services/public-gateway:/app:ro
depends_on:
- libredesk
# Cloudflare 临时隧道:给 Meta 一个公网 HTTPS 回调地址
cloudflared:
image: cloudflare/cloudflared:latest
container_name: crmnew-cloudflared
restart: unless-stopped
command: tunnel --no-autoupdate --url http://public-gateway:9001
depends_on:
- public-gateway
# ------------------------------------------------------------------- bridge
bridge:
build:
context: ./bridge
container_name: crmnew-bridge
restart: unless-stopped
extra_hosts:
- "host.docker.internal:host-gateway"
ports:
- "4100:4100"
environment:
TOOLS_PORT: 4100
TOOLS_SHARED_KEY: ${TOOLS_SHARED_KEY}
TOOLS_PUBLIC_BASE_URL: http://bridge:4100
TOOLS_DEV_BYPASS: ${TOOLS_DEV_BYPASS:-false}
RECOMMEND_URL: ${RECOMMEND_URL}
ORDER_API_URL: ${ORDER_API_URL}
INVENTORY_API_URL: ${INVENTORY_API_URL}
MEMBER_RPC_URL: ${MEMBER_RPC_URL}
RPC_TIMEOUT_MS: ${RPC_TIMEOUT_MS:-8000}
PRODUCT_TIMEOUT_MS: ${PRODUCT_TIMEOUT_MS:-15000}
SITE_SEARCH_URL: ${SITE_SEARCH_URL}
TWENTY_BASE_URL: http://twenty-server:3000
TWENTY_GRAPHQL_PATH: /graphql
TWENTY_WORKSPACE_ID: ${TWENTY_WORKSPACE_ID:-}
TWENTY_API_KEY: ${TWENTY_API_KEY:-}
LIBREDESK_BASE_URL: ${LIBREDESK_BASE_URL}
LIBREDESK_API_KEY: ${LIBREDESK_API_KEY:-}
LIBREDESK_API_SECRET: ${LIBREDESK_API_SECRET:-}
LIBREDESK_WEBHOOK_SECRET: ${LIBREDESK_WEBHOOK_SECRET:-}
LIBREDESK_WEBHOOK_INBOX_IDS: ${LIBREDESK_WEBHOOK_INBOX_IDS:-1}
LLM_BASE_URL: ${LLM_BASE_URL:-}
LLM_API_KEY: ${LLM_API_KEY:-}
LLM_MODEL: ${LLM_MODEL:-qwen-plus-latest}
LLM_TIMEOUT_MS: ${LLM_TIMEOUT_MS:-30000}
SMTP_HOST: ${SMTP_HOST:-}
SMTP_PORT: ${SMTP_PORT:-465}
SMTP_USER: ${SMTP_USER:-}
SMTP_PASS: ${SMTP_PASS:-}
SMTP_FROM: ${SMTP_FROM:-}
RAG_PG_URL: ${RAG_PG_URL:-}
EMB_BASE_URL: ${EMB_BASE_URL:-}
EMB_API_KEY: ${EMB_API_KEY:-}
EMB_MODEL: ${EMB_MODEL:-text-embedding-v4}
EMB_DIM: ${EMB_DIM:-1024}
EMB_TRANSLATE_MODEL: ${EMB_TRANSLATE_MODEL:-qwen-turbo}
LIBREDESK_INBOX_UUID: ${LIBREDESK_INBOX_UUID:-}
LIBREDESK_INBOX_SECRET: ${LIBREDESK_INBOX_SECRET:-}
SITE_JWT_SECRET: ${SITE_JWT_SECRET:-}
IDENTITY_DEV_MODE: ${IDENTITY_DEV_MODE:-false}
IDENTITY_CORS_ORIGIN: ${IDENTITY_CORS_ORIGIN:-}
IDENTITY_TTL_SEC: ${IDENTITY_TTL_SEC:-3600}
REDIS_URL: redis://redis:6379/3
DEFAULT_TENANT_ID: ${DEFAULT_TENANT_ID:-2}
DEFAULT_LANGUAGE_ID: ${DEFAULT_LANGUAGE_ID:-1}
PG_URL: postgres://${POSTGRES_USER:-crmnew}:${POSTGRES_PASSWORD}@postgres:5432/bridge
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_healthy
networks:
- default
- spug-net
healthcheck:
test: ["CMD", "wget", "-q", "-O", "-", "http://127.0.0.1:4100/healthz"]
interval: 10s
timeout: 3s
retries: 10
networks:
default:
name: crm-new_default
# 与本工作区的 wangliang-dev 同网络,bridge 可直接按容器名调用 9503/9505/9506/9509
spug-net:
external: true
volumes:
pg-data:
redis-data:
twenty-data: