This guide provides comprehensive instructions for building, running, and securing the Gemini Flow backend using Docker.
- Overview
- Quick Start
- Building the Image
- Running the Container
- Docker Compose
- Security Verification
- Health Checks
- Troubleshooting
- Best Practices
The Dockerfile uses a two-stage build process:
-
Builder Stage (node:18-alpine)
- Installs all dependencies (including devDependencies)
- Prepares application for production
- Prunes development dependencies
-
Production Stage (node:18-alpine)
- Minimal runtime image
- Non-root user (geminiflow, UID 1001)
- dumb-init for proper signal handling
- Security hardening
- ✅ Non-root user: Runs as UID 1001 (geminiflow)
- ✅ Multi-stage build: Smaller image, no build tools in production
- ✅ Signal handling: dumb-init handles SIGTERM/SIGINT properly
- ✅ File ownership: All files owned by non-root user
- ✅ Health checks: Validates service availability
- ✅ Resource limits: CPU and memory constraints via docker-compose
- ✅ Security options: no-new-privileges flag enabled
| Build Type | Size | Reduction |
|---|---|---|
| Single-stage (baseline) | ~180MB | - |
| Multi-stage (optimized) | ~140MB | 22% |
# Build and start all services
docker-compose up -d
# View logs
docker-compose logs -f backend
# Stop services
docker-compose down
# Stop and remove volumes
docker-compose down -v# Build image
docker build -t gemini-flow-backend:latest backend/
# Run container
docker run -d \
--name gemini-flow-backend \
-p 3001:3001 \
-e GOOGLE_API_KEY="your-api-key" \
gemini-flow-backend:latest
# View logs
docker logs -f gemini-flow-backend
# Stop container
docker stop gemini-flow-backendcd backend
docker build -t gemini-flow-backend:latest .docker build \
--build-arg BUILD_VERSION=1.0.0 \
--build-arg BUILD_DATE=$(date -u +"%Y-%m-%dT%H:%M:%SZ") \
-t gemini-flow-backend:latest \
backend/docker build --no-cache -t gemini-flow-backend:latest backend/docker buildx build \
--platform linux/amd64,linux/arm64 \
-t gemini-flow-backend:latest \
backend/docker run -d \
--name gemini-flow-backend \
-p 3001:3001 \
gemini-flow-backend:latestdocker run -d \
--name gemini-flow-backend \
-p 3001:3001 \
-e NODE_ENV=production \
-e PORT=3001 \
-e LOG_LEVEL=info \
-e GOOGLE_API_KEY="your-api-key-here" \
gemini-flow-backend:latestdocker run -d \
--name gemini-flow-backend \
-p 3001:3001 \
-v $(pwd)/data:/app/.data \
-v $(pwd)/logs:/app/logs \
-e GOOGLE_API_KEY="your-api-key-here" \
gemini-flow-backend:latestdocker run -d \
--name gemini-flow-backend \
-p 3001:3001 \
--user 1001:1001 \
--security-opt no-new-privileges:true \
--memory=512m \
--cpus=1 \
-e GOOGLE_API_KEY="your-api-key-here" \
gemini-flow-backend:latest# Generate random API key
export GOOGLE_API_KEY=$(openssl rand -hex 32)
# Or use UUID
export GOOGLE_API_KEY=$(uuidgen)
# Run with generated key
docker run -d \
--name gemini-flow-backend \
-p 3001:3001 \
-e GOOGLE_API_KEY="$GOOGLE_API_KEY" \
gemini-flow-backend:latestThe docker-compose.yml file includes:
- Backend service with security hardening
- Volume mounts for persistent data
- Resource limits (CPU/memory)
- Health checks
- Logging configuration
- Optional Redis service (commented out)
# Start services in detached mode
docker-compose up -d
# Build and start
docker-compose up -d --build
# View logs
docker-compose logs -f
# View backend logs only
docker-compose logs -f backend
# Stop services
docker-compose down
# Stop and remove volumes
docker-compose down -v
# Restart specific service
docker-compose restart backend
# Scale services (if configured)
docker-compose up -d --scale backend=3Create a .env file in the root directory:
# .env
VERSION=1.0.0
BUILD_DATE=2024-01-01T00:00:00Z
LOG_LEVEL=info
GOOGLE_API_KEY=your-api-key-here# Check user in Dockerfile
docker inspect gemini-flow-backend | grep -i user
# Expected output: "User": "geminiflow" or "User": "1001"# View processes inside container
docker exec gemini-flow-backend ps aux
# Expected: processes running as UID 1001, not root (UID 0)# Check data directory ownership
docker exec gemini-flow-backend ls -la /app/.data
# Expected: drwxr-xr-x geminiflow nodejs# Using Docker Scout (if available)
docker scout cves gemini-flow-backend:latest
# Using Trivy
docker run --rm -v /var/run/docker.sock:/var/run/docker.sock \
aquasec/trivy image gemini-flow-backend:latest
# Using Grype
grype gemini-flow-backend:latest# Check security options
docker inspect gemini-flow-backend | jq '.[0].HostConfig.SecurityOpt'
# Expected: ["no-new-privileges:true"]
# Check if running as root
docker exec gemini-flow-backend id
# Expected: uid=1001(geminiflow) gid=1001(nodejs)
# Check capabilities
docker inspect gemini-flow-backend | jq '.[0].HostConfig.CapDrop'# Check health endpoint
curl http://localhost:3001/health
# Expected response:
# {
# "status": "healthy",
# "timestamp": "2024-01-01T00:00:00.000Z",
# "service": "gemini-flow-backend"
# }# View health status
docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"
# Inspect health check logs
docker inspect gemini-flow-backend | jq '.[0].State.Health'
# View health check history
docker inspect gemini-flow-backend | jq '.[0].State.Health.Log'# Execute health check manually
docker exec gemini-flow-backend node -e \
"require('http').get('http://localhost:3001/health', (r) => {
r.on('data', d => console.log(d.toString()));
})"# Check logs
docker logs gemini-flow-backend
# Check if port is already in use
lsof -i :3001
# Check container events
docker events --filter container=gemini-flow-backend# Fix volume permissions on host
sudo chown -R 1001:1001 ./data ./logs
# Or run with correct user
docker run --user 1001:1001 ...# Test health endpoint manually
docker exec gemini-flow-backend curl http://localhost:3001/health
# Check if Node.js process is running
docker exec gemini-flow-backend ps aux | grep node
# View application logs
docker logs gemini-flow-backend# Clean build with no cache
docker build --no-cache -t gemini-flow-backend:latest backend/
# Check for Docker daemon issues
docker system info
# Clean up Docker resources
docker system prune -a# Check resource usage
docker stats gemini-flow-backend
# Adjust memory limits in docker-compose.yml
# deploy.resources.limits.memory: 512M
# Check for memory leaks in logs
docker logs gemini-flow-backend | grep -i "memory"Development:
# Use volume mounts for hot reload
docker run -d \
--name gemini-flow-dev \
-p 3001:3001 \
-v $(pwd)/backend/src:/app/src \
-e NODE_ENV=development \
gemini-flow-backend:latestProduction:
# Use docker-compose with all security options
docker-compose up -d# Follow logs with timestamps
docker logs -f --timestamps gemini-flow-backend
# View last 100 lines
docker logs --tail 100 gemini-flow-backend
# Save logs to file
docker logs gemini-flow-backend > backend.log 2>&1# Pull latest changes
git pull origin main
# Rebuild image
docker-compose build --no-cache backend
# Restart with new image
docker-compose up -d backend
# Verify new image is running
docker ps | grep gemini-flow-backend# Backup volumes
docker run --rm \
-v backend-data:/data \
-v $(pwd)/backups:/backup \
alpine tar czf /backup/backend-data-$(date +%Y%m%d).tar.gz /data
# Restore volumes
docker run --rm \
-v backend-data:/data \
-v $(pwd)/backups:/backup \
alpine tar xzf /backup/backend-data-20240101.tar.gz -C /# Real-time resource usage
docker stats gemini-flow-backend
# Container events
docker events --filter container=gemini-flow-backend --since 1h
# Export metrics
docker inspect gemini-flow-backend | jq '.[0].State'- The backend runs on port 3001 by default
- Health check endpoint:
http://localhost:3001/health - Non-root user:
geminiflow(UID 1001) - Data directory:
/app/.data - Logs directory:
/app/logs - Base image:
node:18-alpine - Signal handler:
dumb-init
For issues or questions:
- Open an issue on GitHub
- Check existing issues for similar problems
- Review Docker logs for error messages
- Verify environment variables are set correctly