# Twenty CRM stack for commons-hub lead funnel # Deploy to /opt/twenty-crm/ on Netcup # # Prerequisites: # - rspace-online stack running (creates rspace-online_rspace-internal network) # - Traefik running on traefik-public network # - .env with POSTGRES_PASSWORD + APP_SECRET # # All services use rspace-internal network for inter-container communication. # This avoids Docker br_netfilter issues with freshly-created bridge networks. services: twenty-ch-server: image: twentycrm/twenty:latest container_name: twenty-ch-server restart: unless-stopped depends_on: twenty-ch-db: condition: service_healthy twenty-ch-redis: condition: service_healthy environment: # ── Core ── - NODE_ENV=production - SERVER_URL=https://crm.rspace.online - FRONT_BASE_URL=https://crm.rspace.online - NODE_PORT=3000 # ── Database ── - PG_DATABASE_URL=postgres://postgres:${POSTGRES_PASSWORD}@twenty-ch-db:5432/default # ── Redis ── - REDIS_URL=redis://twenty-ch-redis:6379 # ── Auth ── - APP_SECRET=${APP_SECRET} # ── Storage ── - STORAGE_TYPE=local - STORAGE_LOCAL_PATH=.local-storage # ── Misc ── - SIGN_IN_PREFILLED=false - IS_BILLING_ENABLED=false - TELEMETRY_ENABLED=false # ── Multi-workspace ── - IS_MULTIWORKSPACE_ENABLED=true - IS_WORKSPACE_CREATION_LIMITED_TO_SERVER_ADMINS=true - DEFAULT_SUBDOMAIN=admin-crm - FRONT_DOMAIN=rspace.online volumes: - twenty-ch-server-data:/app/.local-storage labels: - "traefik.enable=true" - "traefik.http.routers.twenty-crm.rule=Host(`crm.rspace.online`)" - "traefik.http.routers.twenty-crm.entrypoints=web" - "traefik.http.routers.twenty-crm.priority=130" - "traefik.http.services.twenty-crm.loadbalancer.server.port=3000" - "traefik.docker.network=traefik-public" networks: - traefik-public - rspace-internal healthcheck: test: ["CMD", "curl", "-f", "http://localhost:3000/healthz"] interval: 30s timeout: 10s retries: 5 start_period: 60s twenty-ch-worker: image: twentycrm/twenty:latest container_name: twenty-ch-worker restart: unless-stopped command: ["yarn", "worker:prod"] depends_on: twenty-ch-db: condition: service_healthy twenty-ch-redis: condition: service_healthy environment: - NODE_ENV=production - PG_DATABASE_URL=postgres://postgres:${POSTGRES_PASSWORD}@twenty-ch-db:5432/default - REDIS_URL=redis://twenty-ch-redis:6379 - APP_SECRET=${APP_SECRET} - STORAGE_TYPE=local - STORAGE_LOCAL_PATH=.local-storage - SERVER_URL=https://crm.rspace.online - TELEMETRY_ENABLED=false # ── Multi-workspace ── - IS_MULTIWORKSPACE_ENABLED=true - IS_WORKSPACE_CREATION_LIMITED_TO_SERVER_ADMINS=true - DEFAULT_SUBDOMAIN=admin-crm - FRONT_DOMAIN=rspace.online volumes: - twenty-ch-server-data:/app/.local-storage networks: - rspace-internal twenty-ch-db: image: postgres:16-alpine container_name: twenty-ch-db restart: unless-stopped environment: - POSTGRES_DB=default - POSTGRES_USER=postgres - POSTGRES_PASSWORD=${POSTGRES_PASSWORD} volumes: - twenty-ch-pgdata:/var/lib/postgresql/data networks: - rspace-internal healthcheck: test: ["CMD-SHELL", "pg_isready -U postgres -d default"] interval: 10s timeout: 5s retries: 5 start_period: 10s twenty-ch-redis: image: redis:7 container_name: twenty-ch-redis restart: unless-stopped volumes: - twenty-ch-redis-data:/data networks: - rspace-internal healthcheck: test: ["CMD", "redis-cli", "ping"] interval: 10s timeout: 5s retries: 5 volumes: twenty-ch-server-data: twenty-ch-pgdata: twenty-ch-redis-data: networks: traefik-public: external: true rspace-internal: name: rspace-online_rspace-internal external: true