Zapier and Make (formerly Integromatic) charge per-task fees that scale quickly, and they require sending all your data through their cloud infrastructure. Self-hosted automation platforms give you unlimited workflow executions, complete data privacy, and the ability to integrate with internal services that cloud automation tools cannot reach. Three open-source platforms dominate this space: n8n (visual workflow builder, closest to Zapier), Node-RED (flow-based programming, IoT focused), and Huginn (agent-based system, web scraping and monitoring).

Platform Comparison

Feature n8n Node-RED Huginn
Language TypeScript Node.js Ruby
Interface Visual workflow builder Flow editor (drag-and-drop) Agent configuration forms
Best for Business automation, API integration IoT, hardware, data pipelines Web scraping, IFTTT-style agents
Built-in integrations 400+ nodes 3000+ community nodes 50+ agent types
Webhook support Yes (built-in) Yes (http-in node) Yes (webhook agent)
Scheduling Cron + interval triggers Inject node (cron, interval) Per-agent schedules
Error handling Per-node error workflows Catch nodes, status nodes Basic (logs)
Execution history Yes (detailed logs per execution) Limited (debug sidebar) Yes (event logs)
Credentials management Encrypted credential store Node properties (in flow) Per-agent credentials
RAM usage ~200-400 MB ~100-200 MB ~300-500 MB
License Sustainable Use License (source available) Apache-2.0 MIT

Docker Deployment: n8n

# docker-compose.yml for n8n
version: "3.8"
services:
  n8n:
    image: n8nio/n8n:latest
    container_name: n8n
    restart: unless-stopped
    environment:
      - N8N_HOST=automation.example.com
      - N8N_PORT=5678
      - N8N_PROTOCOL=https
      - WEBHOOK_URL=https://automation.example.com/
      - N8N_ENCRYPTION_KEY=${ENCRYPTION_KEY}
      - DB_TYPE=postgresdb
      - DB_POSTGRESDB_HOST=n8n-db
      - DB_POSTGRESDB_PORT=5432
      - DB_POSTGRESDB_DATABASE=n8n
      - DB_POSTGRESDB_USER=n8n
      - DB_POSTGRESDB_PASSWORD=${DB_PASSWORD}
      - EXECUTIONS_DATA_PRUNE=true
      - EXECUTIONS_DATA_MAX_AGE=168  # Hours (7 days)
      - N8N_METRICS=true
      # SMTP for error notifications
      - N8N_EMAIL_MODE=smtp
      - N8N_SMTP_HOST=smtp.example.com
      - N8N_SMTP_PORT=587
      - [email protected]
      - N8N_SMTP_PASS=${SMTP_PASSWORD}
      - [email protected]
    volumes:
      - n8n_data:/home/node/.n8n
    ports:
      - "5678:5678"
    depends_on:
      - n8n-db

  n8n-db:
    image: postgres:16-alpine
    container_name: n8n-db
    restart: unless-stopped
    environment:
      - POSTGRES_DB=n8n
      - POSTGRES_USER=n8n
      - POSTGRES_PASSWORD=${DB_PASSWORD}
    volumes:
      - n8n_db:/var/lib/postgresql/data

volumes:
  n8n_data:
  n8n_db:

Docker Deployment: Node-RED

# docker-compose.yml for Node-RED
version: "3.8"
services:
  node-red:
    image: nodered/node-red:latest
    container_name: node-red
    restart: unless-stopped
    environment:
      - TZ=America/New_York
      - NODE_RED_CREDENTIAL_SECRET=${CREDENTIAL_SECRET}
    volumes:
      - node_red_data:/data
    ports:
      - "1880:1880"
    # For hardware access (GPIO, USB, serial)
    # privileged: true
    # devices:
    #   - /dev/ttyUSB0:/dev/ttyUSB0

volumes:
  node_red_data:

Securing Node-RED

// settings.js - authentication configuration
// Generate password hash: node-red admin hash-pw
module.exports = {
    adminAuth: {
        type: "credentials",
        users: [{
            username: "admin",
            password: "$2b$08$HASHED_PASSWORD_HERE",
            permissions: "*"
        }]
    },
    // HTTPS configuration
    https: {
        key: require("fs").readFileSync('/data/certs/privkey.pem'),
        cert: require("fs").readFileSync('/data/certs/fullchain.pem')
    },
    // Disable admin UI in production (API-only mode)
    // httpAdminRoot: false,
    credentialSecret: process.env.CREDENTIAL_SECRET
}

Docker Deployment: Huginn

# docker-compose.yml for Huginn
version: "3.8"
services:
  huginn:
    image: ghcr.io/huginn/huginn:latest
    container_name: huginn
    restart: unless-stopped
    environment:
      - DOMAIN=huginn.example.com
      - PORT=3000
      - DATABASE_ADAPTER=postgresql
      - DATABASE_HOST=huginn-db
      - DATABASE_NAME=huginn
      - DATABASE_USERNAME=huginn
      - DATABASE_PASSWORD=${DB_PASSWORD}
      - HUGINN_SEED_USERNAME=admin
      - HUGINN_SEED_PASSWORD=${ADMIN_PASSWORD}
      - SMTP_DOMAIN=example.com
      - SMTP_SERVER=smtp.example.com
      - SMTP_PORT=587
      - [email protected]
      - SMTP_PASSWORD=${SMTP_PASSWORD}
      - [email protected]
    volumes:
      - huginn_data:/app/data
    ports:
      - "3000:3000"
    depends_on:
      - huginn-db

  huginn-db:
    image: postgres:16-alpine
    container_name: huginn-db
    restart: unless-stopped
    environment:
      - POSTGRES_DB=huginn
      - POSTGRES_USER=huginn
      - POSTGRES_PASSWORD=${DB_PASSWORD}
    volumes:
      - huginn_db:/var/lib/postgresql/data

volumes:
  huginn_data:
  huginn_db:

Practical Workflow Examples

n8n: GitHub Issue to Slack Notification

// n8n workflow JSON (importable)
{
  "nodes": [
    {
      "name": "GitHub Trigger",
      "type": "n8n-nodes-base.githubTrigger",
      "parameters": {
        "owner": "my-org",
        "repository": "my-repo",
        "events": ["issues"]
      }
    },
    {
      "name": "Filter New Issues",
      "type": "n8n-nodes-base.if",
      "parameters": {
        "conditions": {
          "string": [{
            "value1": "={{ $json.action }}",
            "operation": "equals",
            "value2": "opened"
          }]
        }
      }
    },
    {
      "name": "Slack Notification",
      "type": "n8n-nodes-base.slack",
      "parameters": {
        "channel": "#dev-alerts",
        "text": "New issue: {{ $json.issue.title }}\n{{ $json.issue.html_url }}"
      }
    }
  ]
}

Node-RED: Temperature Monitoring Flow

// Node-RED flow JSON (importable)
[
  {
    "id": "mqtt-in",
    "type": "mqtt in",
    "topic": "sensors/temperature",
    "broker": "mqtt-broker-config"
  },
  {
    "id": "parse-json",
    "type": "json",
    "wires": [["threshold-check"]]
  },
  {
    "id": "threshold-check",
    "type": "switch",
    "property": "payload.temperature",
    "rules": [
      {"t": "gt", "v": "30", "vt": "num"}
    ],
    "wires": [["send-alert"]]
  },
  {
    "id": "send-alert",
    "type": "e-mail",
    "to": "[email protected]",
    "subject": "Temperature Alert: {{ payload.temperature }}C"
  }
]

Huginn: Website Change Monitor

# Huginn Agent configuration (JSON)
# Agent Type: WebsiteAgent
{
  "expected_update_period_in_days": 1,
  "url": "https://example.com/pricing",
  "type": "html",
  "mode": "on_change",
  "extract": {
    "price": {
      "css": ".pricing-card .price",
      "value": "string(.)"
    },
    "plan_name": {
      "css": ".pricing-card .plan-name",
      "value": "string(.)"
    }
  }
}

# Chained with EmailAgent to notify on changes:
{
  "subject": "Pricing change detected on example.com",
  "headline": "The following pricing changes were detected:",
  "expected_receive_period_in_days": 7
}

Webhook Integrations

Webhooks are the most common trigger for self-hosted automation. All three platforms support them:

# n8n webhook URL format:
# https://automation.example.com/webhook/your-workflow-id
# https://automation.example.com/webhook-test/your-workflow-id (for testing)

# Node-RED webhook (http-in node):
# https://nodered.example.com/your-endpoint

# Huginn webhook (WebhookAgent):
# https://huginn.example.com/users/1/web_requests/your-agent-id/your-secret

# Testing webhooks locally with curl:
curl -X POST https://automation.example.com/webhook/abc123 \
  -H "Content-Type: application/json" \
  -d '{"event": "deploy", "status": "success", "service": "web-app"}'
Tip: Use webhook URLs from your automation platform as notification targets in your monitoring stack. For example, configure Alertmanager to send alerts to an n8n webhook that then routes them to Slack, creates Jira tickets, and logs them to a database, all in a single workflow.

Scheduling and Cron

# n8n: Cron trigger node
# - Run every 5 minutes: */5 * * * *
# - Run daily at 9 AM: 0 9 * * *
# - Run on weekdays only: 0 9 * * 1-5

# Node-RED: Inject node with cron
# - Repeat: interval or cron expression
# - Supports seconds for high-frequency: */10 * * * * * (every 10 seconds)

# Huginn: Per-agent scheduling
# - check_every: "2h" (every 2 hours)
# - check_every: "1d" (daily)
# - schedule: "8pm" (specific time)

API Integrations

Common integrations available across platforms:

Integration n8n Node-RED Huginn
Slack / Discord Native node Community node SlackAgent
GitHub / GitLab Native node Community node HTTP Agent
Email (SMTP/IMAP) Native node Core node EmailAgent / IMAPAgent
HTTP/REST API HTTP Request node http request node PostAgent / WebsiteAgent
Databases PostgreSQL, MySQL, MongoDB nodes Community nodes Via HTTP/SQL
MQTT MQTT node Core node (excellent) Not supported
RSS feeds RSS Read node Feed parse node RssAgent
Docker Via HTTP to Docker API Docker node Via HTTP

Monitoring Workflows

Your automation workflows are infrastructure; they need monitoring too:

# n8n exposes Prometheus metrics when N8N_METRICS=true
# Scrape at: http://n8n:5678/metrics
# Key metrics:
#   n8n_workflow_execution_total{status="success|error"}
#   n8n_workflow_execution_duration_seconds
#   n8n_active_workflows_total

# Monitor workflow health with a meta-workflow:
# 1. Cron trigger every hour
# 2. Query n8n API for recent execution errors
# 3. Alert via Slack/email if error rate exceeds threshold

# Node-RED health endpoint:
# GET http://node-red:1880/health
# Returns: {"status": "healthy"}
Warning: Automation workflows with external webhook endpoints are attack vectors. Always validate incoming webhook payloads, use webhook secrets/signatures where supported, and run automation containers in isolated Docker networks. An attacker who can trigger your webhooks can potentially execute arbitrary actions through your workflows.

Which One Should You Choose?

  • Choose n8n if you want the closest experience to Zapier/Make with a polished visual workflow builder, extensive built-in integrations, and good execution logging. Best for business automation, API orchestration, and teams transitioning from cloud automation tools.
  • Choose Node-RED if your automation involves IoT devices, hardware, MQTT, or data transformation pipelines. Best for home automation, industrial IoT, and data processing workflows where the flow-based programming model is natural.
  • Choose Huginn if you need web scraping, website monitoring, and IFTTT-style agent chains. Best for personal automation, content monitoring, and scenarios where you need to react to changes on the web.

Many self-hosters run both n8n and Node-RED: n8n for business-oriented API integrations (CRM, ticketing, notifications) and Node-RED for hardware and data pipeline automation. They complement rather than compete with each other.

Managing automation containers alongside the rest of your self-hosted stack is straightforward with tools like usulnet, which provides visibility into container health, resource usage, and logs across all your services.