Baseworks n8n CrewAI Deployment Guide
ARCHIVED — 2026-03-02 CrewAI has been decommissioned. Intelligence tasks now run through Claude Code on the repurposed OpenClaw VPS, using Patrick’s Claude Max account and Asia’s Claude Pro account. No OpenRouter or API keys in use. n8n remains active in a reduced role: Slack routing, git sync, scheduled triggers — no AI calls. See: Claude-Code-VPS-Setup
Deployment Guide — Baseworks Agent System
Section titled “Deployment Guide — Baseworks Agent System”Step-by-step guide to deploy the n8n + CrewAI agent system on Hetzner via xCloud.
Estimated total time: 2-3 hours for Phases 1-5, plus Phase 6 (Remote MCP for mobile) as a follow-up
Phase 1: VPS & n8n Setup — COMPLETED 2026-02-19
Section titled “Phase 1: VPS & n8n Setup — COMPLETED 2026-02-19”1.1 Provision Hetzner Server via xCloud — DONE
Section titled “1.1 Provision Hetzner Server via xCloud — DONE”- Log in to xCloud dashboard
- Add Server → Hetzner → Select CX33 (4 vCPU, 8GB RAM, 80GB SSD — €4.99/mo)
- Server type: Docker+NGINX (not LEMP — we need Docker for the full stack)
- App Type: None (leave blank — we deploy n8n ourselves via Docker)
- Database: MySQL (default — irrelevant, n8n uses PostgreSQL in Docker)
- Region: Falkenstein, DE (Central) (close to existing Baseworks sites in Germany)
- Ubuntu: 24.04 LTS
- Plan: Lifetime (Seven Server LTD)
- Hetzner Auto Backups: Enabled (+€1/mo)
- Server name: baseworks-agents
- Tags: agents, n8n, docker
Actual server details:
- IP:
167.235.236.99 - SSH:
ssh patrick@167.235.236.99(passwordless sudo configured) - Docker: 29.2.1 + Compose v5.0.2
- NGINX: 1.28.1
- Git: 2.43.0
- Ubuntu: 24.04 LTS (kernel 6.8.0-90-generic)
1.2 Deploy n8n via Docker Compose — DONE
Section titled “1.2 Deploy n8n via Docker Compose — DONE”We did NOT use xCloud’s one-click n8n app. Instead, n8n runs in Docker alongside PostgreSQL and CrewAI, managed by a single docker-compose.yml.
Docker Compose file: 03-resources/agent-system/docker/docker-compose.yml
Environment file: /opt/baseworks-vault/03-resources/agent-system/docker/.env (on VPS, not in git)
Services running:
baseworks-postgres— PostgreSQL 16 (Alpine) on port 5432baseworks-n8n— n8n (latest) on 127.0.0.1:5678
# Start/restart the stackssh patrick@167.235.236.99cd /opt/baseworks-vault/03-resources/agent-system/dockersudo docker compose up -d
# Check statussudo docker ps1.3 Configure SSH Access — DONE
Section titled “1.3 Configure SSH Access — DONE”SSH user patrick created via xCloud Sudo Users panel with “Patricks Desktop Mac” SSH key.
Passwordless sudo configured via xCloud Commands: echo "patrick ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers.d/patrick
# Connect from Patrick's Macssh patrick@167.235.236.99Note: Ksenia’s SSH key should be added via xCloud → Sudo Users when she needs access.
1.4 Clone Vault to VPS — DONE
Section titled “1.4 Clone Vault to VPS — DONE”Vault cloned to /opt/baseworks-vault using GitHub PAT named “Baseworks-agents-VPS”.
# Vault location on VPS/opt/baseworks-vault
# Git configuser.name: "Baseworks Agent"user.email: "agent@baseworks.com"GitHub PAT rotation reminder: Token was created 2026-02-19 with 90-day expiry. Rotate by ~2026-05-19.
1.5 Set Up Git Sync — DONE
Section titled “1.5 Set Up Git Sync — DONE”Originally a root cron job pulled every 5 minutes. The cron job was removed on 2026-02-20 because it created root-owned files in .git/ that broke n8n container access (n8n runs as uid 1000).
The n8n “Vault Git Sync” workflow (ID: Oh75ZJIJiIZreS06) is now the sole sync mechanism, pulling every 5 minutes. The .git directory ownership was fixed: chown -R 1000:1000 /opt/baseworks-vault/.git and a persistent gitconfig was added via GIT_CONFIG_GLOBAL=/home/node/.n8n/.gitconfig.
1.6 Configure NGINX + SSL — DONE
Section titled “1.6 Configure NGINX + SSL — DONE”Domain: n8n.baseworks.com
DNS: Cloudflare A record → 167.235.236.99 (proxy ON, orange cloud)
SSL: Cloudflare Origin Certificate (wildcard *.baseworks.com, expires 2041-02-15)
Certificate files on VPS:
/etc/ssl/cloudflare/baseworks.com.pem/etc/ssl/cloudflare/baseworks.com.key
NGINX config: /etc/nginx/sites-available/n8n (port 80 redirects to 443, proxies to 127.0.0.1:5678)
Access n8n at: https://n8n.baseworks.com
1.7 n8n Account Setup — DONE
Section titled “1.7 n8n Account Setup — DONE”- Owner account: Baseworks Team (
agents@baseworks.com) - Free license key activated (advanced debugging, execution search, folders)
- Individual user accounts for Patrick and Ksenia to be added
1.8 Additional Directories Created — DONE
Section titled “1.8 Additional Directories Created — DONE”/opt/baseworks-crewai — CrewAI deployment directory/var/log/baseworks — Application logsPhase 2: CrewAI Setup — COMPLETED 2026-02-19
Section titled “Phase 2: CrewAI Setup — COMPLETED 2026-02-19”2.1 Add OpenRouter API Key — DONE
Section titled “2.1 Add OpenRouter API Key — DONE”OpenRouter API key added to .env on VPS.
2.2 Build and Start CrewAI — DONE
Section titled “2.2 Build and Start CrewAI — DONE”Fixed FileReadTool import (moved from crewai.tools to crewai_tools).
Added crewai-tools>=0.14.0 to requirements.txt.
All three containers running and healthy:
baseworks-crewai healthy 127.0.0.1:8000baseworks-n8n healthy 127.0.0.1:5678 → https://n8n.baseworks.combaseworks-postgres healthy 54322.3 Verify CrewAI Endpoints — DONE
Section titled “2.3 Verify CrewAI Endpoints — DONE”curl http://127.0.0.1:8000/health# {"status":"healthy","running_tasks":0}Phase 2.5: Operations Dashboard — NOT STARTED
Section titled “Phase 2.5: Operations Dashboard — NOT STARTED”A custom web dashboard at crews.baseworks.com providing a single pane of glass for the entire agent system. Built directly into the existing CrewAI FastAPI app — no external tools.
What the dashboard shows
Section titled “What the dashboard shows”| Section | What it shows |
|---|---|
| Agent Roster | All agents, roles, goals, tools (read from YAML configs) |
| Crew Map | Visual flow of which agents work together in each crew |
| Execution History | Every crew run — input, output, duration, token cost |
| Live Status | Currently running crews, queue depth |
| Server Health | CPU, RAM, disk usage, container status |
| Vault Sync | Last pull time, sync status, recent file changes |
| OpenRouter Spend | Token usage, cost per crew, daily/weekly totals |
| Workflow Status | Which n8n workflows are active, recent failures |
| Backup Status | Last Hetzner snapshot, Backblaze backup status |
| Secret Rotation | GitHub PAT expiry date, API key ages, rotation reminders |
| System Log | Unified timeline of events across all services |
Technical approach
Section titled “Technical approach”- Lightweight HTML templates served by FastAPI (no heavy frontend framework)
- Reads agent/task configs from YAML files in the vault
- Queries Docker API for container health and resource usage
- Queries n8n API for workflow status
- Tracks execution history in a local SQLite database
- Basic auth or same credentials as n8n
Setup steps
Section titled “Setup steps”- Add dashboard routes to CrewAI FastAPI app
- Create HTML templates for each dashboard section
- Add Cloudflare DNS:
crews.baseworks.com→167.235.236.99 - Add NGINX config (same pattern as n8n, uses existing wildcard cert)
- Expose port 8000 via NGINX for the dashboard (CrewAI API + dashboard on same port)
Phase 3: Slack Setup — COMPLETED 2026-02-19
Section titled “Phase 3: Slack Setup — COMPLETED 2026-02-19”3.1 Slack Workspace — DONE
Section titled “3.1 Slack Workspace — DONE”Using existing baseworks.slack.com workspace.
3.2 Slack Channels — DONE
Section titled “3.2 Slack Channels — DONE”5 private channels created:
| Channel | ID | Purpose |
|---|---|---|
#wordpress-updates | C0AFWBZDDR9 | Site monitoring alerts & actions |
#forum-responses | C0AG6BZEA2Y | Draft responses for approval |
#content-strategy | C0AG0MUFE1L | Content ideas & drafts |
#agent-alerts | C0AGFM6AZ09 | System status, errors, kill switch |
#vault-inbox | C0AG0MWBP5L | Mobile vault editor (Slack → Obsidian) |
3.3 Slack Bot — DONE
Section titled “3.3 Slack Bot — DONE”- App name: “Baseworks Agent”
- App ID: A0AG6CC8CG4
- Bot invited to all 5 private channels
- Scopes:
chat:write,chat:write.public,channels:history,channels:read,channels:join,groups:history,groups:read,reactions:write,users:read
3.4 n8n Slack Credential — DONE
Section titled “3.4 n8n Slack Credential — DONE”Slack API credential (“Slack account”) created and tested in n8n.
Phase 4: Import n8n Workflows — COMPLETED 2026-02-19
Section titled “Phase 4: Import n8n Workflows — COMPLETED 2026-02-19”4.1 Import Workflow Files — DONE
Section titled “4.1 Import Workflow Files — DONE”Important lesson: n8n’s UI “Import from File” rejects hand-crafted JSON with a “could not find property option” error. The CLI import (n8n import:workflow) accepts it but the UI can’t render the nodes. The only reliable method is the n8n Public API (POST /api/v1/workflows).
Correct Slack node format (discovered through testing):
{ "select": "channel", "channelId": {"__rl": true, "value": "CHANNEL_ID", "mode": "list", "cachedResultName": "channel-name"}, "text": "message text", "otherOptions": {}}All 7 workflows created via the API and rendering correctly:
| Workflow | n8n ID | Status |
|---|---|---|
| Vault Git Sync | Oh75ZJIJiIZreS06 | Imported, inactive |
| Kill Switch — Emergency Stop | v4T9Xu39sxR5CJnB | Imported, inactive |
| Daily Vault Summary | 3QEX4wna4XMr348K | Imported, inactive |
| Vault Capture via Slack | A0hTmPJN38HRe3Ch | Imported, inactive |
| WordPress Monitoring & Updates | 1uUisQfjZ0TUqiM4 | Imported, inactive |
| Forum Response Pipeline | shLtsDHV6zIqySZ0 | Imported, inactive |
| Content Creation Pipeline | q1eV3z1aQs9VWh67 | Imported, inactive |
4.2 Configure Each Workflow — PARTIALLY DONE
Section titled “4.2 Configure Each Workflow — PARTIALLY DONE”Slack credential: Auto-connected to all 14 Slack nodes (only one credential exists). Channel IDs: All Slack nodes configured with correct channel IDs via API script.
Still needed:
- WordPress Monitoring: HTTP Basic Auth credential (WP username + application password) +
WP_URLenv var - Forum Response:
FORUM_API_URLenvironment variable - Slack Event Subscriptions: Need to configure in Slack app settings to forward messages to webhook URLs
4.3 Activate Workflows — PARTIALLY COMPLETE (2026-02-20)
Section titled “4.3 Activate Workflows — PARTIALLY COMPLETE (2026-02-20)”6 of 8 workflows are active. Activation order used:
- ✅ Vault Git Sync — ACTIVE
- ✅ Kill Switch — ACTIVE (tested end-to-end)
- ✅ Daily Vault Summary — ACTIVE
- ❌ WordPress Monitoring — INACTIVE (needs WP_URL + HTTP Basic Auth)
- ✅ Vault Capture via Slack — ACTIVE
- ❌ Forum Response Pipeline — INACTIVE (needs FORUM_API_URL)
- ✅ Content Creation Pipeline — ACTIVE
- ✅ Slack Event Router — ACTIVE (new workflow, see Phase 4.6)
Still needed to activate remaining workflows:
- WordPress Monitoring: HTTP Basic Auth credential (WP username + application password),
WP_URLenv var, clonep-oancia/baseworks-changelogrepo to VPS - Forum Response:
FORUM_API_URLenvironment variable
4.4 n8n API Key — CREATED
Section titled “4.4 n8n API Key — CREATED”- Label: “Baseworks Deploy”
- Expires: 2026-03-22 (30 days)
- All scopes enabled
- Used for workflow creation/management via API
4.5 Configure n8n Environment Variables — NOT STARTED
Section titled “4.5 Configure n8n Environment Variables — NOT STARTED”In n8n → Settings → Environment Variables:
WP_URL=https://baseworks.comFORUM_API_URL=https://your-forum-api.comPhase 4.6: Slack Event Subscriptions — COMPLETED 2026-02-20
Section titled “Phase 4.6: Slack Event Subscriptions — COMPLETED 2026-02-20”Slack Event Subscriptions configured to forward channel messages to n8n.
Solution: Slack Event Router
Section titled “Solution: Slack Event Router”Since Slack only allows one Request URL per app, we created a dedicated “Slack Event Router” workflow (ID: fcsJFL21APR2uyV9) that:
- Receives all Slack events at a single URL
- Handles Slack’s URL verification challenge
- Routes events to the correct workflow based on channel ID
Slack App Settings (https://api.slack.com/apps/A0AG6CC8CG4):
- Event Subscriptions: Enabled
- Request URL:
https://n8n.baseworks.com/webhook/slack-events - Subscribed bot event:
message.groups(private channels)
Routing Table:
| Source Channel | Channel ID | Routes To |
|---|---|---|
#agent-alerts | C0AGFM6AZ09 | Kill Switch (/webhook/kill-switch) |
#vault-inbox | C0AG0MWBP5L | Vault Capture (/webhook/vault-capture) |
Architecture: Event Router → IF node per channel → HTTP Request to internal webhook → target workflow handles the event. Both Kill Switch and Vault Capture workflows also handle the URL verification challenge independently (belt and suspenders).
Phase 5: Testing — PARTIALLY COMPLETE (2026-02-20)
Section titled “Phase 5: Testing — PARTIALLY COMPLETE (2026-02-20)”5.1 Test Kill Switch First — DONE ✅
Section titled “5.1 Test Kill Switch First — DONE ✅”Tested end-to-end on 2026-02-20:
- Typed
STOPin#agent-alerts→ Received “EMERGENCY STOP EXECUTED” confirmation - Typed
RESUMEin#agent-alerts→ Received “RESUMED” confirmation - Full event flow verified: Slack → Event Router → Kill Switch → Slack response
5.2 Test Vault Sync
Section titled “5.2 Test Vault Sync”- Add a test file to vault on your Mac
- Commit and push
- Wait 5 minutes
- SSH to VPS:
ls /opt/baseworks-vault/00-inbox/ - Your file should be there
5.3 Test Daily Summary
Section titled “5.3 Test Daily Summary”- Manually execute the “Daily Vault Summary” workflow in n8n
- Check
#agent-alertsfor the summary message
5.4 Test Vault Capture
Section titled “5.4 Test Vault Capture”- In Slack
#vault-inbox, type: “Test note — this is a capture test” - Should get a filing suggestion with Confirm/Cancel buttons
- Confirm and check vault
5.5 Test Forum Response
Section titled “5.5 Test Forum Response”- Manually trigger with a test post in n8n (or via webhook)
- Check
#forum-responsesfor the draft - Test Approve/Edit/Reject buttons
5.6 Test Content Pipeline
Section titled “5.6 Test Content Pipeline”- Manually execute the “Content Creation Pipeline” in n8n
- Check
#content-strategyfor proposals - Test approval buttons
5.7 Test WordPress Monitoring
Section titled “5.7 Test WordPress Monitoring”- Manually execute the “WordPress Monitoring” workflow
- Check
#wordpress-updatesfor status
Phase 6: Remote MCP Server (Mobile Access) — NOT STARTED
Section titled “Phase 6: Remote MCP Server (Mobile Access) — NOT STARTED”Enables Claude on iOS/Android to talk directly to the agent infrastructure — no Slack middleman needed for vault capture and crew execution from phone conversations.
6.1 Deploy Remote MCP Server on VPS
Section titled “6.1 Deploy Remote MCP Server on VPS”The remote MCP server is a lightweight authenticated API that wraps the same endpoints n8n already calls.
ssh patrick@167.235.236.99cd /opt/baseworks-mcp-remotesudo docker compose up -d --build
# Verifycurl http://127.0.0.1:8001/health6.2 Configure NGINX Proxy for MCP Server
Section titled “6.2 Configure NGINX Proxy for MCP Server”Add Cloudflare DNS A record: mcp.baseworks.com → 167.235.236.99 (proxy ON)
NGINX config same pattern as n8n — uses the existing wildcard origin cert.
6.3 MCP Server Capabilities (Tools)
Section titled “6.3 MCP Server Capabilities (Tools)”The remote MCP server exposes these tools to Claude:
| Tool | Description |
|---|---|
vault-capture | Save a note/insight to the vault with auto-filing |
vault-search | Search the vault for existing knowledge |
trigger-crew | Trigger a CrewAI crew (forum-response, content-strategy, research) |
crew-status | Check running crew tasks |
kill-switch | Emergency stop all crews |
6.4 Register on claude.ai
Section titled “6.4 Register on claude.ai”- Go to https://claude.ai → Settings → Integrations (or MCP Servers)
- Add Remote MCP Server
- URL:
https://mcp.baseworks.com - Authenticate with API key (generated during deploy)
- Do this for both Patrick’s and Ksenia’s Anthropic accounts
6.5 Verify on Mobile
Section titled “6.5 Verify on Mobile”- Open Claude iOS app on your phone
- Start a new conversation
- The MCP tools should be available (vault-capture, trigger-crew, etc.)
- Test: Ask Claude to save a note — confirm it appears in the vault
6.6 Interim Workflow (Before Phase 6 is Complete)
Section titled “6.6 Interim Workflow (Before Phase 6 is Complete)”Until the remote MCP server is deployed, use this workflow from mobile:
- Have your conversation with Claude on your phone
- Copy key insights → paste into Slack
#vault-inbox - n8n + CrewAI auto-files to vault
- For deeper follow-up, continue the conversation on Claude Desktop (conversations sync across devices)
Maintenance
Section titled “Maintenance”Updating Agent Behavior
Section titled “Updating Agent Behavior”Edit vault files locally, git push. The VPS pulls automatically. Agent behavior updates on next execution.
Key files that affect agent behavior:
03-resources/agent-system/crewai/config/agents.yaml— Agent personalities03-resources/agent-system/crewai/config/tasks.yaml— Task instructions02-areas/communications/communications-guide.md— Response policies02-areas/community-forums-groups/index.md— Classification rules
Updating CrewAI Code
Section titled “Updating CrewAI Code”If you change Python code (not just YAML/knowledge):
ssh patrick@167.235.236.99cd /opt/baseworks-vault/03-resources/agent-system/dockersudo docker compose up -d --build crewaiMonitoring
Section titled “Monitoring”- n8n execution history: https://n8n.baseworks.com → Executions
- CrewAI health:
curl http://127.0.0.1:8000/health - CrewAI running tasks:
curl http://127.0.0.1:8000/status - Docker logs:
sudo docker compose logs crewai -f - OpenRouter spend: https://openrouter.ai/usage
Rotating Secrets
Section titled “Rotating Secrets”- GitHub PAT (expires ~2026-05-19): Re-create at github.com/settings/tokens, update git remote URL on VPS
- OpenRouter key: Update
.env→sudo docker compose restart crewai - Slack bot token: Update in n8n Credentials
- n8n encryption key: In
.env— do NOT change after initial setup (breaks encrypted credentials)
Backup Strategy
Section titled “Backup Strategy”| Layer | What | When | Covers |
|---|---|---|---|
| Hetzner snapshots | Full server image | Automated daily (+€1/mo) | Catastrophic failure, OS corruption |
| Backblaze B2 | App data (DB dumps, configs) | Daily + on-demand via n8n (to be configured) | Accidental deletion, rollback |
| GitHub | Vault + code | Every commit | Knowledge base, deployment scripts |
Troubleshooting
Section titled “Troubleshooting”| Issue | Check |
|---|---|
| n8n not accessible | sudo docker ps, NGINX config, Cloudflare DNS |
| CrewAI not responding | sudo docker compose logs crewai, check .env |
| Vault not syncing | Check n8n Git Sync workflow executions, git remote URL, PAT validity |
| Slack not receiving | Bot token scopes, channel IDs in workflows, Event Subscriptions config |
| High LLM costs | OpenRouter usage page, MAX_TOKENS_PER_EXECUTION |
| Crew execution timeout | Increase timeout in FastAPI (default 300s) |
| SSL/521 errors | Check NGINX SSL cert paths, Cloudflare SSL mode (must be Full) |
| “Unrecognized node type: executeCommand” | n8n v2 blocks this node by default. Set NODES_EXCLUDE=[n8n-nodes-base.localFileTrigger] in docker-compose (keeps localFileTrigger blocked, re-enables executeCommand) |
| CrewAI “connection refused” from n8n | Use http://crewai:8000 (Docker service name), NOT http://127.0.0.1:8000. Localhost inside a container refers to that container only |
| Switch node routes everything to output 0 | Known bug in n8n 2.8.3 Switch node v3. Use IF nodes instead |
| Git “dubious ownership” in n8n container | Run chown -R 1000:1000 /opt/baseworks-vault/.git and ensure GIT_CONFIG_GLOBAL=/home/node/.n8n/.gitconfig is set in docker-compose |
| X-Forwarded-For trust proxy warning | Set N8N_PROXY_HOPS=1 in docker-compose environment |
n8n v2 Compatibility Notes (discovered 2026-02-20)
Section titled “n8n v2 Compatibility Notes (discovered 2026-02-20)”These issues were found running n8n 2.8.3 and may apply to other v2 releases:
-
executeCommandnode blocked by default — n8n v2 blocksexecuteCommandandlocalFileTriggerfor security. To re-enableexecuteCommand, setNODES_EXCLUDE=[n8n-nodes-base.localFileTrigger](this keeps the file trigger blocked but allows command execution). -
Switch node v3 broken — Always routes items to output index 0 regardless of which condition matches. Workaround: use sequential IF nodes (
n8n-nodes-base.iftypeVersion 2) instead. -
Code node multi-output not supported —
runOnceForAllItemsmode doesn’t support returning[[items], [items]]for multi-output routing. Return single-output items and use IF/Switch nodes for routing instead. -
Docker inter-container networking — Containers access each other via Docker Compose service names (e.g.,
crewai:8000), never127.0.0.1.