Docker Compose Deployment
Overview
Three Docker Compose profiles support different deployment scenarios:
| Profile | Use Case | Services | Features |
|---|---|---|---|
| prod | Production | flow8, mongo, mongo-express | Minimal, optimized |
| dev | Development | flow8, mongo, mongo-express | Hot reload, debugging |
| local | Local debugging | flow8, mongo, postgres, mongo-express | Delve debugger, all features |
Production Profile (docker-compose.yml)
version: '3.8'
services: flow8: image: flow8core:latest container_name: flow8 restart: unless-stopped ports: - "4454:4454" - "4445:4445" - "7701-7799:7701-7799" environment: MONGODB_URI: mongodb://mongo:27017/flow8 MONGODB_DB: flow8 SERVER_PORT: 4454 ENCRYPTION_KEY: ${ENCRYPTION_KEY} ENCRYPTION_KEY_SALT: ${ENCRYPTION_KEY_SALT} OAUTH2_CLIENT_ID: ${OAUTH2_CLIENT_ID} OAUTH2_CLIENT_SECRET: ${OAUTH2_CLIENT_SECRET} LOG_LEVEL: info SESSION_COOKIE_SECURE: "true" SESSION_COOKIE_HTTP_ONLY: "true" volumes: - flow8-data:/app/data depends_on: mongo: condition: service_healthy networks: - backend healthcheck: test: ["CMD", "curl", "-f", "http://localhost:4454/health"] interval: 30s timeout: 10s retries: 3 start_period: 40s restart: unless-stopped resources: limits: cpus: "2" memory: 2G reservations: cpus: "1" memory: 1G
mongo: image: mongo:6.0 container_name: flow8-mongo restart: unless-stopped environment: MONGO_INITDB_ROOT_USERNAME: admin MONGO_INITDB_ROOT_PASSWORD: ${MONGO_ROOT_PASSWORD} MONGO_INITDB_DATABASE: flow8 volumes: - mongo-data:/data/db - mongo-config:/data/configdb - ./init-mongo.js:/docker-entrypoint-initdb.d/init-mongo.js networks: - backend healthcheck: test: mongosh --eval "db.adminCommand('ping')" interval: 10s timeout: 5s retries: 5 resources: limits: cpus: "2" memory: 2G
mongo-express: image: mongo-express:latest container_name: flow8-mongo-express restart: unless-stopped ports: - "8081:8081" environment: ME_CONFIG_MONGODB_URL: mongodb://admin:${MONGO_ROOT_PASSWORD}@mongo:27017/ ME_CONFIG_MONGODB_ADMINUSERNAME: admin ME_CONFIG_MONGODB_ADMINPASSWORD: ${MONGO_ROOT_PASSWORD} depends_on: - mongo networks: - backend
volumes: flow8-data: driver: local mongo-data: driver: local mongo-config: driver: local
networks: backend: driver: bridgeDevelopment Profile (docker-compose.dev.yml)
version: '3.8'
services: flow8: build: context: . dockerfile: Dockerfile.dev container_name: flow8-dev restart: on-failure ports: - "4454:4454" - "4445:4445" - "7701-7799:7701-7799" environment: MONGODB_URI: mongodb://mongo:27017/flow8 SERVER_PORT: 4454 ENCRYPTION_KEY: ${ENCRYPTION_KEY:?Required — generate with: openssl rand -hex 128} ENCRYPTION_KEY_SALT: ${ENCRYPTION_KEY_SALT:?Required — generate with: openssl rand -hex 32} LOG_LEVEL: debug volumes: - .:/app/src - flow8-data:/app/data depends_on: mongo: condition: service_healthy networks: - backend environment: CGO_ENABLED: 1 GOOS: linux
mongo: image: mongo:6.0 container_name: flow8-mongo-dev restart: unless-stopped environment: MONGO_INITDB_ROOT_USERNAME: admin MONGO_INITDB_ROOT_PASSWORD: <your-mongo-password> MONGO_INITDB_DATABASE: flow8 volumes: - mongo-data:/data/db - ./init-mongo.js:/docker-entrypoint-initdb.d/init-mongo.js ports: - "27017:27017" networks: - backend healthcheck: test: mongosh --eval "db.adminCommand('ping')" interval: 10s timeout: 5s retries: 5
mongo-express: image: mongo-express:latest container_name: flow8-mongo-express-dev restart: unless-stopped ports: - "8081:8081" environment: ME_CONFIG_MONGODB_URL: mongodb://admin:<your-mongo-password>@mongo:27017/ ME_CONFIG_MONGODB_ADMINUSERNAME: admin ME_CONFIG_MONGODB_ADMINPASSWORD: <your-mongo-password> depends_on: - mongo networks: - backend
volumes: flow8-data: driver: local mongo-data: driver: local
networks: backend: driver: bridgeLocal Debug Profile (docker-compose.local.yml)
version: '3.8'
services: flow8: build: context: . dockerfile: Dockerfile.local container_name: flow8-local restart: on-failure ports: - "4454:4454" - "4445:4445" - "7701-7799:7701-7799" - "2345:2345" # Delve debugger port environment: MONGODB_URI: mongodb://mongo:27017/flow8 POSTGRESQL_URI: postgresql://user:password@postgres:5432/flow8_test SERVER_PORT: 4454 ENCRYPTION_KEY: ${ENCRYPTION_KEY:?Required — generate with: openssl rand -hex 128} ENCRYPTION_KEY_SALT: ${ENCRYPTION_KEY_SALT:?Required — generate with: openssl rand -hex 32} LOG_LEVEL: debug volumes: - .:/app/src - flow8-data:/app/data depends_on: mongo: condition: service_healthy postgres: condition: service_healthy networks: - backend cap_add: - SYS_PTRACE # Required for Delve debugger security_opt: - "apparmor=unconfined"
mongo: image: mongo:6.0 container_name: flow8-mongo-local restart: unless-stopped environment: MONGO_INITDB_ROOT_USERNAME: admin MONGO_INITDB_ROOT_PASSWORD: <your-mongo-password> MONGO_INITDB_DATABASE: flow8 volumes: - mongo-data:/data/db - ./init-mongo.js:/docker-entrypoint-initdb.d/init-mongo.js ports: - "27017:27017" networks: - backend healthcheck: test: mongosh --eval "db.adminCommand('ping')" interval: 10s timeout: 5s retries: 5
postgres: image: postgres:15 container_name: flow8-postgres-local restart: unless-stopped environment: POSTGRES_USER: user POSTGRES_PASSWORD: password POSTGRES_DB: flow8_test volumes: - postgres-data:/var/lib/postgresql/data ports: - "5432:5432" networks: - backend healthcheck: test: ["CMD-SHELL", "pg_isready -U user"] interval: 10s timeout: 5s retries: 5
mongo-express: image: mongo-express:latest container_name: flow8-mongo-express-local restart: unless-stopped ports: - "8081:8081" environment: ME_CONFIG_MONGODB_URL: mongodb://admin:<your-mongo-password>@mongo:27017/ ME_CONFIG_MONGODB_ADMINUSERNAME: admin ME_CONFIG_MONGODB_ADMINPASSWORD: <your-mongo-password> depends_on: - mongo networks: - backend
volumes: flow8-data: driver: local mongo-data: driver: local postgres-data: driver: local
networks: backend: driver: bridgeEnvironment Configuration
.env File
# MongoDBMONGO_ROOT_PASSWORD=your_secure_password_here
# Encryption (REQUIRED for production)ENCRYPTION_KEY=<output of: openssl rand -hex 128>ENCRYPTION_KEY_SALT=<output of: openssl rand -hex 32>
# OAuth2 (optional)OAUTH2_CLIENT_ID=your-client-idOAUTH2_CLIENT_SECRET=your-client-secret
# Database (for local dev)POSTGRES_USER=userPOSTGRES_PASSWORD=password.env.example
# Copy to .env and fill in valuesMONGO_ROOT_PASSWORD=change_meENCRYPTION_KEY=generate_with_openssl_rand_-hex_128ENCRYPTION_KEY_SALT=generate_with_openssl_rand_-hex_32OAUTH2_CLIENT_ID=from_azure_adOAUTH2_CLIENT_SECRET=from_azure_adMongoDB Initialization
init-mongo.js
// Runs automatically when MongoDB starts for first time
db = db.getSiblingDB('flow8');
// Create collections with indexesdb.createCollection('flows');db.flows.createIndex({ company_id: 1, created_at: -1 });db.flows.createIndex({ company_id: 1, name: 1 });
db.createCollection('plays');db.plays.createIndex({ company_id: 1, created_at: -1 });db.plays.createIndex({ flow_id: 1, created_at: -1 });
db.createCollection('audit_logs');db.audit_logs.createIndex({ company_id: 1, timestamp: -1 });db.audit_logs.createIndex({ user_id: 1, timestamp: -1 });db.audit_logs.createIndex( { expires_at: 1 }, { expireAfterSeconds: 0 } // TTL index for retention);
// Create default companydb.companies.insertOne({ _id: ObjectId(), name: 'Default Company', created_at: new Date(), updated_at: new Date()});
// Create admin user (password: admin123, bcrypt hash)db.users.insertOne({ _id: ObjectId(), email: 'admin@flow8.local', password_hash: '$2a$12$nOUIs5kJ7naTuTFkWK1Be.g6Scot5aIyab.MQyqmqVH4.y3jC6sFm', // bcrypt of "admin123" company_associations: [ { company_id: db.companies.findOne()._id, role: 'admin', joined_at: new Date() } ], created_at: new Date(), updated_at: new Date()});Network Configuration
Bridge Network
The backend network isolates flow8 services from the host:
networks: backend: driver: bridgeBenefits:
- Services communicate by name (flow8 → mongo)
- Isolated from host network
- Easy to add more services (Redis, queue, etc.)
Port Exposure
services: flow8: ports: - "4454:4454" # External:Internal - "4445:4445" # MCP server (optional) - "7701-7799:7701-7799" # Channel ports (optional)Production Security:
Bind only to localhost:
ports: - "127.0.0.1:4454:4454" # Only accessible from localhost - "127.0.0.1:4445:4445"Then use a reverse proxy for external access.
Volume Strategy
Data Persistence
volumes: flow8-data: driver: local mongo-data: driver: localNamed volumes are created automatically by Docker and persist between container restarts.
Backup Named Volumes
# Backup flow8-data volumedocker run --rm \ -v flow8-data:/data \ -v $(pwd):/backup \ ubuntu tar czf /backup/flow8-data-backup.tar.gz -C /data .
# Restoredocker run --rm \ -v flow8-data:/data \ -v $(pwd):/backup \ ubuntu tar xzf /backup/flow8-data-backup.tar.gz -C /dataBind Mounts (Development)
volumes: - .:/app/src # Mount source code for hot reload - /app/src/vendor # But exclude vendor directoryCommands
Production
# Start servicesdocker-compose up -d
# View logsdocker-compose logs -f flow8
# Stop servicesdocker-compose down
# Restart MongoDBdocker-compose restart mongo
# Backup databasedocker exec flow8-mongo mongodump --uri="mongodb://admin:password@localhost:27017" --out=/backupDevelopment
# Start with dev profiledocker-compose -f docker-compose.yml -f docker-compose.dev.yml up -d
# Rebuild imagedocker-compose build --no-cache
# Enter container shelldocker exec -it flow8-dev bash
# View real-time logsdocker-compose logs -f flow8Local Debugging
# Start with Delve debuggerdocker-compose -f docker-compose.local.yml up -d
# Connect Delve from IDE (port 2345)# In VS Code: Add launch configuration for localhost:2345
# View logsdocker-compose logs -f flow8Common Issues
”Cannot connect to MongoDB”
Error: connect: connection refusedCheck MongoDB health:
docker-compose ps mongodocker-compose logs mongodocker exec flow8-mongo mongosh --eval "db.adminCommand('ping')"“Volume permission denied”
Error: mkdir: cannot create directory '/app/data': Permission deniedFix permissions:
docker-compose downdocker volume rm flow8-datadocker-compose up -d“Port already in use”
Error: Bind for 0.0.0.0:4454 failed: port is already allocatedFind and stop conflicting service:
lsof -i :4454kill -9 <PID>
# Or use different portdocker-compose -e "PORT=4455" upMongoDB Credentials
Default credentials in compose files:
Username: adminPassword: ${MONGO_ROOT_PASSWORD} (from .env)Change for production:
# Generate strong passwordopenssl rand -base64 32
# Update .envMONGO_ROOT_PASSWORD=your_generated_password
# Recreate MongoDB (destroys data)docker-compose down -v mongodocker-compose up -d mongoScaling to Multiple Instances
For load balancing, deploy multiple flow8 instances:
version: '3.8'
services: flow8-1: image: flow8core:latest ports: - "4454:4454" environment: MONGODB_URI: mongodb://mongo:27017/flow8 CHANNEL_PORT_RANGE: 7701-7799 # Instance 1
flow8-2: image: flow8core:latest ports: - "4455:4454" environment: MONGODB_URI: mongodb://mongo:27017/flow8 CHANNEL_PORT_RANGE: 7800-7899 # Instance 2 (separate range)
nginx: image: nginx:latest ports: - "80:80" - "443:443" volumes: - ./nginx.conf:/etc/nginx/nginx.conf:ro - ./ssl:/etc/nginx/ssl:ro depends_on: - flow8-1 - flow8-2nginx.conf:
upstream flow8_backend { least_conn; server flow8-1:4454; server flow8-2:4454;}
server { listen 80; server_name app.flow8.local;
location / { proxy_pass http://flow8_backend; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; }}