Instalación de Node-RED: Programación por Flujos en Linux

Node-RED es una herramienta de programación visual basada en flujos que permite conectar dispositivos IoT, APIs web y servicios en línea mediante una interfaz de arrastre y suelta. Construido sobre Node.js, facilita la creación de integraciones complejas sin necesidad de escribir código, siendo especialmente popular en proyectos de automatización industrial, IoT y orquestación de servicios en servidores Linux.

Requisitos Previos

  • Ubuntu 20.04/22.04 o CentOS/Rocky Linux 8+
  • Node.js 18 LTS o superior
  • npm 8+ (incluido con Node.js)
  • Al menos 512 MB de RAM
  • Acceso root o usuario con privilegios sudo

Instalación de Node-RED

Instalación con el script oficial (recomendada)

# El script oficial instala Node.js, npm y Node-RED
bash <(curl -sL https://raw.githubusercontent.com/node-red/linux-installers/master/deb/update-nodejs-and-nodered)

# El script preguntará si instalar las herramientas de Raspberry Pi:
# Responder NO en un servidor Linux estándar

# Habilitar e iniciar el servicio
sudo systemctl enable nodered.service
sudo systemctl start nodered.service

# Verificar estado
sudo systemctl status nodered.service

# Acceder a la interfaz web:
# http://IP_DEL_SERVIDOR:1880

Instalación manual con npm

# Instalar Node.js 20 LTS
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
sudo apt-get install -y nodejs

# Verificar versiones
node --version
npm --version

# Instalar Node-RED globalmente
sudo npm install -g --unsafe-perm node-red

# Verificar instalación
node-red --version

# Iniciar Node-RED (el editor escucha en el puerto 1880)
node-red &

# Para uso en producción, crear usuario dedicado
sudo useradd -m -r -s /bin/bash nodered
sudo -u nodered node-red &

Instalación con Docker

# Ejecutar Node-RED con Docker
docker run -d \
    --name nodered \
    -p 1880:1880 \
    -v nodered_data:/data \
    -e TZ=Europe/Madrid \
    --restart unless-stopped \
    nodered/node-red:latest

# Ver logs de inicio
docker logs nodered -f

Configuración Inicial

Configurar la seguridad y las opciones de Node-RED:

# El archivo de configuración está en ~/.node-red/settings.js
# En instalación con servicio: /root/.node-red/settings.js o /home/nodered/.node-red/settings.js

nano ~/.node-red/settings.js

Configuración básica de seguridad:

module.exports = {
    // Puerto de escucha del editor
    uiPort: process.env.PORT || 1880,
    
    // Directorio de flujos
    userDir: '/home/nodered/.node-red',
    flowFile: 'flows.json',
    
    // Credenciales encriptadas
    credentialSecret: "mi_clave_de_encriptacion_segura",
    
    // Autenticación en la interfaz web (IMPORTANTE: habilitar en producción)
    adminAuth: {
        type: "credentials",
        users: [
            {
                username: "admin",
                // Generar hash: node-red-admin hash-pw
                password: "$2a$08$zZWtXTja0fB1pzD4sHCMyOCMYz2Z6dNbM6tl8sJogENOMcxWV9DN.",
                permissions: "*"
            },
            {
                username: "readonly",
                password: "$2a$08$HASH_PASSWORD_LECTURA",
                permissions: "read"
            }
        ]
    },
    
    // Configurar tiempo de sesión (en milisegundos)
    adminAuth: {
        sessionExpiryTime: 86400, // 24 horas en segundos
    },
    
    // Logging
    logging: {
        console: {
            level: "info",
            metrics: false,
            audit: false
        }
    },
    
    // Editor de código habilitado
    codeEditor: {
        lib: {
            // Usar Monaco editor (mejor experiencia)
            editor: "monaco"
        }
    }
}

Generar la contraseña hasheada:

# Generar hash de contraseña para la configuración
node-red-admin hash-pw
# Introducir la contraseña cuando se pide
# Copiar el hash generado a settings.js

# Reiniciar Node-RED para aplicar cambios
sudo systemctl restart nodered.service

Creación de Flujos

Los flujos se crean visualmente, pero se almacenan como JSON:

# Importar un flujo de ejemplo via API REST de Node-RED
# Primero obtener el token de sesión (si la autenticación está habilitada)
TOKEN=$(curl -s -X POST http://localhost:1880/auth/token \
    -H "Content-Type: application/json" \
    -d '{"client_id":"node-red-admin","grant_type":"password","username":"admin","password":"contraseña"}' \
    | python3 -c "import sys,json; print(json.load(sys.stdin)['access_token'])")

# Importar flujo via API
curl -X POST http://localhost:1880/flows \
    -H "Authorization: Bearer $TOKEN" \
    -H "Content-Type: application/json" \
    -d '{
        "flows": [
            {
                "id": "tab1",
                "type": "tab",
                "label": "Mi Primer Flujo"
            },
            {
                "id": "inject1",
                "type": "inject",
                "z": "tab1",
                "name": "Cada minuto",
                "repeat": "60",
                "once": true,
                "wires": [["function1"]]
            },
            {
                "id": "function1",
                "type": "function",
                "z": "tab1",
                "name": "Procesar datos",
                "func": "// Código JavaScript del nodo función\nvar ahora = new Date();\nmsg.payload = {\n    timestamp: ahora.toISOString(),\n    hora: ahora.getHours(),\n    minuto: ahora.getMinutes()\n};\nreturn msg;",
                "wires": [["debug1"]]
            },
            {
                "id": "debug1",
                "type": "debug",
                "z": "tab1",
                "name": "Ver resultado",
                "active": true,
                "wires": []
            }
        ]
    }'

Ejemplo de flujo para monitorización del servidor:

// Código del nodo Function para monitorizar el servidor
// Este código se pega en el nodo "Función" del editor visual

const { execSync } = require('child_process');

// Obtener uso de CPU (valor de 0-100)
const cpuInfo = execSync("top -bn1 | grep 'Cpu(s)' | awk '{print $2}'").toString().trim();
const cpu = parseFloat(cpuInfo) || 0;

// Obtener uso de memoria
const memInfo = execSync("free | awk '/^Mem:/{printf \"%.1f\", $3/$2 * 100}'").toString().trim();
const memoria = parseFloat(memInfo) || 0;

// Obtener uso de disco
const discoInfo = execSync("df / | awk 'NR==2{print $5}' | tr -d '%'").toString().trim();
const disco = parseInt(discoInfo) || 0;

// Construir el payload de la métrica
msg.payload = {
    timestamp: new Date().toISOString(),
    host: require('os').hostname(),
    cpu_porcentaje: cpu,
    memoria_porcentaje: memoria,
    disco_porcentaje: disco,
    alerta: (cpu > 80 || memoria > 85 || disco > 90)
};

// Añadir nivel de severidad
if (msg.payload.alerta) {
    msg.topic = "alerta/servidor/" + require('os').hostname();
} else {
    msg.topic = "metricas/servidor/" + require('os').hostname();
}

return msg;

Integración con MQTT

Conectar Node-RED con un broker MQTT:

# Instalar el paquete MQTT adicional si es necesario
# (node-red-contrib-mqtt-broker para broker integrado)
cd ~/.node-red && npm install node-red-contrib-mqtt-broker

sudo systemctl restart nodered.service

Configuración de flujo MQTT en JSON:

[
    {
        "id": "mqtt-in-sensores",
        "type": "mqtt in",
        "name": "Recibir datos sensores",
        "topic": "casa/+/datos",
        "broker": "broker-local",
        "wires": [["parse-json"]]
    },
    {
        "id": "parse-json",
        "type": "json",
        "name": "Parsear JSON",
        "action": "obj",
        "wires": [["verificar-temperatura"]]
    },
    {
        "id": "verificar-temperatura",
        "type": "switch",
        "name": "¿Temperatura alta?",
        "property": "payload.temperatura",
        "rules": [
            {"t": "gt", "v": "28"},
            {"t": "else"}
        ],
        "wires": [["enviar-alerta"], ["almacenar-dato"]]
    },
    {
        "id": "broker-local",
        "type": "mqtt-broker",
        "name": "Mosquitto Local",
        "broker": "localhost",
        "port": "1883",
        "clientid": "nodered-client",
        "autoConnect": true,
        "usetls": false,
        "protocolVersion": "4",
        "keepalive": "60",
        "credentials": {
            "user": "nodered_user",
            "password": "mqtt_password"
        }
    }
]

Nodos de Dashboard

Crear interfaces visuales con node-red-dashboard:

# Instalar el módulo de dashboard
cd ~/.node-red
npm install node-red-dashboard

sudo systemctl restart nodered.service

# El dashboard estará disponible en: http://servidor:1880/ui

Flujo de ejemplo para dashboard de temperatura:

// Nodo Function para preparar datos del gráfico
// El payload de entrada: {"temperatura": 22.5, "humedad": 60}

// Redirigir temperatura al gauge del dashboard
var msgTemperatura = {
    payload: msg.payload.temperatura,
    topic: "Temperatura (°C)"
};

// Redirigir humedad al gauge del dashboard  
var msgHumedad = {
    payload: msg.payload.humedad,
    topic: "Humedad (%)"
};

// Devolver múltiples salidas (el nodo Function puede tener varias)
return [msgTemperatura, msgHumedad];

Endpoints de API REST

Crear APIs HTTP con Node-RED:

[
    {
        "id": "http-endpoint",
        "type": "http in",
        "name": "GET /api/estado",
        "url": "/api/estado",
        "method": "get",
        "wires": [["get-estado"]]
    },
    {
        "id": "get-estado",
        "type": "function",
        "name": "Obtener estado del sistema",
        "func": "const os = require('os');\n\nmsg.payload = {\n    uptime_segundos: os.uptime(),\n    memoria_libre_mb: Math.round(os.freemem() / 1024 / 1024),\n    memoria_total_mb: Math.round(os.totalmem() / 1024 / 1024),\n    cpus: os.cpus().length,\n    load: os.loadavg(),\n    hostname: os.hostname()\n};\n\nmsg.statusCode = 200;\nreturn msg;",
        "wires": [["http-response"]]
    },
    {
        "id": "http-response",
        "type": "http response",
        "name": "Responder JSON",
        "statusCode": "",
        "headers": {"Content-Type": "application/json"},
        "wires": []
    }
]
# Probar el endpoint creado
curl -s http://localhost:1880/api/estado | python3 -m json.tool

# Crear endpoint POST para recibir webhooks
# (añadir en el flujo un nodo "http in" con method: POST y la URL deseada)

Nodos Personalizados

Instalar y usar nodos de la comunidad:

# Instalar nodos desde la paleta de Node-RED
# Herramientas > Gestionar paleta > Instalar

# O instalar directamente via npm
cd ~/.node-red

# Nodo para InfluxDB
npm install node-red-contrib-influxdb

# Nodo para notificaciones Telegram
npm install node-red-contrib-telegrambot

# Nodo para bases de datos SQLite
npm install node-red-node-sqlite

# Nodo para email
npm install node-red-node-email

# Nodo para monitorización de sitios web
npm install node-red-node-ping

sudo systemctl restart nodered.service

# Ver los nodos instalados
npm list --depth=0 --prefix ~/.node-red

Despliegue en Producción

Configuración para entornos de producción:

# 1. Configurar Nginx como proxy inverso con SSL
sudo cat > /etc/nginx/sites-available/nodered << 'EOF'
server {
    listen 80;
    server_name nodered.mi-dominio.com;
    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl http2;
    server_name nodered.mi-dominio.com;
    
    ssl_certificate /etc/letsencrypt/live/nodered.mi-dominio.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/nodered.mi-dominio.com/privkey.pem;
    
    # Editor de Node-RED (acceso restringido)
    location / {
        # Limitar acceso al editor solo desde IPs de administración
        allow 192.168.1.0/24;
        allow 10.0.0.0/8;
        deny all;
        
        proxy_pass http://127.0.0.1:1880;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        
        # WebSocket para actualizaciones en tiempo real del editor
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }
    
    # Dashboard público (accesible externamente)
    location /ui {
        proxy_pass http://127.0.0.1:1880;
        proxy_set_header Host $host;
    }
    
    # Endpoints de API pública
    location /api/ {
        proxy_pass http://127.0.0.1:1880;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}
EOF

sudo ln -s /etc/nginx/sites-available/nodered /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx

# 2. Configurar límites del sistema para el servicio
sudo mkdir -p /etc/systemd/system/nodered.service.d/
cat > /etc/systemd/system/nodered.service.d/override.conf << 'EOF'
[Service]
# Límites de recursos
LimitNOFILE=65535
# Reiniciar automáticamente si falla
Restart=always
RestartSec=10
EOF

sudo systemctl daemon-reload && sudo systemctl restart nodered.service

Solución de Problemas

Node-RED no arranca (error de Node.js):

# Verificar versión de Node.js
node --version  # Debe ser 18+ para la versión actual de Node-RED

# Ver logs del servicio
sudo journalctl -u nodered -n 50

# Iniciar manualmente para ver errores
sudo -u nodered node-red --userDir /home/nodered/.node-red

Los flujos no se despliegan (error en el editor):

# Ver los logs del servidor de Node-RED en tiempo real
tail -f ~/.node-red/node-red.log

# Verificar que el archivo de flujos no tiene errores JSON
python3 -m json.tool ~/.node-red/flows.json

Error de credenciales MQTT:

# Verificar la configuración del broker en el nodo MQTT
# El broker debe ser accesible desde el servidor
telnet localhost 1883

# Ver los logs del broker Mosquitto
sudo journalctl -u mosquitto -n 20

El dashboard no carga:

# Verificar que el módulo de dashboard está instalado
ls ~/.node-red/node_modules | grep dashboard

# Reinstalar si es necesario
cd ~/.node-red && npm install node-red-dashboard
sudo systemctl restart nodered.service

Conclusión

Node-RED democratiza la integración de sistemas y dispositivos IoT al eliminar la necesidad de escribir código para conectar servicios, sensores y APIs mediante una interfaz visual intuitiva. Su modelo de programación por flujos es especialmente poderoso para prototipar y desplegar rápidamente integraciones que de otra forma requerirían desarrollo significativo. La combinación de MQTT, las extensas librerías de nodos de la comunidad y los endpoints HTTP nativos convierte a Node-RED en una plataforma de orquestación de servicios completa para proyectos IoT y automatización en servidores Linux de producción.