DEV Community

Cover image for Node-RED Kubernetes Deployment & Password Management Guide
Durrell  Gemuh
Durrell Gemuh

Posted on

Node-RED Kubernetes Deployment & Password Management Guide

Deploying Node-RED on Kubernetes is a powerful way to run your low-code workflows at scale. In this guide, I’ll walk you through a streamlined setup on GKE (Google Kubernetes Engine), including secure password management best practices.

Prerequisites

  • Kubernetes cluster (GKE) with kubectl configured
  • Node-RED Docker image: nodered/node-red:4.0.8
  • (Optional) Static IP and ManagedCertificate for HTTPS (GKE Ingress)
  1. Initial Deployment

1.1 Deploy Node-RED Deployment (deployment.yml)

apiVersion: apps/v1
kind: Deployment
metadata:
  name: node-red
  namespace: <namespace>
  labels:
    app: node-red
spec:
  replicas: 1
  selector:
    matchLabels:
      app: node-red
  template:
    metadata:
      labels:
        app: node-red
    spec:
      securityContext:
        fsGroup: 1000
      containers:
      - name: nodered
        image: nodered/node-red:4.0.8
        args: ["--settings", "/config/settings.js"]
        env:
        - name: NODE_OPTIONS
          value: "--trace-warnings"
        ports:
        - containerPort: 1880
        securityContext:
          runAsUser: 1000
          runAsGroup: 1000
          allowPrivilegeEscalation: false
        resources:
          limits:
            memory: "512Mi"
            cpu: "500m"
          requests:
            memory: "256Mi"
            cpu: "250m"
        livenessProbe:
          httpGet:
            path: /
            port: 1880
          initialDelaySeconds: 30
          periodSeconds: 10
        readinessProbe:
          httpGet:
            path: /
            port: 1880
          initialDelaySeconds: 5
          periodSeconds: 5
        volumeMounts:
        - name: node-red-storage
          mountPath: /data
        - name: node-red-settings
          mountPath: /config/settings.js
          subPath: settings.js
      volumes:
      - name: node-red-storage
        persistentVolumeClaim:
          claimName: node-red-pvc
      - name: node-red-settings
        configMap:
          name: node-red-settings
Enter fullscreen mode Exit fullscreen mode

Deploy:
kubectl apply -f deployment.yml -n <namespace>

1.2 Create ConfigMap (configmap.yml)
Note: Leave the password blank for now; you will generate it inside the pod.

apiVersion: v1
kind: ConfigMap
metadata:
  name: node-red-settings
  namespace: <namespace>
data:
  settings.js: |
    module.exports = {
      httpAdminRoot: '/',
      httpNodeRoot: '/',
      userDir: '/data',
      flowFile: 'flows.json',
      credentialSecret: 'yzM0ol6Zn5kd1234',
      adminAuth: {
        type: "credentials",
        users: [{
          username: "admin",
          password: "",
          permissions: "*"
        }]
      },
      uiPort: process.env.PORT || 1880,
      mqttReconnectTime: 15000,
      serialReconnectTime: 15000,
      debugMaxLength: 1000,
      functionGlobalContext: {},
      exportGlobalContextKeys: false,
      logging: {
        console: {
          level: "info",
          metrics: false,
          audit: false
        }
      },
      editorTheme: {
        projects: {
          enabled: false
        }
      }
    };
Enter fullscreen mode Exit fullscreen mode

Apply:
kubectl apply -f configmap.yml -n <namespace>

1.3 Expose Service (service.yml)

apiVersion: v1
kind: Service
metadata:
  name: node-red-service
  namespace: <namespace>
  labels:
    app: node-red
spec:
  type: ClusterIP
  ports:
  - port: 1880
    targetPort: 1880
    protocol: TCP
    name: http
  selector:
    app: node-red
Enter fullscreen mode Exit fullscreen mode

Apply:
kubectl apply -f service.yml -n <namespace>

1.4 Create Persistent Volume Claim (pvc.yml)

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: node-red-pvc
  namespace: <namespace>
  labels:
    app: node-red
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 2Gi
Enter fullscreen mode Exit fullscreen mode

Apply it with:
kubectl apply -f pvc.yml -n <namespace>

1.5 Optional: Ingress & HTTPS (ingress.yml)

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: node-red-ingress
  namespace: <namespace>
  labels:
    app: node-red
  annotations:
    kubernetes.io/ingress.class: "gce"
    kubernetes.io/ingress.global-static-ip-name: "node-red"
    ingress.gcp.kubernetes.io/pre-shared-cert: "mcrt-b7f0d81d-9c86-4731-b38f-111c1a486a44"
    nginx.ingress.kubernetes.io/proxy-body-size: "10m"
    nginx.ingress.kubernetes.io/rewrite-target: /
    cloud.google.com/backend-config: '{"default": "node-red-backendconfig"}'
spec:
  rules:
  - host: node-red.dev.c1conversations.io
    http:
      paths:
      - path: /*
        pathType: ImplementationSpecific
        backend:
          service:
            name: node-red-service
            port:
              number: 1880
Enter fullscreen mode Exit fullscreen mode

Apply:
kubectl apply -f ingress.yml -n <namespace>

1.6 Horizontal Pod Autoscaler (hpa.yml)

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: node-red-hpa
  namespace: <namespace>
  labels:
    app: node-red
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: node-red
  minReplicas: 1
  maxReplicas: 3
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 70
  - type: Resource
    resource:
      name: memory
      target:
        type: Utilization
        averageUtilization: 80
Enter fullscreen mode Exit fullscreen mode

Apply:
kubectl apply -f hpa.yml -n <namespace>

1.7 BackendConfig (backend.yml)

apiVersion: cloud.google.com/v1
kind: BackendConfig
metadata:
  name: node-red-backendconfig
  namespace: <namespace>
spec:
  healthCheck:
    checkIntervalSec: 10
    timeoutSec: 5
    healthyThreshold: 1
    unhealthyThreshold: 3
    type: HTTP
    requestPath: /
    port: 1880
Enter fullscreen mode Exit fullscreen mode

Apply:
kubectl apply -f backend.yml -n <namespace>

  1. Generate Password Inside the Pod After deployment is ready, generate a hashed password inside the pod:
kubectl get pods -n <namespace>
kubectl exec -it <node-red-pod> -n <namespace> -- node-red admin hash-pw
Enter fullscreen mode Exit fullscreen mode

Enter your desired password when prompted. Copy the generated bcrypt hash.

  1. Update ConfigMap with Hashed Password Edit the ConfigMap: kubectl edit configmap node-red-settings -n <namespace>

Paste the bcrypt hash under:

js
adminAuth: {
  users: [{
    username: "admin",
    password: "<bcrypt-hash-here>",
    permissions: "*"
  }]
}
Enter fullscreen mode Exit fullscreen mode
  1. Restart Node-RED Pod
    Delete the pod to reload the updated ConfigMap and password:
    kubectl delete pod <node-red-pod> -n <namespace>
    Kubernetes will recreate it automatically. Log in to the Node-RED UI with your new password.

  2. Changing Password in the Future
    Exec into the pod again and generate a new hash:
    kubectl exec -it <node-red-pod> -n <namespace> -- node-red admin hash-pw
    Update the ConfigMap with the new hash.
    Delete the pod to reload the ConfigMap.
    Node-RED will pick up the new password immediately.

  3. Notes & Best Practices
    Always generate bcrypt hashes inside the running pod to match Node.js versions and environment, ensuring compatibility.

Never hardcode plain-text passwords in ConfigMaps. Always store hashed passwords.

The credentialSecret encrypts flow credentials (like MQTT passwords). Changing it requires regenerating flows_cred.json.

Deploying Node-RED on Kubernetes with secure password practices helps you scale workflows without sacrificing security. Happy automating!

If you found this guide helpful or have questions, feel free to leave a comment!

Top comments (0)