From 887e98ca0b24e30da54215393fd18dc02c5e7e74 Mon Sep 17 00:00:00 2001 From: czlonkowski Date: Sun, 8 Jun 2025 08:21:38 +0000 Subject: [PATCH] Add production deployment scripts and quickstart guide MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add deploy-to-vm.sh script for easy VM deployment - Add systemd service file template - Add Nginx configuration with SSL and rate limiting - Add DEPLOYMENT_QUICKSTART.md for n8ndocumentation.aiservices.pl - Update REMOTE_DEPLOYMENT.md to reference quickstart The deployment process is now streamlined: 1. Copy .env.example to .env 2. Configure for production (domain, auth token) 3. Run ./scripts/deploy-to-vm.sh Tested locally with production configuration - all endpoints working correctly with authentication. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- docs/DEPLOYMENT_QUICKSTART.md | 175 ++++++++++++++++++++++++++++++++++ docs/REMOTE_DEPLOYMENT.md | 2 + scripts/deploy-to-vm.sh | 151 +++++++++++++++++++++++++++++ scripts/n8n-docs-mcp.service | 29 ++++++ scripts/nginx-n8n-mcp.conf | 75 +++++++++++++++ 5 files changed, 432 insertions(+) create mode 100644 docs/DEPLOYMENT_QUICKSTART.md create mode 100755 scripts/deploy-to-vm.sh create mode 100644 scripts/n8n-docs-mcp.service create mode 100644 scripts/nginx-n8n-mcp.conf diff --git a/docs/DEPLOYMENT_QUICKSTART.md b/docs/DEPLOYMENT_QUICKSTART.md new file mode 100644 index 0000000..2ff6ce3 --- /dev/null +++ b/docs/DEPLOYMENT_QUICKSTART.md @@ -0,0 +1,175 @@ +# Quick Deployment Guide for n8ndocumentation.aiservices.pl + +This guide walks through deploying the n8n Documentation MCP Server to a VM. + +## Prerequisites + +- Ubuntu 20.04+ VM with root access +- Domain pointing to your VM (e.g., n8ndocumentation.aiservices.pl) +- Node.js 18+ installed on your local machine +- Git installed locally + +## Step 1: Prepare Local Environment + +```bash +# Clone the repository +git clone https://github.com/yourusername/n8n-mcp.git +cd n8n-mcp + +# Install dependencies +npm install + +# Copy and configure environment +cp .env.example .env +``` + +## Step 2: Configure for Production + +Edit `.env` file: + +```bash +# Change these values: +NODE_ENV=production +MCP_DOMAIN=n8ndocumentation.aiservices.pl +MCP_CORS=true + +# Generate and set auth token: +openssl rand -hex 32 +# Copy the output and set: +MCP_AUTH_TOKEN=your-generated-token-here +``` + +## Step 3: Build and Deploy + +```bash +# Build the project +npm run build + +# Run the deployment script +./scripts/deploy-to-vm.sh +``` + +If you don't have SSH key authentication set up, you'll be prompted for the server password. + +## Step 4: Server Setup (First Time Only) + +SSH into your server and run: + +```bash +# Install Node.js 18+ +curl -fsSL https://deb.nodesource.com/setup_18.x | sudo -E bash - +sudo apt install -y nodejs + +# Install PM2 +sudo npm install -g pm2 + +# Install Nginx +sudo apt install -y nginx + +# Copy Nginx configuration +sudo cp /opt/n8n-mcp/scripts/nginx-n8n-mcp.conf /etc/nginx/sites-available/n8n-mcp +sudo ln -s /etc/nginx/sites-available/n8n-mcp /etc/nginx/sites-enabled/ +sudo nginx -t +sudo systemctl reload nginx + +# Get SSL certificate +sudo apt install -y certbot python3-certbot-nginx +sudo certbot --nginx -d n8ndocumentation.aiservices.pl + +# Setup PM2 startup +pm2 startup +# Follow the instructions it provides +``` + +## Step 5: Configure Claude Desktop + +Add to your Claude Desktop configuration: + +```json +{ + "mcpServers": { + "n8n-nodes-remote": { + "command": "npx", + "args": [ + "-y", + "@modelcontextprotocol/client-http", + "https://n8ndocumentation.aiservices.pl/mcp" + ], + "env": { + "MCP_AUTH_TOKEN": "your-auth-token-from-env-file" + } + } + } +} +``` + +## Verify Deployment + +Test the endpoints: + +```bash +# Health check +curl https://n8ndocumentation.aiservices.pl/health + +# Statistics (public) +curl https://n8ndocumentation.aiservices.pl/stats + +# MCP endpoint (requires auth) +curl -X POST https://n8ndocumentation.aiservices.pl/mcp \ + -H "Content-Type: application/json" \ + -H "Authorization: Bearer your-auth-token" \ + -d '{"jsonrpc": "2.0", "method": "tools/list", "id": 1}' +``` + +## Management Commands + +On the server: + +```bash +# View logs +pm2 logs n8n-docs-mcp + +# Restart service +pm2 restart n8n-docs-mcp + +# View status +pm2 status + +# Rebuild database +cd /opt/n8n-mcp +npm run db:rebuild:v2 +pm2 restart n8n-docs-mcp +``` + +## Troubleshooting + +### Service won't start +```bash +# Check logs +pm2 logs n8n-docs-mcp --lines 50 + +# Check if port is in use +sudo lsof -i :3000 +``` + +### SSL issues +```bash +# Renew certificate +sudo certbot renew +``` + +### Database issues +```bash +# Rebuild database +cd /opt/n8n-mcp +rm data/nodes-v2.db +npm run db:rebuild:v2 +``` + +## Security Notes + +1. Keep your `MCP_AUTH_TOKEN` secret +2. Regularly update dependencies: `npm update` +3. Monitor logs for suspicious activity +4. Use fail2ban to prevent brute force attacks +5. Keep your VM updated: `sudo apt update && sudo apt upgrade` \ No newline at end of file diff --git a/docs/REMOTE_DEPLOYMENT.md b/docs/REMOTE_DEPLOYMENT.md index e4e2925..1804c03 100644 --- a/docs/REMOTE_DEPLOYMENT.md +++ b/docs/REMOTE_DEPLOYMENT.md @@ -2,6 +2,8 @@ This guide explains how to deploy the n8n Documentation MCP Server to a remote VM (such as Hetzner) and connect to it from Claude Desktop. +**Quick Start**: For a streamlined deployment to n8ndocumentation.aiservices.pl, see [DEPLOYMENT_QUICKSTART.md](./DEPLOYMENT_QUICKSTART.md). + ## Overview The n8n Documentation MCP Server can be deployed as a remote HTTP service, allowing Claude Desktop to access n8n node documentation over the internet. This is useful for: diff --git a/scripts/deploy-to-vm.sh b/scripts/deploy-to-vm.sh new file mode 100755 index 0000000..d5b3fef --- /dev/null +++ b/scripts/deploy-to-vm.sh @@ -0,0 +1,151 @@ +#!/bin/bash + +# Deployment script for n8n Documentation MCP Server +# Target: n8ndocumentation.aiservices.pl + +set -e + +echo "🚀 n8n Documentation MCP Server - VM Deployment" +echo "==============================================" + +# Configuration +SERVER_USER=${SERVER_USER:-root} +SERVER_HOST=${SERVER_HOST:-n8ndocumentation.aiservices.pl} +APP_DIR="/opt/n8n-mcp" +SERVICE_NAME="n8n-docs-mcp" + +# Colors +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +RED='\033[0;31m' +NC='\033[0m' # No Color + +# Check if .env exists +if [ ! -f .env ]; then + echo -e "${RED}❌ .env file not found. Please create it from .env.example${NC}" + exit 1 +fi + +# Check required environment variables +source .env +if [ "$MCP_DOMAIN" != "n8ndocumentation.aiservices.pl" ]; then + echo -e "${YELLOW}⚠️ Warning: MCP_DOMAIN is not set to n8ndocumentation.aiservices.pl${NC}" + read -p "Continue anyway? (y/N) " -n 1 -r + echo + if [[ ! $REPLY =~ ^[Yy]$ ]]; then + exit 1 + fi +fi + +if [ -z "$MCP_AUTH_TOKEN" ] || [ "$MCP_AUTH_TOKEN" == "your-secure-auth-token-here" ]; then + echo -e "${RED}❌ MCP_AUTH_TOKEN not set or using default value${NC}" + echo "Generate a secure token with: openssl rand -hex 32" + exit 1 +fi + +echo -e "${GREEN}✅ Configuration validated${NC}" + +# Build the project locally +echo -e "\n${YELLOW}Building project...${NC}" +npm run build + +# Create deployment package +echo -e "\n${YELLOW}Creating deployment package...${NC}" +rm -rf deploy-package +mkdir -p deploy-package + +# Copy necessary files +cp -r dist deploy-package/ +cp -r data deploy-package/ +cp package*.json deploy-package/ +cp .env deploy-package/ +cp ecosystem.config.js deploy-package/ 2>/dev/null || true + +# Create tarball +tar -czf deploy-package.tar.gz deploy-package + +echo -e "${GREEN}✅ Deployment package created${NC}" + +# Upload to server +echo -e "\n${YELLOW}Uploading to server...${NC}" +scp deploy-package.tar.gz $SERVER_USER@$SERVER_HOST:/tmp/ + +# Deploy on server +echo -e "\n${YELLOW}Deploying on server...${NC}" +ssh $SERVER_USER@$SERVER_HOST << 'ENDSSH' +set -e + +# Create app directory +mkdir -p /opt/n8n-mcp +cd /opt/n8n-mcp + +# Stop existing service if running +pm2 stop n8n-docs-mcp 2>/dev/null || true + +# Extract deployment package +tar -xzf /tmp/deploy-package.tar.gz --strip-components=1 +rm /tmp/deploy-package.tar.gz + +# Install production dependencies +npm ci --only=production + +# Create PM2 ecosystem file if not exists +if [ ! -f ecosystem.config.js ]; then + cat > ecosystem.config.js << 'EOF' +module.exports = { + apps: [{ + name: 'n8n-docs-mcp', + script: './dist/index-http.js', + instances: 1, + autorestart: true, + watch: false, + max_memory_restart: '1G', + env: { + NODE_ENV: 'production' + }, + error_file: './logs/error.log', + out_file: './logs/out.log', + log_file: './logs/combined.log', + time: true + }] +}; +EOF +fi + +# Create logs directory +mkdir -p logs + +# Start with PM2 +pm2 start ecosystem.config.js +pm2 save + +echo "✅ Deployment complete!" +echo "" +echo "Service status:" +pm2 status n8n-docs-mcp +ENDSSH + +# Clean up local files +rm -rf deploy-package deploy-package.tar.gz + +echo -e "\n${GREEN}🎉 Deployment successful!${NC}" +echo -e "\nServer endpoints:" +echo -e " Health: https://$SERVER_HOST/health" +echo -e " Stats: https://$SERVER_HOST/stats" +echo -e " MCP: https://$SERVER_HOST/mcp" +echo -e "\nClaude Desktop configuration:" +echo -e " { + \"mcpServers\": { + \"n8n-nodes-remote\": { + \"command\": \"npx\", + \"args\": [ + \"-y\", + \"@modelcontextprotocol/client-http\", + \"https://$SERVER_HOST/mcp\" + ], + \"env\": { + \"MCP_AUTH_TOKEN\": \"$MCP_AUTH_TOKEN\" + } + } + } + }" \ No newline at end of file diff --git a/scripts/n8n-docs-mcp.service b/scripts/n8n-docs-mcp.service new file mode 100644 index 0000000..986a1fb --- /dev/null +++ b/scripts/n8n-docs-mcp.service @@ -0,0 +1,29 @@ +[Unit] +Description=n8n Documentation MCP Server +After=network.target + +[Service] +Type=simple +User=nodejs +WorkingDirectory=/opt/n8n-mcp +ExecStart=/usr/bin/node /opt/n8n-mcp/dist/index-http.js +Restart=always +RestartSec=10 + +# Environment +Environment="NODE_ENV=production" +EnvironmentFile=/opt/n8n-mcp/.env + +# Security +NoNewPrivileges=true +PrivateTmp=true +ProtectSystem=strict +ProtectHome=true +ReadWritePaths=/opt/n8n-mcp/data /opt/n8n-mcp/logs /opt/n8n-mcp/temp + +# Logging +StandardOutput=append:/opt/n8n-mcp/logs/service.log +StandardError=append:/opt/n8n-mcp/logs/service-error.log + +[Install] +WantedBy=multi-user.target \ No newline at end of file diff --git a/scripts/nginx-n8n-mcp.conf b/scripts/nginx-n8n-mcp.conf new file mode 100644 index 0000000..31fd976 --- /dev/null +++ b/scripts/nginx-n8n-mcp.conf @@ -0,0 +1,75 @@ +server { + listen 80; + server_name n8ndocumentation.aiservices.pl; + + # Redirect HTTP to HTTPS + location / { + return 301 https://$server_name$request_uri; + } +} + +server { + listen 443 ssl http2; + server_name n8ndocumentation.aiservices.pl; + + # SSL configuration (managed by Certbot) + ssl_certificate /etc/letsencrypt/live/n8ndocumentation.aiservices.pl/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/n8ndocumentation.aiservices.pl/privkey.pem; + + # SSL security settings + ssl_protocols TLSv1.2 TLSv1.3; + ssl_ciphers HIGH:!aNULL:!MD5; + ssl_prefer_server_ciphers on; + + # Security headers + add_header X-Content-Type-Options nosniff; + add_header X-Frame-Options DENY; + add_header X-XSS-Protection "1; mode=block"; + add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; + + # Logging + access_log /var/log/nginx/n8n-mcp-access.log; + error_log /var/log/nginx/n8n-mcp-error.log; + + # Proxy settings + location / { + proxy_pass http://localhost:3000; + 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_cache_bypass $http_upgrade; + + # Timeouts for MCP operations + proxy_connect_timeout 60s; + proxy_send_timeout 60s; + proxy_read_timeout 60s; + + # Increase buffer sizes for large responses + proxy_buffer_size 16k; + proxy_buffers 8 16k; + proxy_busy_buffers_size 32k; + } + + # Rate limiting for API endpoints + location /mcp { + limit_req zone=mcp_limit burst=10 nodelay; + proxy_pass http://localhost:3000; + proxy_http_version 1.1; + 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; + + # Larger timeouts for MCP + proxy_connect_timeout 120s; + proxy_send_timeout 120s; + proxy_read_timeout 120s; + } +} + +# Rate limiting zone +limit_req_zone $binary_remote_addr zone=mcp_limit:10m rate=10r/s; \ No newline at end of file