Skip to main content
Glama
docker-production.md17 kB
# Docker Production Deployment Examples Complete configuration examples for deploying MCP WordPress in production environments using Docker. ## Basic Production Setup ### Dockerfile (Production) ```dockerfile # Multi-stage build for production FROM node:20-alpine AS builder # Set working directory WORKDIR /app # Copy package files COPY package*.json ./ # Install dependencies RUN npm ci --only=production # Copy source code COPY . . # Build application RUN npm run build # Production stage FROM node:20-alpine AS production # Install security updates RUN apk update && apk upgrade && apk add --no-cache \ ca-certificates \ && update-ca-certificates # Create non-root user RUN addgroup -g 1001 -S nodejs && \ adduser -S nextjs -u 1001 # Set working directory WORKDIR /app # Copy built application from builder stage COPY --from=builder --chown=nextjs:nodejs /app/dist ./dist COPY --from=builder --chown=nextjs:nodejs /app/node_modules ./node_modules COPY --from=builder --chown=nextjs:nodejs /app/package*.json ./ # Create necessary directories RUN mkdir -p cache logs && chown -R nextjs:nodejs cache logs # Switch to non-root user USER nextjs # Expose port EXPOSE 3000 # Health check HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \ CMD node -e "require('http').get('http://localhost:3000/health', (res) => { process.exit(res.statusCode === 200 ? 0 : 1) })" # Start application CMD ["node", "dist/index.js"] ``` ### Docker Compose (Production) ```yaml # docker-compose.prod.yml version: "3.8" services: mcp-wordpress: build: context: . dockerfile: Dockerfile target: production container_name: mcp-wordpress-prod restart: unless-stopped ports: - "3000:3000" environment: - NODE_ENV=production - WORDPRESS_SITE_URL=${WORDPRESS_SITE_URL} - WORDPRESS_USERNAME=${WORDPRESS_USERNAME} - WORDPRESS_APP_PASSWORD=${WORDPRESS_APP_PASSWORD} - CACHE_ENABLED=true - CACHE_TTL=600 - SECURITY_MONITORING=true - LOG_LEVEL=info volumes: - ./cache:/app/cache - ./logs:/app/logs - ./config:/app/config:ro networks: - mcp-network deploy: resources: limits: cpus: "0.5" memory: 512M reservations: cpus: "0.25" memory: 256M healthcheck: test: [ "CMD", "node", "-e", "require('http').get('http://localhost:3000/health', (res) => { process.exit(res.statusCode === 200 ? 0 : 1) })", ] interval: 30s timeout: 10s retries: 3 start_period: 40s logging: driver: "json-file" options: max-size: "10m" max-file: "3" networks: mcp-network: driver: bridge volumes: cache-data: logs-data: ``` ### Environment Configuration **.env.production** ```bash # Production Environment Configuration NODE_ENV=production # WordPress Configuration WORDPRESS_SITE_URL=https://your-production-site.com WORDPRESS_USERNAME=api-user WORDPRESS_APP_PASSWORD=secure-production-password # Performance Settings CACHE_ENABLED=true CACHE_TTL=600 CACHE_MAX_ITEMS=1000 CACHE_MAX_MEMORY_MB=200 # Security Settings SECURITY_MONITORING=true RATE_LIMIT_ENABLED=true RATE_LIMIT_WINDOW=900000 RATE_LIMIT_MAX=100 # Logging LOG_LEVEL=info LOG_FORMAT=json LOG_FILE=/app/logs/mcp-wordpress.log # Monitoring PERFORMANCE_MONITORING=true METRICS_ENABLED=true HEALTH_CHECK_ENABLED=true # Timeouts API_TIMEOUT=15000 CONNECTION_TIMEOUT=10000 ``` ## Load Balanced Setup ### Docker Compose with Load Balancer ```yaml # docker-compose.loadbalanced.yml version: "3.8" services: nginx: image: nginx:alpine container_name: mcp-nginx-lb ports: - "80:80" - "443:443" volumes: - ./nginx.conf:/etc/nginx/nginx.conf:ro - ./ssl:/etc/nginx/ssl:ro depends_on: - mcp-wordpress-1 - mcp-wordpress-2 networks: - mcp-network restart: unless-stopped mcp-wordpress-1: build: context: . dockerfile: Dockerfile target: production container_name: mcp-wordpress-1 environment: - NODE_ENV=production - SERVER_ID=server-1 - WORDPRESS_SITE_URL=${WORDPRESS_SITE_URL} - WORDPRESS_USERNAME=${WORDPRESS_USERNAME} - WORDPRESS_APP_PASSWORD=${WORDPRESS_APP_PASSWORD} - CACHE_ENABLED=true - REDIS_URL=redis://redis:6379 volumes: - ./cache:/app/cache - ./logs:/app/logs networks: - mcp-network depends_on: - redis restart: unless-stopped mcp-wordpress-2: build: context: . dockerfile: Dockerfile target: production container_name: mcp-wordpress-2 environment: - NODE_ENV=production - SERVER_ID=server-2 - WORDPRESS_SITE_URL=${WORDPRESS_SITE_URL} - WORDPRESS_USERNAME=${WORDPRESS_USERNAME} - WORDPRESS_APP_PASSWORD=${WORDPRESS_APP_PASSWORD} - CACHE_ENABLED=true - REDIS_URL=redis://redis:6379 volumes: - ./cache:/app/cache - ./logs:/app/logs networks: - mcp-network depends_on: - redis restart: unless-stopped redis: image: redis:alpine container_name: mcp-redis command: redis-server --appendonly yes volumes: - redis-data:/data networks: - mcp-network restart: unless-stopped networks: mcp-network: driver: bridge volumes: redis-data: ``` ### Nginx Configuration ```nginx # nginx.conf events { worker_connections 1024; } http { upstream mcp-backend { server mcp-wordpress-1:3000; server mcp-wordpress-2:3000; # Health checks keepalive 32; } # Rate limiting limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s; server { listen 80; server_name your-domain.com; # Redirect to HTTPS return 301 https://$server_name$request_uri; } server { listen 443 ssl http2; server_name your-domain.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 ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384; # Security headers add_header X-Frame-Options DENY; add_header X-Content-Type-Options nosniff; add_header X-XSS-Protection "1; mode=block"; add_header Strict-Transport-Security "max-age=31536000; includeSubDomains"; # Rate limiting limit_req zone=api burst=20 nodelay; location / { proxy_pass http://mcp-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; proxy_set_header X-Forwarded-Proto $scheme; # Timeouts proxy_connect_timeout 5s; proxy_send_timeout 60s; proxy_read_timeout 60s; } location /health { proxy_pass http://mcp-backend/health; access_log off; } } } ``` ## Multi-Site Production Setup ### Multi-Site Docker Compose ```yaml # docker-compose.multisite.yml version: "3.8" services: mcp-wordpress: build: context: . dockerfile: Dockerfile target: production container_name: mcp-wordpress-multisite restart: unless-stopped ports: - "3000:3000" environment: - NODE_ENV=production volumes: - ./mcp-wordpress.config.json:/app/mcp-wordpress.config.json:ro - ./cache:/app/cache - ./logs:/app/logs networks: - mcp-network deploy: resources: limits: cpus: "1.0" memory: 1G reservations: cpus: "0.5" memory: 512M networks: mcp-network: driver: bridge ``` ### Multi-Site Configuration ```json { "sites": [ { "id": "main-production", "name": "Main Production Site", "config": { "WORDPRESS_SITE_URL": "https://main.company.com", "WORDPRESS_USERNAME": "api-admin", "WORDPRESS_APP_PASSWORD": "secure-main-password", "CACHE_ENABLED": "true", "CACHE_TTL": "600", "SECURITY_MONITORING": "true", "PERFORMANCE_MONITORING": "true" } }, { "id": "blog-production", "name": "Blog Production Site", "config": { "WORDPRESS_SITE_URL": "https://blog.company.com", "WORDPRESS_USERNAME": "blog-editor", "WORDPRESS_APP_PASSWORD": "secure-blog-password", "CACHE_ENABLED": "true", "CACHE_TTL": "300" } }, { "id": "shop-production", "name": "E-commerce Production Site", "config": { "WORDPRESS_SITE_URL": "https://shop.company.com", "WORDPRESS_USERNAME": "shop-manager", "WORDPRESS_APP_PASSWORD": "secure-shop-password", "CACHE_ENABLED": "true", "RATE_LIMIT_ENABLED": "true" } } ] } ``` ## Kubernetes Deployment ### Kubernetes Manifests **Namespace** ```yaml # namespace.yaml apiVersion: v1 kind: Namespace metadata: name: mcp-wordpress ``` **ConfigMap** ```yaml # configmap.yaml apiVersion: v1 kind: ConfigMap metadata: name: mcp-wordpress-config namespace: mcp-wordpress data: NODE_ENV: "production" CACHE_ENABLED: "true" CACHE_TTL: "600" SECURITY_MONITORING: "true" LOG_LEVEL: "info" ``` **Secret** ```yaml # secret.yaml apiVersion: v1 kind: Secret metadata: name: mcp-wordpress-secret namespace: mcp-wordpress type: Opaque data: WORDPRESS_SITE_URL: <base64-encoded-url> WORDPRESS_USERNAME: <base64-encoded-username> WORDPRESS_APP_PASSWORD: <base64-encoded-password> ``` **Deployment** ```yaml # deployment.yaml apiVersion: apps/v1 kind: Deployment metadata: name: mcp-wordpress namespace: mcp-wordpress spec: replicas: 3 selector: matchLabels: app: mcp-wordpress template: metadata: labels: app: mcp-wordpress spec: containers: - name: mcp-wordpress image: docdyhr/mcp-wordpress:latest ports: - containerPort: 3000 envFrom: - configMapRef: name: mcp-wordpress-config - secretRef: name: mcp-wordpress-secret resources: requests: memory: "256Mi" cpu: "250m" limits: memory: "512Mi" cpu: "500m" livenessProbe: httpGet: path: /health port: 3000 initialDelaySeconds: 30 periodSeconds: 10 readinessProbe: httpGet: path: /health port: 3000 initialDelaySeconds: 5 periodSeconds: 5 volumeMounts: - name: cache-volume mountPath: /app/cache - name: logs-volume mountPath: /app/logs volumes: - name: cache-volume emptyDir: {} - name: logs-volume emptyDir: {} ``` **Service** ```yaml # service.yaml apiVersion: v1 kind: Service metadata: name: mcp-wordpress-service namespace: mcp-wordpress spec: selector: app: mcp-wordpress ports: - protocol: TCP port: 80 targetPort: 3000 type: ClusterIP ``` **Ingress** ```yaml # ingress.yaml apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: mcp-wordpress-ingress namespace: mcp-wordpress annotations: kubernetes.io/ingress.class: nginx cert-manager.io/cluster-issuer: letsencrypt-prod nginx.ingress.kubernetes.io/rate-limit: "10" spec: tls: - hosts: - api.company.com secretName: mcp-wordpress-tls rules: - host: api.company.com http: paths: - path: / pathType: Prefix backend: service: name: mcp-wordpress-service port: number: 80 ``` ## Monitoring and Logging ### Prometheus Configuration ```yaml # prometheus.yml global: scrape_interval: 15s scrape_configs: - job_name: "mcp-wordpress" static_configs: - targets: ["mcp-wordpress:3000"] metrics_path: /metrics scrape_interval: 30s ``` ### Docker Compose with Monitoring ```yaml # docker-compose.monitoring.yml version: "3.8" services: mcp-wordpress: build: context: . dockerfile: Dockerfile target: production container_name: mcp-wordpress environment: - NODE_ENV=production - METRICS_ENABLED=true - PROMETHEUS_ENABLED=true networks: - monitoring prometheus: image: prom/prometheus:latest container_name: prometheus ports: - "9090:9090" volumes: - ./prometheus.yml:/etc/prometheus/prometheus.yml:ro networks: - monitoring grafana: image: grafana/grafana:latest container_name: grafana ports: - "3001:3000" environment: - GF_SECURITY_ADMIN_PASSWORD=admin volumes: - grafana-data:/var/lib/grafana networks: - monitoring networks: monitoring: driver: bridge volumes: grafana-data: ``` ### Logging Configuration ```yaml # filebeat.yml filebeat.inputs: - type: log enabled: true paths: - /app/logs/*.log json.keys_under_root: true json.add_error_key: true output.elasticsearch: hosts: ["elasticsearch:9200"] setup.kibana: host: "kibana:5601" ``` ## Backup and Recovery ### Backup Script ```bash #!/bin/bash # backup.sh BACKUP_DIR="/backups" DATE=$(date +%Y%m%d_%H%M%S) # Create backup directory mkdir -p $BACKUP_DIR # Backup configuration docker cp mcp-wordpress:/app/mcp-wordpress.config.json $BACKUP_DIR/config_$DATE.json # Backup cache data docker cp mcp-wordpress:/app/cache $BACKUP_DIR/cache_$DATE # Backup logs docker cp mcp-wordpress:/app/logs $BACKUP_DIR/logs_$DATE # Create archive tar -czf $BACKUP_DIR/mcp-wordpress-backup_$DATE.tar.gz \ $BACKUP_DIR/config_$DATE.json \ $BACKUP_DIR/cache_$DATE \ $BACKUP_DIR/logs_$DATE # Cleanup rm -rf $BACKUP_DIR/config_$DATE.json $BACKUP_DIR/cache_$DATE $BACKUP_DIR/logs_$DATE echo "Backup completed: mcp-wordpress-backup_$DATE.tar.gz" ``` ### Recovery Script ```bash #!/bin/bash # restore.sh BACKUP_FILE=$1 RESTORE_DIR="/restore" if [ -z "$BACKUP_FILE" ]; then echo "Usage: $0 <backup_file>" exit 1 fi # Extract backup mkdir -p $RESTORE_DIR tar -xzf $BACKUP_FILE -C $RESTORE_DIR # Restore configuration docker cp $RESTORE_DIR/config_*.json mcp-wordpress:/app/mcp-wordpress.config.json # Restore cache docker cp $RESTORE_DIR/cache_* mcp-wordpress:/app/cache # Restart container docker restart mcp-wordpress echo "Restore completed from $BACKUP_FILE" ``` ## Security Hardening ### Security-Enhanced Dockerfile ```dockerfile FROM node:20-alpine AS production # Install security updates and tools RUN apk update && apk upgrade && \ apk add --no-cache \ ca-certificates \ dumb-init \ && update-ca-certificates # Create non-root user with minimal permissions RUN addgroup -g 1001 -S nodejs && \ adduser -S nextjs -u 1001 -G nodejs # Set security-focused work directory WORKDIR /app # Copy application with correct ownership COPY --from=builder --chown=nextjs:nodejs /app/dist ./dist COPY --from=builder --chown=nextjs:nodejs /app/node_modules ./node_modules COPY --from=builder --chown=nextjs:nodejs /app/package.json ./ # Create directories with restricted permissions RUN mkdir -p cache logs && \ chown -R nextjs:nodejs cache logs && \ chmod 750 cache logs # Remove unnecessary packages and clean up RUN apk del --purge \ && rm -rf /var/cache/apk/* \ && rm -rf /tmp/* # Set security labels LABEL security.scan="true" \ security.vulnerability-scan="true" USER nextjs # Use dumb-init for proper signal handling ENTRYPOINT ["dumb-init", "--"] CMD ["node", "dist/index.js"] ``` ### Security Policies ```yaml # security-policy.yaml apiVersion: v1 kind: Pod metadata: name: mcp-wordpress-secure spec: securityContext: runAsNonRoot: true runAsUser: 1001 runAsGroup: 1001 fsGroup: 1001 containers: - name: mcp-wordpress image: docdyhr/mcp-wordpress:latest securityContext: allowPrivilegeEscalation: false readOnlyRootFilesystem: true capabilities: drop: - ALL volumeMounts: - name: tmp-volume mountPath: /tmp - name: cache-volume mountPath: /app/cache - name: logs-volume mountPath: /app/logs volumes: - name: tmp-volume emptyDir: {} - name: cache-volume emptyDir: {} - name: logs-volume emptyDir: {} ``` This comprehensive Docker production setup provides scalable, secure, and monitored deployment options for MCP WordPress in production environments.

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/docdyhr/mcp-wordpress'

If you have feedback or need assistance with the MCP directory API, please join our Discord server