# Docker Deployment Plan for n8n-MCP (v2) ## Executive Summary This document outlines a phased plan to enhance the developer experience of n8n-MCP through Docker deployment. We'll start with a simple, working solution and progressively add features like nginx HTTPS support based on user needs. ## Goals 1. **One-Command Deployment**: Users should be able to run `docker compose up -d` after minimal configuration 2. **Progressive Enhancement**: Start simple, add complexity only when needed 3. **Dual Mode Support**: Single Docker image supporting both stdio (local) and HTTP (remote) modes 4. **Automated Builds**: GitHub Actions workflow for building and publishing to GitHub Container Registry (ghcr.io) 5. **Database Persistence**: Reliable SQLite database persistence with proper volume management 6. **Cross-Platform Support**: Multi-architecture images (amd64, arm64) for broad compatibility ## Implementation Strategy ### Phase 1: Simple Docker (Week 1) - Basic Dockerfile without nginx - Simple docker-compose.yml - Essential features only - Focus on ease of use ### Phase 2: Enhanced Security (Week 2) - Optional nginx support - HTTPS capabilities - Advanced configurations - Production-ready features ### Phase 3: CI/CD & Documentation (Week 3) - GitHub Actions setup - Comprehensive documentation - Community feedback integration ## Architecture Overview ### Phase 1: Simple Container Architecture ``` ┌─────────────────────────────────────────┐ │ n8n-MCP Docker Image (Simple) │ ├─────────────────────────────────────────┤ │ Layer 1: Base Runtime │ │ - Node.js 20 Alpine (minimal) │ │ - Essential system dependencies │ ├─────────────────────────────────────────┤ │ Layer 2: Application │ │ - Production npm packages │ │ - Pre-built JavaScript from TypeScript │ ├─────────────────────────────────────────┤ │ Layer 3: Data & Config │ │ - SQLite database with auto-init │ │ - Environment-based configuration │ └─────────────────────────────────────────┘ ``` ### Phase 2: Enhanced Architecture (Optional) ``` ┌─────────────────────────────────────────┐ │ n8n-MCP Docker Image (Enhanced) │ ├─────────────────────────────────────────┤ │ Layer 1: Extended Runtime │ │ - Node.js 20 Alpine │ │ - nginx (optional via USE_NGINX) │ │ - supervisor (when nginx enabled) │ ├─────────────────────────────────────────┤ │ Layer 2: Application │ │ - Production npm packages │ │ - Pre-built JavaScript │ ├─────────────────────────────────────────┤ │ Layer 3: Security & Config │ │ - Auto-generated SSL certificates │ │ - nginx configurations │ │ - Enhanced security headers │ └─────────────────────────────────────────┘ ``` ### Dual Mode Operation ``` ┌─────────────────┐ │ Docker Container │ └────────┬─────────┘ │ ┌─────────────┴─────────────┐ │ Check MCP_MODE env var │ └─────────────┬─────────────┘ │ ┌─────────────────┴─────────────────┐ │ │ [stdio mode] [http mode] │ │ ▼ ▼ ┌───────────────┐ ┌─────────────────────┐ │ MCP Server │ │ Check USE_NGINX │ │ (stdio) │ └──────────┬──────────┘ └───────────────┘ │ │ ┌───────────┴───────────┐ │ │ │ │ [USE_NGINX=false] [USE_NGINX=true] │ │ │ │ ▼ ▼ │ ┌─────────────┐ ┌──────────────┐ │ │ Node.js │ │ supervisor │ │ │ HTTP :3000 │ ├──────┬───────┤ │ └─────────────┘ │nginx │Node.js│ │ │:443 │:3000 │ │ └──────┴───────┘ ▼ │ ┌───────────────┐ ┌───────────────┐ │ Claude Desktop│ │ mcp-remote │ └───────────────┘ └───────────────┘ ``` ## Implementation Plan ### Phase 1: Simple Docker Implementation #### 1.1 Basic Multi-Stage Dockerfile ```dockerfile # Stage 1: Dependencies FROM node:20-alpine AS deps WORKDIR /app COPY package*.json ./ # Install all dependencies including dev for building RUN npm ci # Stage 2: Builder FROM node:20-alpine AS builder WORKDIR /app COPY package*.json ./ COPY --from=deps /app/node_modules ./node_modules COPY . . # Build TypeScript RUN npm run build # Rebuild database during image build (if possible) RUN npm run rebuild || echo "Database will be initialized at runtime" # Stage 3: Simple Runtime FROM node:20-alpine AS runtime WORKDIR /app # Install only essential tools RUN apk add --no-cache curl && \ rm -rf /var/cache/apk/* # Install production dependencies only COPY package*.json ./ RUN npm ci --only=production && \ npm cache clean --force # Copy built application COPY --from=builder /app/dist ./dist COPY --from=builder /app/data ./data 2>/dev/null || mkdir -p ./data # Copy necessary files COPY .env.example .env.example COPY LICENSE LICENSE COPY README.md README.md # Add container labels LABEL org.opencontainers.image.source="https://github.com/czlonkowski/n8n-mcp" LABEL org.opencontainers.image.description="n8n MCP Server - Simple Version" LABEL org.opencontainers.image.licenses="Sustainable-Use-1.0" LABEL org.opencontainers.image.vendor="n8n-mcp" LABEL org.opencontainers.image.title="n8n-mcp" # Create data directory and fix permissions RUN mkdir -p /app/data && \ addgroup -g 1001 -S nodejs && \ adduser -S nodejs -u 1001 && \ chown -R nodejs:nodejs /app # Copy entrypoint script COPY docker/docker-entrypoint.sh /usr/local/bin/ RUN chmod +x /usr/local/bin/docker-entrypoint.sh # Switch to non-root user USER nodejs # Expose HTTP port EXPOSE 3000 # Health check HEALTHCHECK --interval=30s --timeout=10s --start-period=10s --retries=3 \ CMD curl -f http://127.0.0.1:3000/health || exit 1 # Entrypoint ENTRYPOINT ["/usr/local/bin/docker-entrypoint.sh"] CMD ["node", "dist/mcp/index.js"] ``` #### 1.2 Simple Entrypoint Script ```bash #!/bin/sh set -e # Environment variable validation if [ "$MCP_MODE" = "http" ] && [ -z "$AUTH_TOKEN" ]; then echo "ERROR: AUTH_TOKEN is required for HTTP mode" exit 1 fi # Database initialization with file locking to prevent race conditions if [ ! -f "/app/data/nodes.db" ]; then echo "Database not found. Initializing..." # Use a lock file to prevent multiple containers from initializing simultaneously ( flock -x 200 # Double-check inside the lock if [ ! -f "/app/data/nodes.db" ]; then echo "Initializing database..." cd /app && node dist/scripts/rebuild.js || { echo "ERROR: Database initialization failed" exit 1 } fi ) 200>/app/data/.db.lock fi # Fix permissions if running as root (for development) if [ "$(id -u)" = "0" ]; then echo "Running as root, fixing permissions..." chown -R nodejs:nodejs /app/data # Switch to nodejs user exec su-exec nodejs "$@" fi # Trap signals for graceful shutdown trap 'echo "Shutting down..."; kill -TERM $PID' TERM INT # Execute the main command in background "$@" & PID=$! wait $PID ``` #### 1.3 .dockerignore File ```dockerignore # .dockerignore node_modules npm-debug.log .git .gitignore .env .env.local data/nodes.db data/*.db dist .DS_Store *.log coverage .nyc_output .vscode .idea *.swp *.swo *~ ``` #### 1.4 Simple docker-compose.yml ```yaml # docker-compose.yml version: '3.8' services: n8n-mcp: image: ghcr.io/czlonkowski/n8n-mcp:latest container_name: n8n-mcp restart: unless-stopped # Environment configuration environment: # Mode configuration MCP_MODE: ${MCP_MODE:-http} AUTH_TOKEN: ${AUTH_TOKEN:?AUTH_TOKEN is required for HTTP mode} # Application settings NODE_ENV: ${NODE_ENV:-production} LOG_LEVEL: ${LOG_LEVEL:-info} PORT: ${PORT:-3000} # Database NODE_DB_PATH: ${NODE_DB_PATH:-/app/data/nodes.db} REBUILD_ON_START: ${REBUILD_ON_START:-false} # Volumes for persistence volumes: - n8n-mcp-data:/app/data # Port mapping ports: - "${PORT:-3000}:3000" # Resource limits deploy: resources: limits: memory: 512M reservations: memory: 256M # Health check healthcheck: test: ["CMD", "curl", "-f", "http://127.0.0.1:3000/health"] interval: 30s timeout: 10s retries: 3 start_period: 40s # Named volume for data persistence volumes: n8n-mcp-data: driver: local ``` #### 1.5 Environment Variable Documentation ```bash # .env.example # n8n-MCP Docker Configuration # Mode configuration # - stdio: For Claude Desktop integration # - http: For remote access via HTTP/HTTPS MCP_MODE=http # Authentication token for HTTP mode (required) # Generate with: openssl rand -base64 32 AUTH_TOKEN=your-secure-token-here # Server configuration PORT=3000 NODE_ENV=production LOG_LEVEL=info # Database configuration NODE_DB_PATH=/app/data/nodes.db REBUILD_ON_START=false # Optional: For future nginx support USE_NGINX=false ``` #### 1.6 Docker-specific Environment Template ```bash # .env.docker # Docker-specific environment template # Copy to .env and fill in values # Required for HTTP mode AUTH_TOKEN= # Server configuration PORT=3000 HTTP_PORT=80 HTTPS_PORT=443 # Application settings NODE_ENV=production LOG_LEVEL=info MCP_MODE=http # Database NODE_DB_PATH=/app/data/nodes.db REBUILD_ON_START=false # Optional nginx mode USE_NGINX=false ``` #### 1.7 Development Override File ```yaml # docker-compose.override.yml # Local development overrides (git-ignored) version: '3.8' services: n8n-mcp: environment: NODE_ENV: development LOG_LEVEL: debug REBUILD_ON_START: "true" volumes: # Mount source for hot reload - ./src:/app/src:ro - ./scripts:/app/scripts:ro ``` ### Phase 2: Enhanced Docker with nginx (Week 2) #### 2.1 Enhanced Dockerfile with nginx Support ```dockerfile # Dockerfile.nginx - Enhanced version with HTTPS support FROM node:20-alpine AS deps WORKDIR /app COPY package*.json ./ RUN npm ci FROM node:20-alpine AS builder WORKDIR /app COPY package*.json ./ COPY --from=deps /app/node_modules ./node_modules COPY . . RUN npm run build RUN npm run rebuild || echo "Database will be initialized at runtime" FROM node:20-alpine AS runtime WORKDIR /app # Install nginx, supervisor, openssl RUN apk add --no-cache nginx supervisor openssl curl su-exec && \ rm -rf /var/cache/apk/* # Copy application COPY package*.json ./ RUN npm ci --only=production && npm cache clean --force COPY --from=builder /app/dist ./dist COPY --from=builder /app/data ./data 2>/dev/null || mkdir -p ./data # Setup users and directories RUN addgroup -g 1001 -S nodejs && \ adduser -S nodejs -u 1001 && \ mkdir -p /app/data /app/certs /var/log/supervisor /var/log/nginx \ /var/cache/nginx /var/run /etc/nginx/conf.d && \ chown -R nodejs:nodejs /app && \ chown -R nginx:nginx /var/log/nginx /var/cache/nginx # Add container labels LABEL org.opencontainers.image.source="https://github.com/czlonkowski/n8n-mcp" LABEL org.opencontainers.image.description="n8n MCP Server - nginx Enhanced Version" LABEL org.opencontainers.image.licenses="Sustainable-Use-1.0" LABEL org.opencontainers.image.vendor="n8n-mcp" LABEL org.opencontainers.image.title="n8n-mcp-nginx" # Copy configurations COPY docker/ /docker/ RUN chmod +x /docker/docker-entrypoint-nginx.sh # Generate self-signed certificate RUN openssl req -x509 -nodes -days 365 -newkey rsa:2048 \ -keyout /app/certs/server.key \ -out /app/certs/server.crt \ -subj "/C=US/ST=State/L=City/O=n8n-MCP/CN=localhost" && \ chown -R nodejs:nodejs /app/certs EXPOSE 80 443 3000 HEALTHCHECK --interval=30s --timeout=10s --start-period=10s --retries=3 \ CMD /docker/healthcheck.sh ENTRYPOINT ["/docker/docker-entrypoint-nginx.sh"] ``` #### 2.2 nginx Configuration (Simplified) ```nginx # /docker/nginx.conf user nginx; worker_processes auto; error_log /var/log/nginx/error.log warn; pid /var/run/nginx.pid; events { worker_connections 1024; } http { include /etc/nginx/mime.types; default_type application/octet-stream; log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; access_log /var/log/nginx/access.log main; sendfile on; tcp_nopush on; tcp_nodelay on; keepalive_timeout 65; server_tokens off; client_max_body_size 1m; # Rate limiting limit_req_zone $binary_remote_addr zone=mcp_limit:10m rate=10r/s; upstream mcp_backend { server 127.0.0.1:3000; } server { listen 80; listen [::]:80; return 301 https://$host$request_uri; } server { listen 443 ssl http2; listen [::]:443 ssl http2; ssl_certificate /app/certs/server.crt; ssl_certificate_key /app/certs/server.key; ssl_protocols TLSv1.2 TLSv1.3; ssl_ciphers HIGH:!aNULL:!MD5; ssl_prefer_server_ciphers on; # Security headers add_header X-Frame-Options "DENY" always; add_header X-Content-Type-Options "nosniff" always; add_header X-XSS-Protection "1; mode=block" always; add_header Strict-Transport-Security "max-age=31536000" always; # Rate limiting limit_req zone=mcp_limit burst=20 nodelay; location /mcp { # Let Node.js handle auth - nginx just proxies proxy_pass http://mcp_backend; 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; proxy_set_header Authorization $http_authorization; proxy_cache_bypass $http_upgrade; proxy_read_timeout 60s; } location /health { proxy_pass http://mcp_backend/health; access_log off; } location / { return 301 /health; } } } ``` #### 2.3 Supervisor Configuration with Log Rotation ```ini # /docker/supervisord.conf [supervisord] nodaemon=true user=root logfile=/var/log/supervisor/supervisord.log pidfile=/var/run/supervisord.pid logfile_maxbytes=10MB logfile_backups=3 [program:nginx] command=/usr/sbin/nginx -g "daemon off;" autostart=true autorestart=true stdout_logfile=/var/log/supervisor/nginx.log stderr_logfile=/var/log/supervisor/nginx.error.log stdout_logfile_maxbytes=10MB stdout_logfile_backups=3 stderr_logfile_maxbytes=10MB stderr_logfile_backups=3 priority=10 [program:mcp-server] command=su-exec nodejs node /app/dist/mcp/index.js directory=/app autostart=true autorestart=true environment=NODE_ENV="production" stdout_logfile=/var/log/supervisor/mcp.log stderr_logfile=/var/log/supervisor/mcp.error.log stdout_logfile_maxbytes=10MB stdout_logfile_backups=3 stderr_logfile_maxbytes=10MB stderr_logfile_backups=3 priority=20 [group:mcp] programs=nginx,mcp-server ``` #### 2.4 Enhanced docker-compose.nginx.yml ```yaml # docker-compose.nginx.yml - For HTTPS deployments version: '3.8' services: n8n-mcp: image: ghcr.io/czlonkowski/n8n-mcp:nginx container_name: n8n-mcp-https restart: unless-stopped environment: MCP_MODE: http AUTH_TOKEN: ${AUTH_TOKEN:?AUTH_TOKEN is required} USE_NGINX: "true" NODE_ENV: ${NODE_ENV:-production} LOG_LEVEL: ${LOG_LEVEL:-info} volumes: - n8n-mcp-data:/app/data # Optional: Custom certificates # - ./certs/server.crt:/app/certs/server.crt:ro # - ./certs/server.key:/app/certs/server.key:ro ports: - "${HTTP_PORT:-80}:80" - "${HTTPS_PORT:-443}:443" # Resource limits deploy: resources: limits: memory: 768M reservations: memory: 512M healthcheck: test: ["CMD", "/docker/healthcheck.sh"] interval: 30s timeout: 10s retries: 3 volumes: n8n-mcp-data: driver: local ``` #### 2.5 Enhanced Entrypoint for nginx Mode ```bash #!/bin/sh # /docker/docker-entrypoint-nginx.sh set -e # Environment variable validation if [ "$MCP_MODE" = "http" ] && [ -z "$AUTH_TOKEN" ]; then echo "ERROR: AUTH_TOKEN is required for HTTP mode" exit 1 fi # Database initialization with locking if [ ! -f "/app/data/nodes.db" ]; then ( flock -x 200 if [ ! -f "/app/data/nodes.db" ]; then echo "Initializing database..." su-exec nodejs node /app/dist/scripts/rebuild.js || exit 1 fi ) 200>/app/data/.db.lock fi # Fix permissions chown -R nodejs:nodejs /app/data if [ "$USE_NGINX" = "true" ] && [ "$MCP_MODE" = "http" ]; then echo "Starting with nginx HTTPS support..." exec /usr/bin/supervisord -c /docker/supervisord.conf else echo "Starting Node.js directly..." # Trap signals for graceful shutdown trap 'echo "Shutting down..."; kill -TERM $PID' TERM INT su-exec nodejs node /app/dist/mcp/index.js & PID=$! wait $PID fi ``` #### 2.6 Health Check Script ```bash #!/bin/sh # /docker/healthcheck.sh if [ "$USE_NGINX" = "true" ]; then # Check nginx first curl -f -k https://127.0.0.1/health || \ curl -f http://127.0.0.1:3000/health || exit 1 else # Direct Node.js check curl -f http://127.0.0.1:3000/health || exit 1 fi ``` ### Phase 3: CI/CD & Documentation (Week 3) #### 3.1 GitHub Actions Workflow ```yaml # .github/workflows/docker-build.yml name: Build and Push Docker Images on: push: branches: - main tags: - 'v*' pull_request: branches: - main workflow_dispatch: env: REGISTRY: ghcr.io IMAGE_NAME: ${{ github.repository }} jobs: build-simple: name: Build Simple Docker Image runs-on: ubuntu-latest permissions: contents: read packages: write steps: - name: Checkout repository uses: actions/checkout@v4 - name: Set up QEMU uses: docker/setup-qemu-action@v3 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - name: Log in to GitHub Container Registry uses: docker/login-action@v3 with: registry: ${{ env.REGISTRY }} username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: Extract metadata id: meta uses: docker/metadata-action@v5 with: images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} tags: | type=ref,event=branch type=ref,event=pr type=semver,pattern={{version}} type=semver,pattern={{major}}.{{minor}} type=sha,prefix={{branch}}-,format=short type=raw,value=latest,enable={{is_default_branch}} - name: Build and push simple Docker image uses: docker/build-push-action@v5 with: context: . file: ./Dockerfile platforms: linux/amd64,linux/arm64 push: ${{ github.event_name != 'pull_request' }} tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} cache-from: type=gha cache-to: type=gha,mode=max build-nginx: name: Build nginx-enhanced Docker Image runs-on: ubuntu-latest permissions: contents: read packages: write steps: - name: Checkout repository uses: actions/checkout@v4 - name: Set up QEMU uses: docker/setup-qemu-action@v3 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - name: Log in to GitHub Container Registry if: github.event_name != 'pull_request' uses: docker/login-action@v3 with: registry: ${{ env.REGISTRY }} username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: Extract metadata id: meta uses: docker/metadata-action@v5 with: images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} flavor: | suffix=-nginx tags: | type=ref,event=branch type=ref,event=pr type=semver,pattern={{version}} type=raw,value=nginx,enable={{is_default_branch}} - name: Build and push nginx Docker image uses: docker/build-push-action@v5 with: context: . file: ./Dockerfile.nginx platforms: linux/amd64,linux/arm64 push: ${{ github.event_name != 'pull_request' }} tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} cache-from: type=gha cache-to: type=gha,mode=max ``` #### 3.2 Quick Start Documentation ```markdown # Docker Quick Start Guide ## Option 1: Simple HTTP Server (Recommended to Start) 1. Create a `.env` file: ```bash # Required for HTTP mode AUTH_TOKEN=$(openssl rand -base64 32) echo "AUTH_TOKEN=$AUTH_TOKEN" > .env ``` 2. Run with Docker Compose: ```bash docker compose up -d ``` 3. Test the server: ```bash curl http://localhost:3000/health ``` 4. Configure Claude Desktop with mcp-remote: ```json { "mcpServers": { "n8n-remote": { "command": "npx", "args": [ "-y", "@modelcontextprotocol/mcp-remote@latest", "connect", "http://localhost:3000/mcp" ], "env": { "MCP_AUTH_TOKEN": "your-auth-token-here" } } } } ``` ## Option 2: Local stdio Mode (Claude Desktop Direct) ```json { "mcpServers": { "n8n-docker": { "command": "docker", "args": [ "run", "--rm", "-i", "-e", "MCP_MODE=stdio", "-v", "n8n-mcp-data:/app/data", "ghcr.io/czlonkowski/n8n-mcp:latest" ] } } } ``` ## Option 3: HTTPS with nginx (Production) ```bash # Use the nginx-enhanced image docker compose -f docker-compose.nginx.yml up -d ``` Access via HTTPS: https://your-server/mcp ``` ## Implementation Details ### Critical Issues Addressed #### 1. nginx Auth Token Validation Instead of trying to validate tokens in nginx configuration, we: - Let nginx act as a simple proxy - Pass Authorization header to Node.js - Node.js handles all authentication logic - This avoids nginx string interpolation issues #### 2. Database Race Condition Prevention Implemented file locking in entrypoint script: ```bash ( flock -x 200 if [ ! -f "/app/data/nodes.db" ]; then echo "Initializing database..." su-exec nodejs node /app/dist/scripts/rebuild.js || exit 1 fi ) 200>/app/data/.db.lock ``` #### 3. Volume Permissions - Use `su-exec` for proper user switching - Fix permissions at runtime in entrypoint - Consistent nodejs user (UID 1001) #### 4. Simplified Architecture - Phase 1: Simple Node.js-only Docker image - Phase 2: Optional nginx enhancement - Users choose based on their needs #### 5. Essential Files Structure ``` docker/ ├── docker-entrypoint.sh # Simple entrypoint ├── docker-entrypoint-nginx.sh # Enhanced entrypoint ├── nginx.conf # Main nginx config ├── supervisord.conf # Process manager config └── healthcheck.sh # Health check script ``` ### Testing Strategy #### Test Script for Docker Deployment ```bash #!/bin/bash # scripts/test-docker.sh echo "🧪 Testing n8n-MCP Docker Deployment" # Test 1: Build simple image echo "1. Building simple Docker image..." docker build -t n8n-mcp:test . # Test 2: Test stdio mode echo "2. Testing stdio mode..." echo '{"jsonrpc":"2.0","method":"tools/list","id":1}' | \ docker run --rm -i -e MCP_MODE=stdio n8n-mcp:test # Test 3: Test HTTP mode echo "3. Testing HTTP mode..." docker run -d --name test-http \ -e MCP_MODE=http \ -e AUTH_TOKEN=test-token \ -p 3001:3000 \ n8n-mcp:test sleep 5 # Check health curl -f http://localhost:3001/health || echo "Health check failed" # Test auth curl -H "Authorization: Bearer test-token" \ -H "Content-Type: application/json" \ -d '{"jsonrpc":"2.0","method":"tools/list","id":1}' \ http://localhost:3001/mcp docker stop test-http && docker rm test-http # Test 4: Volume persistence echo "4. Testing volume persistence..." docker volume create test-data docker run -d --name test-persist \ -v test-data:/app/data \ -e MCP_MODE=http \ -e AUTH_TOKEN=test \ -p 3002:3000 \ n8n-mcp:test sleep 10 docker exec test-persist ls -la /app/data/nodes.db docker stop test-persist && docker rm test-persist docker volume rm test-data echo "✅ Docker tests completed!" ``` ## Success Metrics 1. **Ease of Use**: Setup time < 2 minutes 2. **Performance**: < 5 second startup time 3. **Compatibility**: Works on Linux, macOS, Windows (Docker Desktop) 4. **Reliability**: Automatic database initialization 5. **Security**: Built-in auth token validation ## Implementation Checklist ### Week 1: Phase 1 - Simple Docker - [ ] Create `Dockerfile` with labels - [ ] Create `docker/docker-entrypoint.sh` with validation and graceful shutdown - [ ] Create `.dockerignore` - [ ] Create `docker-compose.yml` with resource limits - [ ] Create `.env.docker` template - [ ] Create `scripts/test-docker.sh` - [ ] Test both stdio and HTTP modes - [ ] Update README with Docker quick start ### Week 2: Phase 2 - Enhanced Features - [ ] Create `Dockerfile.nginx` with labels - [ ] Create `docker/docker-entrypoint-nginx.sh` - [ ] Create `docker/nginx.conf` - [ ] Create `docker/supervisord.conf` with log rotation - [ ] Create `docker/healthcheck.sh` - [ ] Create `docker-compose.nginx.yml` with resource limits - [ ] Test HTTPS functionality - [ ] Document SSL certificate options ### Week 3: Phase 3 - CI/CD & Polish - [ ] Set up GitHub Actions workflow - [ ] Configure GHCR permissions - [ ] Test multi-architecture builds - [ ] Create Docker quick start guide - [ ] Add `docker-compose.override.yml` to `.gitignore` - [ ] Tag first release - [ ] Create troubleshooting guide - [ ] Gather community feedback ## Key Decisions ### 1. Progressive Enhancement Strategy - Start with simple Node.js-only image - Add nginx as optional enhancement - Let users choose complexity level ### 2. Authentication Strategy - Node.js handles all auth validation - nginx acts as simple proxy - Avoids complex nginx configurations ### 3. File Structure ``` . ├── Dockerfile # Simple version ├── Dockerfile.nginx # Enhanced version ├── docker-compose.yml # Simple deployment ├── docker-compose.nginx.yml # HTTPS deployment ├── .dockerignore └── docker/ ├── docker-entrypoint.sh ├── docker-entrypoint-nginx.sh ├── nginx.conf ├── supervisord.conf └── healthcheck.sh ``` ### 4. Image Tags - `ghcr.io/czlonkowski/n8n-mcp:latest` - Simple version - `ghcr.io/czlonkowski/n8n-mcp:nginx` - nginx-enhanced - `ghcr.io/czlonkowski/n8n-mcp:v1.0.0` - Version tags ## Conclusion This revised Docker deployment plan addresses all critical issues identified in the review while maintaining a pragmatic, phased approach. By starting simple and progressively adding features, we ensure that users can quickly get started while still having access to production-grade features when needed. The plan prioritizes ease of use, security, and maintainability.