Self-Hosted Automation: n8n, Node-RED and Huginn for Workflow Automation
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"}'
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"}
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.