Docker Deployment
Deploy Fluxbase using Docker and Docker Compose for simple production environments and development.
Overview
Section titled “Overview”Fluxbase provides official Docker images (~80MB) with:
- Multi-stage build for minimal image size
- Non-root user for security
- Health checks built-in
- Admin UI embedded
- Automatic database migrations
Image Registry: ghcr.io/fluxbase-eu/fluxbase
Quick Start
Section titled “Quick Start”1. Pull the Docker Image
Section titled “1. Pull the Docker Image”docker pull ghcr.io/fluxbase-eu/fluxbase:latest2. Run with Docker Compose
Section titled “2. Run with Docker Compose”Create docker-compose.yml:
version: "3.8"
services: postgres: image: postgis/postgis:18-3.6 container_name: fluxbase-postgres environment: POSTGRES_USER: postgres POSTGRES_PASSWORD: your-secure-password POSTGRES_DB: fluxbase ports: - "5432:5432" volumes: - postgres_data:/var/lib/postgresql/data networks: - fluxbase-network healthcheck: test: ["CMD-SHELL", "pg_isready -U postgres"] interval: 10s timeout: 5s retries: 5
fluxbase: image: ghcr.io/fluxbase-eu/fluxbase:latest container_name: fluxbase depends_on: postgres: condition: service_healthy environment: FLUXBASE_DATABASE_HOST: postgres FLUXBASE_DATABASE_PORT: 5432 FLUXBASE_DATABASE_USER: postgres FLUXBASE_DATABASE_PASSWORD: your-secure-password FLUXBASE_DATABASE_DATABASE: fluxbase FLUXBASE_AUTH_JWT_SECRET: your-jwt-secret-change-in-production FLUXBASE_BASE_URL: http://localhost:8080 FLUXBASE_ENVIRONMENT: production FLUXBASE_DEBUG: "false" ports: - "8080:8080" volumes: - ./storage:/app/storage - ./config:/app/config networks: - fluxbase-network restart: unless-stopped
volumes: postgres_data:
networks: fluxbase-network: driver: bridge3. Start the Services
Section titled “3. Start the Services”docker-compose up -d4. Verify Deployment
Section titled “4. Verify Deployment”# Check container statusdocker-compose ps
# View logsdocker-compose logs -f fluxbase
# Check health endpointcurl http://localhost:8080/healthYou should see:
{ "status": "healthy", "database": "connected", "version": "0.1.0"}Production Docker Compose
Section titled “Production Docker Compose”For production, use this enhanced configuration:
version: "3.8"
services: postgres: image: postgis/postgis:18-3.6 container_name: fluxbase-postgres environment: POSTGRES_USER: postgres POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} POSTGRES_DB: fluxbase POSTGRES_INITDB_ARGS: "-E UTF8 --locale=en_US.UTF-8" ports: - "127.0.0.1:5432:5432" # Only bind to localhost volumes: - postgres_data:/var/lib/postgresql/data - ./backups:/backups networks: - fluxbase-network healthcheck: test: ["CMD-SHELL", "pg_isready -U postgres"] interval: 10s timeout: 5s retries: 5 restart: unless-stopped # Resource limits deploy: resources: limits: cpus: "2" memory: 4G reservations: cpus: "1" memory: 2G
redis: image: redis:7-alpine container_name: fluxbase-redis command: redis-server --requirepass ${REDIS_PASSWORD} ports: - "127.0.0.1:6379:6379" volumes: - redis_data:/data networks: - fluxbase-network healthcheck: test: ["CMD", "redis-cli", "ping"] interval: 10s timeout: 3s retries: 5 restart: unless-stopped
fluxbase: image: ghcr.io/fluxbase-eu/fluxbase:latest container_name: fluxbase depends_on: postgres: condition: service_healthy redis: condition: service_healthy environment: # Database FLUXBASE_DATABASE_HOST: postgres FLUXBASE_DATABASE_PORT: 5432 FLUXBASE_DATABASE_USER: postgres FLUXBASE_DATABASE_PASSWORD: ${POSTGRES_PASSWORD} FLUXBASE_DATABASE_DATABASE: fluxbase FLUXBASE_DATABASE_SSL_MODE: disable FLUXBASE_DATABASE_MAX_CONNECTIONS: 25 FLUXBASE_DATABASE_MIN_CONNECTIONS: 5
# Authentication FLUXBASE_AUTH_JWT_SECRET: ${JWT_SECRET} FLUXBASE_AUTH_JWT_EXPIRY: 15m FLUXBASE_AUTH_REFRESH_EXPIRY: 168h
# Redis FLUXBASE_REDIS_ENABLED: "true" FLUXBASE_REDIS_HOST: redis FLUXBASE_REDIS_PORT: 6379 FLUXBASE_REDIS_PASSWORD: ${REDIS_PASSWORD}
# Server FLUXBASE_BASE_URL: https://api.yourdomain.com FLUXBASE_ENVIRONMENT: production FLUXBASE_DEBUG: "false"
# Email (SendGrid example) FLUXBASE_EMAIL_ENABLED: "true" FLUXBASE_EMAIL_PROVIDER: sendgrid FLUXBASE_EMAIL_FROM_ADDRESS: noreply@yourdomain.com FLUXBASE_EMAIL_FROM_NAME: "Your App" FLUXBASE_EMAIL_SENDGRID_API_KEY: ${SENDGRID_API_KEY}
# Storage (S3) FLUXBASE_STORAGE_PROVIDER: s3 FLUXBASE_STORAGE_S3_BUCKET: your-bucket FLUXBASE_STORAGE_S3_REGION: us-east-1 FLUXBASE_STORAGE_S3_ACCESS_KEY: ${AWS_ACCESS_KEY} FLUXBASE_STORAGE_S3_SECRET_KEY: ${AWS_SECRET_KEY}
# Rate Limiting FLUXBASE_RATE_LIMIT_ENABLED: "true" FLUXBASE_RATE_LIMIT_REQUESTS_PER_SECOND: 100
# Metrics FLUXBASE_METRICS_ENABLED: "true" FLUXBASE_METRICS_PORT: 9090 ports: - "8080:8080" - "127.0.0.1:9090:9090" # Metrics (internal only) volumes: - ./storage:/app/storage - ./config:/app/config - ./logs:/app/logs networks: - fluxbase-network restart: unless-stopped healthcheck: test: ["CMD", "curl", "-f", "http://localhost:8080/health"] interval: 30s timeout: 5s retries: 3 start_period: 10s deploy: resources: limits: cpus: "4" memory: 8G reservations: cpus: "2" memory: 4G
# Nginx reverse proxy with SSL nginx: image: nginx:alpine container_name: fluxbase-nginx depends_on: - fluxbase ports: - "80:80" - "443:443" volumes: - ./nginx.conf:/etc/nginx/nginx.conf:ro - ./ssl:/etc/nginx/ssl:ro - ./nginx-logs:/var/log/nginx networks: - fluxbase-network restart: unless-stopped
volumes: postgres_data: redis_data:
networks: fluxbase-network: driver: bridgeCreate .env file:
# PostgreSQLPOSTGRES_PASSWORD=your-very-secure-postgres-password
# RedisREDIS_PASSWORD=your-very-secure-redis-password
# Fluxbase AuthJWT_SECRET=your-jwt-secret-at-least-32-characters-long
# Email (SendGrid)SENDGRID_API_KEY=SG.xxxxxxxxxxxxx
# AWS S3 StorageAWS_ACCESS_KEY=AKIAXXXXXXXXXXXXXXXXAWS_SECRET_KEY=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxImportant: Add .env to .gitignore!
Section titled “Important: Add .env to .gitignore!”Building Custom Images
Section titled “Building Custom Images”Build from Source
Section titled “Build from Source”# Clone the repositorygit clone https://github.com/your-org/fluxbase.gitcd fluxbase
# Build the imagedocker build -t fluxbase:custom .
# With build args for versioningdocker build \ --build-arg VERSION=1.0.0 \ --build-arg COMMIT=$(git rev-parse HEAD) \ --build-arg BUILD_DATE=$(date -u +"%Y-%m-%dT%H:%M:%SZ") \ -t fluxbase:1.0.0 \ .Multi-Architecture Build
Section titled “Multi-Architecture Build”# Enable buildxdocker buildx create --use
# Build for multiple platformsdocker buildx build \ --platform linux/amd64,linux/arm64 \ -t ghcr.io/your-org/fluxbase:latest \ --push \ .Nginx Configuration
Section titled “Nginx Configuration”Create nginx.conf:
events { worker_connections 1024;}
http { # Rate limiting limit_req_zone $binary_remote_addr zone=api_limit:10m rate=10r/s;
# Upstream Fluxbase upstream fluxbase { server fluxbase:8080; keepalive 32; }
# Redirect HTTP to HTTPS server { listen 80; server_name api.yourdomain.com; return 301 https://$host$request_uri; }
# HTTPS Server server { listen 443 ssl http2; server_name api.yourdomain.com;
# SSL Configuration ssl_certificate /etc/nginx/ssl/cert.pem; ssl_certificate_key /etc/nginx/ssl/key.pem; ssl_protocols TLSv1.2 TLSv1.3; ssl_ciphers HIGH:!aNULL:!MD5; ssl_prefer_server_ciphers on;
# Security Headers add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; add_header X-Frame-Options "SAMEORIGIN" always; add_header X-Content-Type-Options "nosniff" always; add_header X-XSS-Protection "1; mode=block" always;
# Logging access_log /var/log/nginx/access.log; error_log /var/log/nginx/error.log;
# Client body size (for file uploads) client_max_body_size 2G;
# Proxy settings proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme;
# API endpoints location / { limit_req zone=api_limit burst=20 nodelay; proxy_pass http://fluxbase; }
# WebSocket endpoint (realtime) location /realtime { proxy_pass http://fluxbase; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_read_timeout 86400; }
# Health check (no rate limit) location /health { proxy_pass http://fluxbase; access_log off; } }}Database Backups
Section titled “Database Backups”Automated Backup Script
Section titled “Automated Backup Script”Create backup.sh:
#!/bin/bash
BACKUP_DIR="/backups"TIMESTAMP=$(date +%Y%m%d_%H%M%S)FILENAME="fluxbase_backup_${TIMESTAMP}.sql.gz"
# Create backupdocker exec fluxbase-postgres pg_dump \ -U postgres \ -d fluxbase \ -F c \ | gzip > "${BACKUP_DIR}/${FILENAME}"
# Keep only last 7 days of backupsfind ${BACKUP_DIR} -name "fluxbase_backup_*.sql.gz" -mtime +7 -delete
echo "Backup created: ${FILENAME}"Make it executable:
chmod +x backup.shSchedule with Cron
Section titled “Schedule with Cron”# Edit crontabcrontab -e
# Add daily backup at 2 AM0 2 * * * /path/to/backup.sh >> /var/log/fluxbase-backup.log 2>&1Restore from Backup
Section titled “Restore from Backup”# Stop the applicationdocker-compose stop fluxbase
# Restore databasegunzip -c /backups/fluxbase_backup_20240126_020000.sql.gz | \ docker exec -i fluxbase-postgres pg_restore \ -U postgres \ -d fluxbase \ --clean
# Start the applicationdocker-compose start fluxbaseMonitoring with Prometheus
Section titled “Monitoring with Prometheus”Add Prometheus to docker-compose.yml:
prometheus: image: prom/prometheus:latest container_name: fluxbase-prometheus command: - "--config.file=/etc/prometheus/prometheus.yml" - "--storage.tsdb.path=/prometheus" volumes: - ./prometheus.yml:/etc/prometheus/prometheus.yml - prometheus_data:/prometheus ports: - "127.0.0.1:9091:9090" networks: - fluxbase-network restart: unless-stopped
grafana: image: grafana/grafana:latest container_name: fluxbase-grafana environment: GF_SECURITY_ADMIN_PASSWORD: ${GRAFANA_PASSWORD} volumes: - grafana_data:/var/lib/grafana ports: - "3000:3000" networks: - fluxbase-network restart: unless-stoppedCreate prometheus.yml:
global: scrape_interval: 15s evaluation_interval: 15s
scrape_configs: - job_name: "fluxbase" static_configs: - targets: ["fluxbase:9090"]
- job_name: "postgres" static_configs: - targets: ["postgres-exporter:9187"]Logging
Section titled “Logging”Centralized Logging with Loki
Section titled “Centralized Logging with Loki”loki: image: grafana/loki:latest container_name: fluxbase-loki ports: - "127.0.0.1:3100:3100" volumes: - ./loki-config.yml:/etc/loki/local-config.yaml - loki_data:/loki networks: - fluxbase-network restart: unless-stopped
promtail: image: grafana/promtail:latest container_name: fluxbase-promtail volumes: - /var/log:/var/log - ./promtail-config.yml:/etc/promtail/config.yml - /var/lib/docker/containers:/var/lib/docker/containers:ro networks: - fluxbase-network restart: unless-stoppedTroubleshooting
Section titled “Troubleshooting”Container Won’t Start
Section titled “Container Won’t Start”# Check logsdocker-compose logs fluxbase
# Common issues:# 1. Database not ready - wait for healthcheck# 2. Missing environment variables# 3. Port already in use
# Verify environment variablesdocker-compose config
# Check port conflictssudo netstat -tlnp | grep 8080Database Connection Failed
Section titled “Database Connection Failed”# Test database connectivitydocker exec -it fluxbase-postgres psql -U postgres -d fluxbase
# Check connection from Fluxbase containerdocker exec -it fluxbase curl postgres:5432
# Verify networkdocker network inspect fluxbase-networkOut of Memory
Section titled “Out of Memory”# Check container statsdocker stats
# Increase memory limits in docker-compose.ymldeploy: resources: limits: memory: 8GSlow Performance
Section titled “Slow Performance”-
Check database indexes:
SELECT schemaname, tablename, indexnameFROM pg_indexesWHERE schemaname = 'public'; -
Monitor connection pool:
SELECT count(*) FROM pg_stat_activity; -
Enable query logging:
Terminal window FLUXBASE_DEBUG=true
Upgrading
Section titled “Upgrading”Rolling Update
Section titled “Rolling Update”# Pull latest imagedocker-compose pull fluxbase
# Recreate container with new imagedocker-compose up -d --no-deps fluxbase
# Check healthcurl http://localhost:8080/healthWith Downtime
Section titled “With Downtime”# Stop all servicesdocker-compose down
# Pull latest imagesdocker-compose pull
# Start servicesdocker-compose up -d
# Verifydocker-compose psRollback
Section titled “Rollback”# Use specific versiondocker-compose stop fluxbasedocker run -d --name fluxbase ghcr.io/fluxbase-eu/fluxbase:0.9.0Security Best Practices
Section titled “Security Best Practices”-
Use secrets management:
Terminal window # Docker secrets (Swarm mode)echo "my-secret" | docker secret create jwt_secret - -
Run as non-root:
USER fluxbase # Already configured in official image -
Limit container capabilities:
cap_drop:- ALLcap_add:- NET_BIND_SERVICE -
Use read-only filesystem:
read_only: truetmpfs:- /tmp- /app/logs -
Scan images for vulnerabilities:
Terminal window docker scan ghcr.io/fluxbase-eu/fluxbase:latest
Next Steps
Section titled “Next Steps”- Kubernetes Deployment - Scale with Kubernetes
- Production Checklist - Pre-deployment checklist
- Scaling Guide - Optimize performance