Node-RED Flow-Based Programming Installation
Node-RED is a visual, flow-based programming tool built on Node.js that enables IoT, automation, and API integration through a browser-based editor where you wire together nodes to create workflows. This guide covers deploying Node-RED on Linux, creating flows, integrating with MQTT, building dashboards, exposing HTTP endpoints, and deploying to production.
Prerequisites
- Ubuntu 20.04/22.04 or CentOS 8/Rocky Linux 8+
- Node.js 18+ (LTS recommended)
- At least 512 MB RAM
- Root or sudo access
- Port 1880 available
Install Node-RED
Quick install script (Ubuntu/Debian):
# Install Node.js 18 LTS (if not already installed)
curl -fsSL https://deb.nodesource.com/setup_18.x | sudo -E bash -
sudo apt install -y nodejs
# Verify Node.js version
node --version # Should be v18.x or higher
npm --version
# Install Node-RED globally
sudo npm install -g --unsafe-perm node-red
# Verify installation
node-red --version
CentOS/Rocky Linux:
curl -fsSL https://rpm.nodesource.com/setup_18.x | sudo bash -
sudo dnf install -y nodejs
sudo npm install -g --unsafe-perm node-red
Raspberry Pi / Linux quick install:
# Use the official Node-RED install script (handles Node.js + Node-RED)
bash <(curl -sL https://raw.githubusercontent.com/node-red/linux-installers/master/deb/update-nodejs-and-nodered)
Start Node-RED:
# Start as current user (development)
node-red
# Access at http://your-server:1880
# Start with specific settings file
node-red --settings /opt/nodered/.node-red/settings.js
Secure and Configure Node-RED
Node-RED is open by default — secure it before exposing to a network:
# Initialize Node-RED (creates ~/.node-red/ config directory)
node-red &
sleep 5
kill %1
# Generate password hash for admin authentication
node -e "console.log(require('bcryptjs').hashSync('admin123', 8))"
# Or use node-red-admin tool:
sudo npm install -g node-red-admin
node-red-admin hash-pw
# Enter your password and copy the hash
# Edit settings file
nano ~/.node-red/settings.js
Key security settings in settings.js:
// ~/.node-red/settings.js
module.exports = {
// Admin UI authentication
adminAuth: {
type: "credentials",
users: [{
username: "admin",
password: "$2b$08$YourHashedPasswordHere", // bcrypt hash
permissions: "*"
}]
},
// HTTP port
uiPort: 1880,
// Bind to specific interface only
uiHost: "127.0.0.1", // Only localhost (use with Nginx proxy)
// Allow CORS for dashboard
httpAdminCors: {
origin: "https://nodered.example.com",
methods: "GET,PUT,POST,DELETE"
},
// Security headers
httpNodeCors: {
origin: "*",
methods: "GET,PUT,POST,DELETE"
},
// Logging
logging: {
console: {
level: "info",
metrics: false,
audit: false
}
},
// Function node timeout
functionTimeout: 30,
// Projects feature
editorTheme: {
projects: {
enabled: true
}
}
};
Create Your First Flow
Node-RED flows are created in the browser editor at http://your-server:1880:
Basic HTTP flow:
- Drag an http in node to the canvas
- Set Method:
GET, URL:/hello - Drag a function node and connect it
- Double-click the function node and add:
msg.payload = { message: "Hello from Node-RED!", time: new Date().toISOString() }; msg.statusCode = 200; return msg; - Drag an http response node and connect it
- Click Deploy
- Test:
curl http://localhost:1880/hello
Flow via JSON import (import via menu > Import):
[
{
"id": "inject1",
"type": "inject",
"name": "Every 30s",
"repeat": "30",
"wires": [["function1"]]
},
{
"id": "function1",
"type": "function",
"name": "Check time",
"func": "msg.payload = { hour: new Date().getHours(), minute: new Date().getMinutes() };\nreturn msg;",
"wires": [["debug1"]]
},
{
"id": "debug1",
"type": "debug",
"name": "Output",
"active": true,
"wires": []
}
]
MQTT Integration
Connect Node-RED to an MQTT broker to receive IoT sensor data:
# First, configure MQTT broker credentials in Node-RED:
# 1. Drag mqtt-in node to canvas
# 2. Double-click > click pencil icon next to Server
# 3. Server: localhost, Port: 1883
# 4. Security tab: Username + Password
# 5. Click Update > Done
Example sensor processing flow:
// Function node: Parse and validate sensor data
const data = JSON.parse(msg.payload);
if (!data.temperature || !data.device_id) {
node.warn("Invalid sensor data received");
return null; // Drop the message
}
// Convert Fahrenheit to Celsius if needed
if (data.unit === 'F') {
data.temperature = (data.temperature - 32) * 5/9;
data.unit = 'C';
}
// Add processing timestamp
data.processed_at = new Date().toISOString();
msg.payload = data;
msg.topic = `sensors/${data.device_id}/processed`;
return msg;
Subscribe to MQTT topic and forward to HTTP API:
[
{
"id": "mqtt-in",
"type": "mqtt in",
"topic": "home/+/temperature",
"qos": "1",
"broker": "mqtt-broker-config-id",
"wires": [["process-fn"]]
},
{
"id": "process-fn",
"type": "function",
"func": "const d = JSON.parse(msg.payload);\nmsg.payload = JSON.stringify({ device: msg.topic.split('/')[1], temp: d.value, ts: Date.now() });\nmsg.headers = { 'Content-Type': 'application/json' };\nreturn msg;",
"wires": [["http-post"]]
},
{
"id": "http-post",
"type": "http request",
"method": "POST",
"url": "http://localhost:3000/api/sensors",
"wires": [["debug"]]
}
]
Dashboard Nodes
Install and use the Node-RED Dashboard for visualization:
# Install dashboard nodes from the Palette Manager:
# Menu > Manage Palette > Install > search "node-red-dashboard"
# Or install via npm
cd ~/.node-red
npm install node-red-dashboard
# Restart Node-RED
# Dashboard UI available at: http://your-server:1880/ui
Dashboard flow example:
// gauge node configuration (via UI):
// Type: Gauge, Label: CPU Temperature
// Min: 0, Max: 100, Colour gradient: green-yellow-red
// Group: System Monitor
// Chart node:
// Type: Line chart
// Label: Temperature Over Time
// X-Axis: Last 1 hour
// In function node, format data for gauge:
msg.payload = context.global.get('cpu_temp') || 45;
return msg;
HTTP API Endpoints
Create REST API endpoints with Node-RED:
// HTTP In node: POST /api/trigger
// Function node:
const body = msg.payload;
if (!body.action) {
msg.statusCode = 400;
msg.payload = { error: "Missing 'action' field" };
return msg;
}
// Perform action based on request
switch (body.action) {
case 'restart_service':
// Trigger service restart flow
node.send([msg, null]);
msg.payload = { status: 'triggered', action: body.action };
break;
case 'send_alert':
node.send([null, msg]);
msg.payload = { status: 'alert_sent' };
break;
default:
msg.statusCode = 404;
msg.payload = { error: 'Unknown action' };
}
return msg;
Secure an API endpoint with a token check:
// Add before processing in API flows
const authHeader = msg.req.headers['authorization'];
const expectedToken = env.get('API_TOKEN'); // Set via environment variable
if (!authHeader || authHeader !== `Bearer ${expectedToken}`) {
msg.statusCode = 401;
msg.payload = { error: 'Unauthorized' };
node.send([null, msg]); // Second output goes to http response
return;
}
// Proceed with authenticated request
return [msg, null];
Custom Nodes
Install community nodes from the palette:
# Common useful nodes
cd ~/.node-red
npm install node-red-contrib-influxdb # InfluxDB integration
npm install node-red-contrib-postgresql # PostgreSQL
npm install node-red-node-email # Email sending
npm install node-red-contrib-telegrambot # Telegram bot
npm install node-red-contrib-cron-plus # Advanced scheduling
# List installed nodes
npm list --depth=0 | grep node-red
Create a simple custom node:
mkdir -p ~/.node-red/nodes/my-validator
cat > ~/.node-red/nodes/my-validator/my-validator.js << 'EOF'
module.exports = function(RED) {
function ValidatorNode(config) {
RED.nodes.createNode(this, config);
const node = this;
const field = config.field || 'payload';
node.on('input', function(msg, send, done) {
const value = msg[field];
if (value === undefined || value === null) {
node.warn(`Field ${field} is missing or null`);
done();
return;
}
msg.valid = true;
send(msg);
done();
});
}
RED.nodes.registerType("my-validator", ValidatorNode);
};
EOF
cat > ~/.node-red/nodes/my-validator/my-validator.html << 'EOF'
<script type="text/javascript">
RED.nodes.registerType('my-validator', {
category: 'function',
color: '#a6bbcf',
defaults: { name: {value:""}, field: {value:"payload"} },
inputs: 1,
outputs: 1,
label: function() { return this.name || "validator"; }
});
</script>
EOF
Production Deployment
# Create a dedicated user
sudo useradd -r -m -d /opt/nodered -s /bin/bash nodered
sudo -u nodered npm install -g node-red
# Create systemd service
cat > /etc/systemd/system/node-red.service << 'EOF'
[Unit]
Description=Node-RED Flow-Based Programming
After=network.target
[Service]
Type=simple
User=nodered
WorkingDirectory=/opt/nodered
ExecStart=/usr/bin/node-red --settings /opt/nodered/.node-red/settings.js
Restart=on-failure
RestartSec=5
KillSignal=SIGINT
# Environment variables
Environment="NODE_ENV=production"
Environment="API_TOKEN=your-secret-api-token"
Environment="MQTT_PASSWORD=mqttpassword"
[Install]
WantedBy=multi-user.target
EOF
sudo systemctl daemon-reload
sudo systemctl enable --now node-red
# Configure Nginx reverse proxy
cat > /etc/nginx/sites-available/node-red << 'EOF'
server {
listen 443 ssl http2;
server_name nodered.example.com;
ssl_certificate /etc/letsencrypt/live/nodered.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/nodered.example.com/privkey.pem;
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-Real-IP $remote_addr;
proxy_read_timeout 86400;
}
}
EOF
sudo ln -s /etc/nginx/sites-available/node-red /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx
Troubleshooting
Node-RED won't start after installing a node:
# Check logs for errors
node-red --verbose 2>&1 | head -50
sudo journalctl -u node-red -n 50
# Remove the problematic node
cd ~/.node-red
npm uninstall node-red-contrib-problematic-node
Flows not deploying:
# Check browser console for JavaScript errors (F12)
# Verify settings.js syntax
node -e "require('./settings.js')" ~/.node-red/settings.js
# Check disk space
df -h /opt/nodered
MQTT messages not received:
# Test MQTT connection from command line
mosquitto_sub -h localhost -p 1883 -u homeassistant -P mqttpassword -t "home/#" -v
# Check Node-RED debug tab for connection errors
# Verify MQTT broker config in the node settings
Dashboard not loading:
# Verify node-red-dashboard is installed
ls ~/.node-red/node_modules | grep dashboard
# Check dashboard URL
curl http://localhost:1880/ui
# Reinstall dashboard
cd ~/.node-red && npm install node-red-dashboard
node-red-admin init
Conclusion
Node-RED's visual flow editor dramatically reduces the complexity of integrating IoT devices, APIs, and automation workflows — tasks that would require significant boilerplate code become a matter of wiring nodes together. Deploy it as a systemd service behind an Nginx reverse proxy with authentication for production use, leverage the extensive palette of community nodes for integrations, and use the Function node for custom JavaScript logic when built-in nodes are insufficient.


