Docker Deployment
Docker Image Specifications
Base Image
The flow8 Docker image is built on a multi-stage Dockerfile with the following base:
FROM linuxserver/libreoffice:latest
# Includes:# - LibreOffice (for document conversion)# - ImageMagick (for image processing)# - Tesseract OCR (for text extraction from images)Why linuxserver/libreoffice?
- Pre-configured with system dependencies (LibreOffice, ImageMagick, Tesseract)
- Minimal attack surface
- Regular security updates
- English locale and fonts included
Installed System Packages
# Document & Image Processing- liboffice (entire suite)- imagemagick- ghostscript (for PDF manipulation)- tesseract-ocr (English models: eng)
# Network & System Tools- curl- wget- ca-certificates (for TLS validation)- openssl
# Compression & Archives- zip- unzip- tar- gzip
# Database Clients (for debugging)- mongodb-org-tools (mongosh, mongodump)- postgresql-client- mysql-clientBinary Location
/app/flow8coreThe compiled flow8 binary is placed here during multi-stage build.
Port Mappings
| Port | Service | Protocol | Purpose | Required |
|---|---|---|---|---|
| 4454 | flow8 API | HTTP | Main application, REST API, WebSocket, UI | Yes |
| 4445 | MCP Server | HTTP | Model Context Protocol server (AI agents) | No |
| 7701-7799 | Channel Ports | TCP/WebSocket | Async execution workers | No (unless channels enabled) |
Example Docker Run
docker run \ -p 4454:4454 \ -p 4445:4445 \ -p 7701-7799:7701-7799 \ flow8core:latestPort Binding Notes:
-
External Production: Bind main port via reverse proxy (nginx, Caddy, ALB)
Terminal window # ✅ Production: reverse proxy handles 443 → 4454docker run -p 127.0.0.1:4454:4454 flow8core:latest -
Development: Can bind directly
Terminal window docker run -p 0.0.0.0:4454:4454 flow8core:latest -
Channel Ports: Bind for multi-instance or long-running jobs
Terminal window docker run -p 7701-7799:7701-7799 flow8core:latest
Volume Mounts
The application writes data to /app/data/ directory. Mount this volume for persistence:
docker run \ -v flow8-data:/app/data \ flow8core:latestDirectory Structure Inside Container
/app/├── flow8core # Binary├── data/ # Runtime data (mounted volume)│ ├── db/ # JSON database snapshots│ ├── data/ # User-uploaded files│ │ ├── flows/│ │ ├── attachments/│ │ └── tmp/│ ├── logs/ # Application logs│ │ └── app.log│ └── tmp/ # Temporary processing files└── config/ └── config.yml # Runtime configVolume Permissions
The container runs as unprivileged user (UID: 911):
# Ensure volume permissionsdocker run \ -v flow8-data:/app/data \ -u 911:911 \ flow8core:latestEnvironment Variables
Required Variables
# MongoDB ConnectionMONGODB_URI=mongodb://mongo:27017/flow8MONGODB_DB=flow8
# Server ConfigurationSERVER_PORT=4454 # Default: 4454ENCRYPTION_KEY=<generate: openssl rand -hex 128> # 256-char hex, REQUIRED for securityENCRYPTION_KEY_SALT=<generate: openssl rand -hex 32> # 64-char hex, REQUIRED for securityOptional Variables
# MCP Server (for AI agent integration)MCP_SERVER_ENABLED=trueMCP_SERVER_PORT=4445
# Channel Ports (for async execution)CHANNEL_PORT_RANGE=7701-7799CHANNEL_POOL_SIZE=100 # Max concurrent channel workers
# OAuth2 (Microsoft Office 365 SSO)OAUTH2_CLIENT_ID=550e8400...OAUTH2_CLIENT_SECRET=... # EncryptedOAUTH2_REDIRECT_URI=https://app.flow8.io/auth/callback
# Component DefaultsDEFAULT_AI_COMPONENT=openai # or anthropic, mistral, ollamaDEFAULT_STORAGE_COMPONENT=s3 # or gcs, localDEFAULT_DB_COMPONENT=postgres
# Retention & CleanupRETENTION_CLEANUP_INTERVAL=2mRETENTION_AUDIT_CADENCE=30dRETENTION_FLOWS_CADENCE=90d
# LoggingLOG_LEVEL=info # debug, info, warn, errorLOG_FILE=/app/data/logs/app.log
# Field Size LimitsAUDIT_LOG_FIELD_MAX_BYTES=4096UNIT_OUTPUT_UI_MAX_BYTES=1048576
# Session & AuthSESSION_TTL_HOURS=1SESSION_COOKIE_SECURE=trueSESSION_COOKIE_HTTP_ONLY=trueSESSION_COOKIE_SAME_SITE=strictConfiguration File
Configuration is loaded from config/config.yml with environment variable substitution:
server: port: ${SERVER_PORT} # Substituted from env max_request_size_mb: 100 read_timeout_seconds: 30 write_timeout_seconds: 30
mongodb: uri: ${MONGODB_URI} database: ${MONGODB_DB} max_pool_size: 100 ssl: true
encryption: key_secret: ${ENCRYPTION_KEY} key_salt: ${ENCRYPTION_KEY_SALT} algorithm: argon2id
oauth2: microsoft: client_id: ${OAUTH2_CLIENT_ID} client_secret: ${OAUTH2_CLIENT_SECRET} redirect_uri: ${OAUTH2_REDIRECT_URI}
session: ttl_hours: ${SESSION_TTL_HOURS} cookie_secure: ${SESSION_COOKIE_SECURE} cookie_http_only: ${SESSION_COOKIE_HTTP_ONLY} cookie_same_site: ${SESSION_COOKIE_SAME_SITE}
# ... rest of configDocker Run Example
Minimal Setup
docker run \ --name flow8 \ -e MONGODB_URI=mongodb://mongo:27017/flow8 \ -e SERVER_PORT=4454 \ -e ENCRYPTION_KEY=<output of: openssl rand -hex 128> \ -e ENCRYPTION_KEY_SALT=<output of: openssl rand -hex 32> \ -p 4454:4454 \ -v flow8-data:/app/data \ flow8core:latestProduction-Ready Setup
docker run \ --name flow8-prod \ --restart unless-stopped \ \ # Environment -e MONGODB_URI=mongodb+srv://user:pass@cluster.mongodb.net/flow8 \ -e SERVER_PORT=4454 \ -e ENCRYPTION_KEY=$(cat /run/secrets/flow8_encryption_key) \ -e ENCRYPTION_KEY_SALT=$(cat /run/secrets/flow8_salt) \ -e OAUTH2_CLIENT_ID=$(cat /run/secrets/oauth2_client_id) \ -e OAUTH2_CLIENT_SECRET=$(cat /run/secrets/oauth2_client_secret) \ -e LOG_LEVEL=info \ -e SESSION_COOKIE_SECURE=true \ \ # Ports -p 127.0.0.1:4454:4454 \ \ # Volumes -v flow8-data:/app/data \ -v /etc/ssl/certs:/etc/ssl/certs:ro \ \ # Resource limits --cpus=2 \ --memory=2g \ --memory-swap=4g \ \ # Health check --health-cmd='curl -f http://localhost:4454/health || exit 1' \ --health-interval=30s \ --health-timeout=10s \ --health-retries=3 \ --health-start-period=40s \ \ flow8core:latestHealth Checks
Built-in Health Endpoint
# HTTP GET /healthcurl http://localhost:4454/health
Response:{ "status": "healthy", "checks": { "mongodb": "connected", "config": "loaded", "components": "initialized" }, "timestamp": "2026-04-04T10:00:00Z"}Docker Health Check Configuration
HEALTHCHECK --interval=30s --timeout=10s --start-period=40s --retries=3 \ CMD curl -f http://localhost:4454/health || exit 1Docker Compose Health Check
services: flow8: image: flow8core:latest healthcheck: test: ["CMD", "curl", "-f", "http://localhost:4454/health"] interval: 30s timeout: 10s retries: 3 start_period: 40s restart: unless-stoppedResource Requirements
Minimum Requirements
CPU: 500m (0.5 cores)Memory: 512 MBDisk: 5 GB (data volume)Suitable for:
- Development
- Testing
- Small single-instance deployments
Recommended Requirements
CPU: 2-4 coresMemory: 2-4 GBDisk: 50+ GB (data volume)Suitable for:
- Production single-instance
- Multiple concurrent flows
- Large document processing workloads
Large-Scale Deployment
CPU: 8+ cores per instanceMemory: 8+ GB per instanceDisk: 100+ GB per instance (shared storage for S3/GCS)Suitable for:
- Multi-instance cluster
- 1000+ concurrent plays
- Enterprise SLA requirements
Docker Compose
See the Docker Compose deployment guide for complete examples with MongoDB and other services.
Image Scanning & Security
Scan for Vulnerabilities
# Using trivytrivy image flow8core:latest
# Using Snyksnyk container test flow8core:latest
# Using AWS ECRaws ecr start-image-scan --repository-name flow8core --image-id imageTag=latestImage Signing
Sign images with Cosign:
cosign sign --key cosign.key ghcr.io/osbits/flow8core:latestVerify on pull:
cosign verify --key cosign.pub ghcr.io/osbits/flow8core:latestLogging
Application Logs
Logs are written to /app/data/logs/app.log:
# View logsdocker logs flow8-prod
# Stream logsdocker logs -f flow8-prod
# Tail last 100 linesdocker logs --tail 100 flow8-prodLog Format
2026-04-04T10:23:45.123Z INFO http GET /api/v1/flows?page=1 200 45ms2026-04-04T10:23:46.456Z ERROR auth login failed: wrong_password user_id=user_123Log Level Configuration
docker run \ -e LOG_LEVEL=debug \ flow8core:latestValid levels: debug, info, warn, error
Stopping & Cleanup
# Stop container gracefully (30s timeout)docker stop flow8-prod
# Stop forcefullydocker kill flow8-prod
# Remove containerdocker rm flow8-prod
# Remove volume (WARNING: data loss)docker volume rm flow8-dataCommon Issues
”Connection refused” to MongoDB
Error: connect: connection refusedSolution: Ensure MongoDB is accessible
# Test connectivitydocker exec flow8-prod curl -s mongodb://mongo:27017 || echo "MongoDB not accessible"
# Check MongoDB containerdocker logs mongo”Permission denied” on volumes
Error: mkdir: cannot create directory '/app/data': Permission deniedSolution: Set volume permissions
# Create volume with correct permissionsdocker volume create flow8-data
# Or use explicit path with correct permissionsmkdir -p /data/flow8chmod 755 /data/flow8docker run -v /data/flow8:/app/data ...Out of memory
OOMKilledSolution: Increase memory limit or adjust GC
docker run \ --memory=4g \ --memory-swap=8g \ -e GOMAXPROCS=4 \ flow8core:latestDocker Registry
Push to Registry
docker tag flow8core:latest myregistry.azurecr.io/flow8core:latestdocker push myregistry.azurecr.io/flow8core:latestPrivate Registry Authentication
# Log indocker login myregistry.azurecr.io
# Store credentials in Kubernetes Secretkubectl create secret docker-registry flow8-registry \ --docker-server=myregistry.azurecr.io \ --docker-username=user \ --docker-password=password
# Use in Kubernetes Podspec: imagePullSecrets: - name: flow8-registry containers: - image: myregistry.azurecr.io/flow8core:latest