Node-RED is a flow-based, low-code programming tool. You wire together nodes in a browser editor (HTTP endpoints, MQTT, timers, databases, APIs, functions) to build automations, integrations and IoT dashboards, without writing a full application. On a VPS it’s a great always-on hub for webhooks, home automation glue, data collection and alerting.
Comparable tools: n8n (business workflow automation) and Home Assistant (smart home).
Install with Docker (recommended)
# /opt/nodered/compose.yaml
services:
nodered:
image: nodered/node-red:latest
restart: unless-stopped
ports:
- "127.0.0.1:1880:1880"
environment:
TZ: Etc/UTC
volumes:
- ./data:/data
sudo mkdir -p /opt/nodered/data && sudo chown -R 1000:1000 /opt/nodered/data
cd /opt/nodered && docker compose up -d
All flows, credentials, settings and installed nodes live in ./data.
Or with npm (Node.js 18+)
sudo npm install -g --unsafe-perm node-red
node-red
Run it as a systemd service under a dedicated user. See systemd for Node apps and install Node.js.
Secure the editor: do this first
Out of the box, the Node-RED editor has no authentication. Anyone who reaches it can run arbitrary code on your server (the function and exec nodes). Never expose it unprotected.
Generate a password hash:
docker compose exec nodered node-red admin hash-pw
Edit ./data/settings.js:
adminAuth: {
type: "credentials",
users: [{
username: "admin",
password: "$2b$08$…hash…",
permissions: "*"
}]
},
credentialSecret: "a-long-random-string", // encrypts stored credentials
Restart with docker compose restart. Keep credentialSecret safe. Without it, you can’t decrypt stored credentials after migrating.
HTTPS with Nginx
server {
server_name flows.example.com;
location / {
proxy_pass http://127.0.0.1:1880;
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-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
# listen 443 ssl; certbot --nginx -d flows.example.com
}
For extra protection, restrict the editor (/) to your IPs or a VPN, while public HTTP-in endpoints stay reachable. Move the editor to a path with httpAdminRoot: '/admin' in settings.js, and protect that path separately. See Nginx basic auth and zero trust networking.
Your first flows
Webhook → Telegram/Slack alert: an http in node (POST /hooks/deploy) → a function node (format the message) → an http request node (Slack webhook URL) → an http response node.
MQTT sensors → database: an mqtt in node (sensors/+/temperature) → json → an InfluxDB or PostgreSQL node. See Mosquitto MQTT and InfluxDB.
Scheduled API polling: an inject node (every 10 minutes) → http request → switch (thresholds) → notification.
Export and import flows as JSON, which is handy for sharing and version control.
Add nodes
Menu → Manage palette → Install to add community nodes: node-red-dashboard (or the newer FlowFuse Dashboard) for UI dashboards, database nodes, Telegram, Home Assistant, Modbus and more. Prefer well-maintained nodes. Each one runs with Node-RED’s permissions.
Projects and Git
Enable Projects (editorTheme.projects.enabled: true in settings.js) to manage flows in a Git repository, with commits and diffs from the editor. That’s useful for teams and for rolling back changes.
Backups
Back up ./data (flows, flows_cred.json, settings.js, and installed nodes via package.json), plus the credentialSecret. Copy it off-server regularly. See backup strategy.
Updates
docker compose pull && docker compose up -d. Check that community nodes are compatible with the new Node-RED and Node.js versions. See updating self-hosted apps.
Quick reference
| Task | Command / setting |
|---|---|
| Start | docker compose up -d |
| Editor | port 1880 (behind Nginx) |
| Password hash | node-red admin hash-pw |
| Auth | adminAuth in settings.js |
| Credential encryption | credentialSecret |
| Data to back up | /data volume |
Related: Docker security and webhooks explained.