Developer Tools AWS

Node-RED 5.0.9 on AWS User Guide

| Product: Node-RED 5.0.9 on Ubuntu 24.04 on AWS

Overview

This guide covers launching and using the Node-RED 5.0.9 on Ubuntu 24.04 AMI from cloudimg on Amazon EC2. It is one version of the cloudimg developer and API tools listing on AWS Marketplace; you pick it as the software version when you subscribe and launch.

Node-RED is an open source, low-code programming tool for event-driven applications. In a browser editor you wire nodes into flows that receive HTTP requests, call APIs, transform messages, talk to MQTT brokers and databases and run your own JavaScript, then deploy them with one click.

Node-RED runs code. Anyone who signs in to the editor can run any JavaScript (function nodes) and any shell command (exec nodes) on the instance as the node-red service user, so treat the passwords like SSH access and give them only to people you trust with the instance. The cloudimg image keeps everyone else out and keeps flow code away from the rest of the instance:

  • HTTPS from the first boot. nginx serves Node-RED on port 443 with a certificate generated on your instance's first boot. Port 80 redirects to HTTPS.
  • Two logins before the editor, both unique to your instance. Your browser first asks for an HTTP login (user admin), then Node-RED's own admin login (user admin, a different password) is switched on. Upstream Node-RED ships with no login at all. Both passwords are generated on first boot and written to /var/lib/cloudimg/node-red-credentials.txt (root only); only bcrypt hashes are stored anywhere else. No password is baked into the image.
  • Your flows' HTTP endpoints are not public by default. HTTP In nodes are served under /api/ and need a third per instance login (user api), checked by nginx and again by Node-RED. You can make them public deliberately (Step 7).
  • Flow credentials are encrypted with a key unique to your instance (credentialSecret), generated on first boot.
  • Flow code is sandboxed. Node-RED and everything a flow starts run as the unprivileged node-red user with no capabilities, a read only view of the system except the data volume, private /tmp and devices, and a memory ceiling. That user cannot read the passwords, the certificate key or the login files.
  • No route to the instance metadata service. Node-RED, every process a flow starts and nginx are blocked from the EC2 metadata service (IPv4 and IPv6) at the kernel level, so a flow cannot pick up the instance's role credentials.
  • Cross site protection. Another web site cannot use your signed in browser to deploy flows or open the editor's live connection: state changing requests and WebSocket handshakes from another origin are refused, and the editor's API answers only to the Node-RED sign in token.
  • Nothing installs itself from the internet. The palette manager (installing extra nodes with npm) and npm modules in function nodes are off, and so are telemetry and the update check (Step 12 shows how to switch the palette manager on).
  • Current components from pinned sources. Node-RED 5.0.9 installed from a locked, integrity checked dependency list, with two of its libraries updated to releases that close advisories published after 5.0.9, on the official Node.js 24.22.1 LTS build. No compiler or package manager is left on the image.
  • Your flows on their own disk. Node-RED's user directory lives on a separate 20 GiB EBS volume at /var/lib/node-red.
  • Fully patched Ubuntu 24.04 LTS at build time, with unattended security upgrades switched on. The AMI requires IMDSv2.

What is on the image: Node-RED 5.0.9 (/opt/node-red), Node.js 24.22.1 (/opt/nodejs), nginx, Ubuntu 24.04 LTS, cloud-init and the AWS Systems Manager agent.

Default user: ubuntu · Architecture: x86_64 · Recommended instance type: m5.large

Prerequisites

  • An AWS account subscribed to the listing, an EC2 key pair and a VPC subnet.
  • A security group that allows TCP 22 (SSH), TCP 443 (Node-RED) and TCP 80 (redirects to HTTPS) from your own networks only.

Step 1: Launch the instance

In the AWS Marketplace listing choose Continue to Subscribe, then Continue to Configuration, pick Node-RED 5.0.9 on Ubuntu 24.04 as the software version and your Region, then Launch through EC2. Choose m5.large (2 vCPU, 8 GiB), your key pair and a security group as above. The AMI brings its 20 GiB data volume; you can make it larger on the launch page.

With the AWS CLI (replace the values in angle brackets):

aws ec2 run-instances --region <region> --image-id <ami-id-from-the-listing> \
  --instance-type m5.large --key-name <your-key-pair> \
  --security-group-ids <your-security-group> --subnet-id <your-subnet> \
  --metadata-options HttpTokens=required,HttpEndpoint=enabled \
  --tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=node-red}]'

Step 2: Connect to your instance

Version SSH user
Node-RED 5.0.9 on Ubuntu 24.04 ubuntu
ssh -i <your-key.pem> ubuntu@<public-ip>

Step 3: Check the services

First boot generates the certificate, the passwords and Node-RED's credential key, then Node-RED and nginx start:

systemctl is-active node-red nginx node-red-firstboot
sudo test -f /var/lib/cloudimg/node-red-firstboot.done && echo FIRSTBOOT_DONE
active
active
active
FIRSTBOOT_DONE

Only SSH and nginx listen on the network. Node-RED listens on 127.0.0.1:1880 only:

sudo ss -lntp | awk 'NR>1 {print $4, $6}' | grep -v '127.0.0.5' | sed -E 's/,pid=[0-9]+,fd=[0-9]+//g' | sort
0.0.0.0:22 users:(("sshd"),("systemd"))
0.0.0.0:443 users:(("nginx"),("nginx"),("nginx"))
0.0.0.0:80 users:(("nginx"),("nginx"),("nginx"))
127.0.0.1:1880 users:(("node-red"))
[::]:22 users:(("sshd"),("systemd"))
[::]:443 users:(("nginx"),("nginx"),("nginx"))
[::]:80 users:(("nginx"),("nginx"),("nginx"))

Step 4: Get your URL and passwords

sudo cat /var/lib/cloudimg/node-red-credentials.txt

The file is readable by root only and holds the URL and the three logins:

# Node-RED 5.0.9 - generated on first boot by node-red-firstboot.service
# These credentials are unique to this instance; none was baked into the image. Keep this file secret.
# Node-RED RUNS CODE: anyone who signs in to the editor can run any program as the 'node-red' user on this instance.

NODE_RED_URL=https://ec2-<public-ip-dashed>.compute-1.amazonaws.com/
HTTP_USERNAME=admin
HTTP_PASSWORD=<HTTP_PASSWORD>
NODE_RED_USERNAME=admin
NODE_RED_PASSWORD=<NODE_RED_PASSWORD>
API_BASE_URL=https://ec2-<public-ip-dashed>.compute-1.amazonaws.com/api/
API_USERNAME=api
API_PASSWORD=<API_PASSWORD>
#
# Two walls: your browser first asks for HTTP_USERNAME / HTTP_PASSWORD (nginx), then the Node-RED editor asks for
# NODE_RED_USERNAME / NODE_RED_PASSWORD. Your flows' HTTP In endpoints are served under API_BASE_URL and need
# API_USERNAME / API_PASSWORD (sudo node-red-api-auth off makes them public). The certificate is self-signed and minted
# on this instance's first boot; compare its fingerprint (sudo openssl x509 -in /etc/ssl/node-red/node-red.crt -noout
# -fingerprint -sha256) with what your browser shows. Port 80 redirects to https.
# Self-test:  sudo node-red-selftest      Change the name it is served as:  sudo node-red-set-hostname <your-dns-name>
# User guide: https://www.cloudimg.co.uk/guides/node-red-5-0-9-on-ubuntu-24-04-aws/

The URL uses the instance's public DNS name from EC2 instance metadata. The certificate also names the public and private IP addresses, so https://<public-ip>/ works too. To serve Node-RED under your own DNS name, see Step 10.

The self test signs in over HTTPS with the logins and checks the protections described in this guide:

sudo node-red-selftest
SELFTEST-OK https 301 + /health + 401 no/wrong HTTP credential + editor page + Admin API 401 without sign-in + sign-in token + /settings 5.0.9 + /flows + 403 cross-origin POST + 403 cross-origin WebSocket + /api/ 401 without, 404 with the api credential + token revoked + 444 unknown host

Step 5: Sign in

The certificate is self signed and was generated on your instance, so your browser warns about it the first time. Before you accept it, compare its SHA-256 fingerprint with the one the instance reports (do not add it to your computer's trust store; Step 10 shows how to use a certificate from your own certificate authority):

sudo openssl x509 -in /etc/ssl/node-red/node-red.crt -noout -fingerprint -sha256
sha256 Fingerprint=<32 colon-separated hex pairs, unique to your instance>

Open the NODE_RED_URL in your browser. It first asks for a user name and password: enter admin and the HTTP_PASSWORD. Node-RED then shows its own sign in page; enter admin and the NODE_RED_PASSWORD:

The Node-RED sign in page asking for the instance's Node-RED admin password

The editor opens on an empty flow. The palette on the left lists the nodes you can drag into a flow; the sidebar on the right shows node help, debug messages and deployment information:

The Node-RED 5.0.9 editor on cloudimg with an empty flow, the node palette and the sidebar

Step 6: Build and deploy a first flow

Drag an inject node and a debug node onto the workspace, wire the inject node's output to the debug node, then choose Deploy. Clicking the button on the inject node sends a timestamp, and the Debug messages tab in the sidebar shows it:

A first flow with an inject node wired to a debug node, deployed, with the timestamp in the debug sidebar

Flows are saved on the data volume as soon as you deploy. Menu > Export and Menu > Import copy flows between instances as JSON.

Step 7: Serve an HTTP endpoint from a flow

An http in node with the URL /hello, a template or function node and an http response node give you a web endpoint. Node-RED serves every HTTP In endpoint under /api/, so that flow answers at https://<your-host>/api/hello, and it needs the api login from the credentials file:

sudo bash -c '
  F=/var/lib/cloudimg/node-red-credentials.txt
  B=$(grep "^API_BASE_URL=" $F | cut -d= -f2-); H=$(echo "$B" | sed -E "s#^https://([^/]+)/.*#\1#")
  printf "user = \"api:%s\"\n" "$(grep "^API_PASSWORD=" $F | cut -d= -f2-)" > /run/nr-api.cfg; chmod 600 /run/nr-api.cfg
  curl -sk --resolve "$H:443:127.0.0.1" -o /dev/null -w "without the api login -> HTTP %{http_code}\n" "${B}hello"
  curl -sk --resolve "$H:443:127.0.0.1" -o /dev/null -w "with the api login, nothing deployed at /hello yet -> HTTP %{http_code}\n" -K /run/nr-api.cfg "${B}hello"
  rm -f /run/nr-api.cfg
'
without the api login -> HTTP 401
with the api login, nothing deployed at /hello yet -> HTTP 404

The editor's own logins do not open /api/, and the api login does not open the editor. To make your HTTP endpoints public (anyone who can reach port 443 can then call every HTTP In endpoint you deploy), switch the api login off; on switches it back:

sudo node-red-api-auth off
sudo node-red-api-auth status

Step 8: Where your flows live

df -h /var/lib/node-red | tail -1
sudo ls -l /var/lib/node-red /var/lib/node-red/data
/dev/nvme1n1     20G   72K   19G   1% /var/lib/node-red
/var/lib/node-red:
total 24
drwxr-x--- 4 node-red node-red  4096 Oct 28 10:37 data
drwxr-x--- 2 node-red node-red  4096 Oct 28 10:36 home
drwx------ 2 root     root     16384 Oct 28 09:47 lost+found

/var/lib/node-red/data:
total 12
drwxr-x--- 3 node-red node-red 4096 Oct 28 10:36 lib
drwxr-x--- 2 node-red node-red 4096 Oct 28 10:36 node_modules
-rw-r----- 1 node-red node-red  120 Oct 28 10:36 package.json
Path Holds
/var/lib/node-red/data/flows.json your flows
/var/lib/node-red/data/flows_cred.json credentials your nodes use (passwords, API keys), encrypted with this instance's credentialSecret
/var/lib/node-red/data/.sessions.json the editor's sign in sessions
/var/lib/node-red/data/lib your saved library entries
/var/lib/node-red/home the node-red user's home

The volume is a separate EBS volume, so you can grow it (modify the volume in the EC2 console, then sudo resize2fs on its device) or snapshot it on its own. To copy your flows off the instance:

sudo tar -czf <backup-dir>/node-red-flows.tar.gz -C /var/lib/node-red data

flows_cred.json can only be decrypted with this instance's credential key, /etc/node-red/credentials/credential-secret (root only). Keep a copy of it with your backup if you want to restore the flows' credentials on another instance.

Step 9: What flow code can and cannot reach

Function nodes, exec nodes and everything they start run as node-red in the same locked down service as Node-RED itself. From the command line you can confirm what that user can do: it cannot read the passwords, the credential key, the certificate key or the login files, and its service (like nginx) is blocked from the instance metadata service:

for f in /var/lib/cloudimg/node-red-credentials.txt /etc/node-red/credentials/admin-hash /etc/node-red/credentials/credential-secret /etc/ssl/node-red/node-red.key /etc/nginx/.node-red-htpasswd /etc/nginx/.node-red-api-htpasswd; do
  sudo -u node-red test -r "$f" && echo "readable: $f" || echo "not readable by node-red: $f"
done
systemctl show node-red -p User -p NoNewPrivileges -p ProtectSystem -p ReadWritePaths -p CapabilityBoundingSet -p MemoryMax
for u in node-red nginx; do echo "$u IPAddressDeny: $(systemctl show $u -p IPAddressDeny --value | tr ' ' '\n' | sort | xargs)"; done

MemoryMax is 80% of the instance's memory (here a 4 GiB t3.medium), shared by Node-RED and everything its flows start.

not readable by node-red: /var/lib/cloudimg/node-red-credentials.txt
not readable by node-red: /etc/node-red/credentials/admin-hash
not readable by node-red: /etc/node-red/credentials/credential-secret
not readable by node-red: /etc/ssl/node-red/node-red.key
not readable by node-red: /etc/nginx/.node-red-htpasswd
not readable by node-red: /etc/nginx/.node-red-api-htpasswd
MemoryMax=3214704640
CapabilityBoundingSet=
User=node-red
ReadWritePaths=/var/lib/node-red
ProtectSystem=strict
NoNewPrivileges=yes
node-red IPAddressDeny: 168.63.129.16/32 169.254.169.254/32 fd00:ec2::254/128
nginx IPAddressDeny: 168.63.129.16/32 169.254.169.254/32 fd00:ec2::254/128

To see the block from a flow, import this into the editor (Menu > Import), deploy it and click the inject node. The exec node asks the metadata service and, as a control, Node-RED's own sign in endpoint; the debug sidebar shows metadata=HTTP000 (no connection) next to loopback=HTTP200. Delete the flow afterwards.

[{"id":"a1b2c3d4e5f60001","type":"inject","name":"probe","props":[],"repeat":"","once":false,"topic":"","x":120,"y":80,"wires":[["a1b2c3d4e5f60002"]]},{"id":"a1b2c3d4e5f60002","type":"exec","command":"curl -s -m 5 -o /dev/null -w 'metadata=HTTP%{http_code} ' http://169.254.169.254/latest/meta-data/; curl -s -m 5 -o /dev/null -w 'loopback=HTTP%{http_code}' http://127.0.0.1:1880/auth/login","addpay":"","append":"","useSpawn":"false","timer":"20","winHide":false,"oldrc":false,"name":"","x":300,"y":80,"wires":[["a1b2c3d4e5f60003"],[],[]]},{"id":"a1b2c3d4e5f60003","type":"debug","name":"","active":true,"tosidebar":true,"complete":"payload","x":480,"y":80,"wires":[]}]

Step 10: Your own DNS name and certificate

Point a DNS record at the instance, then set the name Node-RED is served as. This generates a new self signed certificate for the name, updates nginx, the cross site protection and the URL in the credentials file, and keeps the name across reboots:

sudo node-red-set-hostname <your-domain>

To use a certificate from your own certificate authority instead, copy it over the generated pair and reload nginx (running node-red-set-hostname again replaces it with a self signed one):

sudo install -m 0644 <your-domain>.crt /etc/ssl/node-red/node-red.crt
sudo install -m 0600 <your-domain>.key /etc/ssl/node-red/node-red.key
sudo nginx -t && sudo systemctl reload nginx

Step 11: Change the passwords

The HTTP login is an nginx Basic Auth file. To set a new password for admin, hand it to htpasswd on standard input (printf is a shell builtin, so the password never appears in the process list; start the line with a space so most shells keep it out of your history), then reload nginx. The api login works the same way with /etc/nginx/.node-red-api-htpasswd:

 printf '%s\n' '<new-password>' | sudo htpasswd -i -B -C 12 /etc/nginx/.node-red-htpasswd admin
sudo systemctl reload nginx

Node-RED's own admin password is stored as a bcrypt hash in /etc/node-red/credentials/admin-hash (root only), which systemd hands to Node-RED when it starts. This writes the hash of a new password (read from standard input) and restarts Node-RED:

 printf '%s' '<new-password>' | sudo bash -c 'umask 077; /opt/nodejs/bin/node -e "let p=\"\";process.stdin.on(\"data\",c=>p+=c).on(\"end\",()=>console.log(require(\"/opt/node-red/node_modules/bcryptjs\").hashSync(p,12)))" > /etc/node-red/credentials/admin-hash'
sudo systemctl restart node-red

For the api login, write the hash to /etc/node-red/credentials/api-hash the same way (Node-RED checks it as well as nginx). Update /var/lib/cloudimg/node-red-credentials.txt too, so it does not hold old passwords.

Node-RED limits sign in attempts: after more than five attempts for one user name within ten minutes it refuses that user name, the right password included, until the ten minutes have passed or Node-RED is restarted (sudo systemctl restart node-red).

Step 12: Optional features (off by default)

Node-RED's settings are in /etc/node-red/settings.js (edit as root, then sudo systemctl restart node-red); the configuration reference lists every setting. Secrets are not in that file.

  • Palette manager. Installing extra nodes from the Node-RED library is npm downloading and running packages from the internet as the node-red user, so it is off. To switch it on, set allowInstall: true (and allowUpload: true to install from a file) in the palette: line under externalModules, and remove "*" from its denyList, then restart Node-RED. Nodes are installed into /var/lib/node-red/data/node_modules with the npm that Node-RED bundles. The image has no C compiler, so nodes that compile native code at install time fail unless you install one (sudo apt-get install -y build-essential).
  • npm modules in function nodes. functionExternalModules: false and the modules: line under externalModules keep function nodes from installing npm modules; change both to allow it.
  • Telemetry and the update check are off (telemetry: { enabled: false, updateNotification: false }).
  • Public HTTP endpoints. sudo node-red-api-auth off (Step 7).
  • Projects (git backed flows) are off; turning them on needs git and outbound access to your git server.

The metadata service stays blocked whatever you switch on.

Step 13: Check the security posture from the command line

Without the HTTP login every editor page and API call is refused, including Node-RED's sign in endpoint and the editor's WebSocket; port 80 redirects to HTTPS; the health check stays open for load balancers; and a request for a host name the instance does not serve is dropped without an answer:

H=$(sudo grep '^NODE_RED_URL=' /var/lib/cloudimg/node-red-credentials.txt | sed -E 's#^NODE_RED_URL=https://([^/]+)/.*#\1#')
R="--resolve $H:443:127.0.0.1 --resolve $H:80:127.0.0.1"
curl -s -o /dev/null -w 'http://  -> %{http_code} %{redirect_url}\n' $R "http://$H/"
curl -sk -o /dev/null -w 'editor, no login -> HTTP %{http_code}\n' $R "https://$H/"
curl -sk -o /dev/null -w 'sign in endpoint, no login -> HTTP %{http_code}\n' $R -X POST "https://$H/auth/token"
curl -sk -o /dev/null -w 'flows API, no login -> HTTP %{http_code}\n' $R "https://$H/flows"
curl -sk --http1.1 -o /dev/null -w 'editor WebSocket, no login -> HTTP %{http_code}\n' $R -H 'Connection: Upgrade' -H 'Upgrade: websocket' -H 'Sec-WebSocket-Version: 13' -H 'Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==' "https://$H/comms"
curl -sk -w '\n' $R "https://$H/health"
curl -sk -o /dev/null -w 'unknown host -> %{http_code}\n' --resolve "evil.example:443:127.0.0.1" "https://evil.example/" || true
http://  -> 301 https://ec2-<public-ip-dashed>.compute-1.amazonaws.com/
editor, no login -> HTTP 401
sign in endpoint, no login -> HTTP 401
flows API, no login -> HTTP 401
editor WebSocket, no login -> HTTP 401
{"type":"credentials","prompts":[{"id":"username","type":"text","label":"user.username"},{"id":"password","type":"password","label":"user.password"}]}
unknown host -> 000

000 means nginx closed the connection without answering, which is how it treats any host name it does not serve.

With the HTTP login the editor page loads, but Node-RED's API still wants Node-RED's own sign in, and requests that arrive from another web site are refused: a flow deploy whose browser Origin is another site, or a WebSocket handshake from another site, gets HTTP 403:

sudo bash -c '
  F=/var/lib/cloudimg/node-red-credentials.txt
  H=$(grep "^NODE_RED_URL=" $F | sed -E "s#^NODE_RED_URL=https://([^/]+)/.*#\1#")
  printf "user = \"admin:%s\"\n" "$(grep "^HTTP_PASSWORD=" $F | cut -d= -f2-)" > /run/nr-gate.cfg; chmod 600 /run/nr-gate.cfg
  c() { curl -K /run/nr-gate.cfg -sk --resolve "$H:443:127.0.0.1" -o /dev/null "$@"; }
  c -w "editor page with the HTTP login -> HTTP %{http_code}\n" "https://$H/"
  c -w "flows API with the HTTP login only -> HTTP %{http_code}\n" "https://$H/flows"
  c -w "flow deploy from another site -> HTTP %{http_code}\n" -X POST -H "Origin: https://evil.example" -H "Content-Type: application/json" --data "[]" "https://$H/flows"
  c --http1.1 -m 3 -w "editor WebSocket, other origin -> HTTP %{http_code}\n" -H "Origin: https://evil.example" -H "Connection: Upgrade" -H "Upgrade: websocket" -H "Sec-WebSocket-Version: 13" -H "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==" "https://$H/comms"
  c --http1.1 -m 3 -w "editor WebSocket, same origin -> HTTP %{http_code}\n" -H "Origin: https://$H" -H "Connection: Upgrade" -H "Upgrade: websocket" -H "Sec-WebSocket-Version: 13" -H "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==" "https://$H/comms" || true
  rm -f /run/nr-gate.cfg
'
editor page with the HTTP login -> HTTP 200
flows API with the HTTP login only -> HTTP 401
flow deploy from another site -> HTTP 403
editor WebSocket, other origin -> HTTP 403
editor WebSocket, same origin -> HTTP 101

Node-RED answers on 127.0.0.1 only, and the certificate was generated on this instance as a server certificate that cannot sign other certificates:

PRIV=$(hostname -I | awk '{print $1}')
timeout 3 bash -c "exec 3<>/dev/tcp/$PRIV/1880" 2>/dev/null && echo "1880 open on $PRIV" || echo "1880 closed on $PRIV"
openssl x509 -in /etc/ssl/node-red/node-red.crt -noout -subject -ext basicConstraints,keyUsage,extendedKeyUsage,subjectAltName
1880 closed on <private-ip>
subject=CN = ec2-<public-ip-dashed>.compute-1.amazonaws.com, O = cloudimg
X509v3 Subject Alternative Name: 
    DNS:ec2-<public-ip-dashed>.compute-1.amazonaws.com, IP Address:<public-ip>, IP Address:<private-ip>, IP Address:127.0.0.1, DNS:localhost
X509v3 Basic Constraints: critical
    CA:FALSE
X509v3 Key Usage: critical
    Digital Signature, Key Encipherment
X509v3 Extended Key Usage: 
    TLS Web Server Authentication

Step 14: Server components

Component Path
Node-RED 5.0.9 /opt/node-red (installed from /opt/node-red/package-lock.json)
Node.js 24.22.1 /opt/nodejs/bin/node (node on the PATH; no npm or npx)
Settings /etc/node-red/settings.js
Per instance secrets /etc/node-red/credentials/ (root only: Node-RED admin and api password hashes, flow credential key)
Flows and data /var/lib/node-red (data volume)
Node-RED service node-red.service (user node-red; 127.0.0.1:1880)
Build record, licences, dependency lock, audit report, checksums /usr/share/doc/cloudimg-node-red/
nginx site /etc/nginx/sites-available/cloudimg-node-red
HTTP login files /etc/nginx/.node-red-htpasswd, /etc/nginx/.node-red-api-htpasswd (bcrypt)
Certificate and key /etc/ssl/node-red/
First boot script /usr/local/sbin/node-red-firstboot.sh
Host name helper /usr/local/sbin/node-red-set-hostname
/api/ login switch /usr/local/sbin/node-red-api-auth
Self test /usr/local/sbin/node-red-selftest
Credentials /var/lib/cloudimg/node-red-credentials.txt (mode 0600)
/opt/nodejs/bin/node -p "require('/opt/node-red/node_modules/node-red/package.json').version"
node --version
command -v gcc npm npx || echo "no C compiler, no npm on the PATH"
nginx -v 2>&1
sed -n '/^npm audit gate/p;/^outbound/p' /usr/share/doc/cloudimg-node-red/BUILD-INFO.txt
5.0.9
v24.22.1
no C compiler, no npm on the PATH
nginx version: nginx/1.24.0 (Ubuntu)
npm audit gate    OK reviewed-only: ip-address:moderate undici:high
outbound          telemetry + update check OFF, diagnostics OFF, palette manager OFF, metadata egress blocked

Step 15: Security notes and recommendations

  • Allow ports 22, 80 and 443 in the security group from your own networks only.
  • Anyone with the HTTP and Node-RED passwords can run code on the instance as node-red, read and change every flow and use every credential stored in your flows. Share them only with people you would give SSH access, and rotate them (Step 11) if they may have leaked.
  • Known advisories that do not apply to this image, rechecked at each Node-RED release:
  • The editor bundles DOMPurify 3.4.14 (vendor/vendor.js), 3.4.12 (inside mermaid 11.17.2) and 3.4.15 (inside the Monaco code editor). Those versions have published advisories that only apply when the calling code switches on DOMPurify's SAFE_FOR_TEMPLATES option with a DOM output mode, its IN_PLACE option or the application/xhtml+xml parser mode. Nothing in the editor sets any of them; cloudimg's build fails if a shipped editor file ever starts to.
  • The npm package that Node-RED uses for its palette manager bundles undici 6.29.0 and ip-address 10.7.2, which have published advisories and no npm release with fixed copies yet. npm only runs when the palette manager or function node modules install something, and both are off on this image (Step 12); the build checks that Node-RED refuses those installs. If you switch the palette manager on, npm runs and downloads over HTTPS from the npm registry.
  • Flows can make HTTP requests to any address the instance can reach, including your VPC, by design; the metadata service is the exception. Treat anyone who can deploy flows as able to reach your network from the instance.
  • Use your own DNS name and a certificate your clients trust (Step 10).
  • Keep the operating system patched; unattended security upgrades are on, and sudo apt-get update && sudo apt-get upgrade applies everything else. Node.js and Node-RED are updated by new versions of this AMI.

Support and licensing

Node-RED is open source under the Apache License 2.0 (OpenJS Foundation); the licence text is in /usr/share/doc/cloudimg-node-red/. Node.js is MIT licensed. There is no per user or per CPU licence fee. The AMI price covers cloudimg's build, hardening, first boot setup and support.

  • Email: support@cloudimg.co.uk
  • Website: https://www.cloudimg.co.uk
  • Support: 24/7, with a 24 hour response SLA