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)
- 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
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
}
}
};
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
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
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
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
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
Apply:
kubectl apply -f backend.yml -n <namespace>
- 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 your desired password when prompted. Copy the generated bcrypt hash.
- 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: "*"
}]
}
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.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.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)