Running Node-RED in Docker gives you a reproducible install that is easy to upgrade, back up and move between machines. In this tutorial you will start the official Node-RED Docker image, keep your flows on a persistent volume, manage it with Docker Compose, add extra nodes, pass secrets safely and connect the container to an MQTT broker over TLS.
Why Run Node-RED in Docker
Installing Node-RED directly with npm works fine, and our install Node-RED guide covers that route. Containers add a few advantages that matter once a flow is doing real work:
- Pinned versions. You choose the exact Node-RED and Node.js version through the image tag, so an upgrade is a deliberate change.
- Clean separation. Everything Node-RED writes lives in one directory,
/data, which you mount as a volume. Back up that one folder and you have everything. - Easy rollback. If an upgrade breaks a contributed node, switch back to the previous tag.
- Same setup everywhere. A Compose file runs identically on a laptop, a Raspberry Pi with a 64-bit OS or a cloud VM.
The official image is nodered/node-red on Docker Hub. Tags such as latest, a specific version like 4.0.9, or variants with a particular Node.js version, let you choose how tightly to pin. In production, pin a version tag rather than latest.
Quick Start with docker run
Make sure Docker is installed, then run:
docker volume create node_red_data
docker run -d \
--name nodered \
--restart unless-stopped \
-p 1880:1880 \
-e TZ=Europe/Istanbul \
-v node_red_data:/data \
nodered/node-red:latest
Open http://localhost:1880 and you have a working editor. The important flag is -v node_red_data:/data. Without it, flows, installed nodes and credentials live inside the container's writable layer and disappear when you remove or recreate the container. TZ sets the timezone so timestamps and inject schedules match your local time.
Useful day-to-day commands:
docker logs -f nodered # follow the Node-RED log
docker exec -it nodered bash # shell inside the container
docker restart nodered # restart after editing settings.js
The --restart unless-stopped policy brings Node-RED back automatically after a crash or a host reboot, but not after you stop it deliberately. That matters for MQTT flows: when the container restarts, the broker node reconnects on its own and subscriptions are restored from the flow, so a gateway that loses power recovers without anyone touching it. Combine it with persistent storage, described next, so the flows it restarts with are the ones you deployed.
Named Volume or Bind Mount
You can mount a named volume, as above, or a host folder:
mkdir -p ~/node-red-data
sudo chown -R 1000:1000 ~/node-red-data
docker run -d --name nodered -p 1880:1880 -v ~/node-red-data:/data nodered/node-red:latest
A bind mount makes settings.js and flows.json easy to edit and back up from the host. The catch is permissions: the container runs Node-RED as a user with UID 1000. If the host folder belongs to root or another user, Node-RED cannot write and you will see EACCES errors in the log. The chown above prevents that.
| Named volume | Bind mount | |
|---|---|---|
| Setup | Nothing to prepare | Folder must be writable by UID 1000 |
| Editing settings.js | Via docker exec or a helper container |
Directly on the host |
| Backups | docker run --rm -v node_red_data:/data ... with tar |
Any file backup tool |
| Portability | Managed by Docker | Visible host path |
A Production-Ready Docker Compose File
For anything long-lived, describe the container in Compose. This file pins the image, persists data, sets the timezone and passes secrets through an environment file:
# docker-compose.yml
services:
nodered:
image: nodered/node-red:4.0.9
container_name: nodered
restart: unless-stopped
ports:
- "127.0.0.1:1880:1880"
environment:
- TZ=Europe/Istanbul
- NODE_RED_CREDENTIAL_SECRET=${NODE_RED_CREDENTIAL_SECRET}
volumes:
- ./data:/data
# .env (same folder, never commit this file)
NODE_RED_CREDENTIAL_SECRET=change-me-to-a-long-random-string
mkdir -p data && sudo chown -R 1000:1000 data
docker compose up -d
Two details are worth calling out. First, the port is published on 127.0.0.1 only, so the editor is reachable from the host but not from the network. Put a reverse proxy with HTTPS in front if you need remote access, and read how to secure Node-RED before exposing it. Second, the credential secret is read from the environment. Edit data/settings.js and set:
// data/settings.js
credentialSecret: process.env.NODE_RED_CREDENTIAL_SECRET,
This key encrypts flows_cred.json. If you leave it unset, Node-RED generates a key and stores it inside the data folder, which works but ties your credentials to that one copy. With an explicit secret you can rebuild the container anywhere and still decrypt your broker passwords.
Installing Extra Nodes in the Container
Use Manage palette in the editor as usual; nodes are installed into /data/node_modules and survive container recreation because /data is a volume. To script it instead:
docker exec -it nodered bash -c "cd /data && npm install @flowfuse/node-red-dashboard"
docker restart nodered
For fully reproducible images, build your own image that installs nodes at build time:
# Dockerfile
FROM nodered/node-red:4.0.9
RUN npm install --no-audit --no-fund @flowfuse/node-red-dashboard node-red-contrib-modbus
Nodes that compile native code may need build tools; the image documentation on nodered.org explains the available variants and how to add them.
Connect the Container to an MQTT Broker
A frequent Node-RED Docker mistake is pointing the MQTT node at localhost. Inside the container, localhost is the container itself, not your host. Use a real hostname: a cloud broker, a service name on the same Compose network, or host.docker.internal on Docker Desktop.
For a first test, use the free public MQTT broker. In the broker configuration node, set server broker.connectmq.com, port 1883 and a unique client ID such as nr-docker-4d2f. Subscribe to connectmq/demo/4d2f/# and publish from your host:
mosquitto_pub -h broker.connectmq.com -p 1883 -i demo-host-4d2f \
-t "connectmq/demo/4d2f/docker/test" -m '{"hello":"from host"}'
For production, switch to your private broker with TLS. Set server to your ConnectMQ broker host, port 8883, tick Use TLS, and fill in the username, password and client ID from the portal. Because the image includes standard CA certificates, the Let's Encrypt certificate is trusted without extra configuration. The full TLS walkthrough is in Node-RED MQTT TLS.
You only type those credentials once in the editor. Node-RED stores them in flows_cred.json, encrypted with the credential secret you set above, never in plain text inside flows.json, so you can share or commit the flow file without leaking your broker password.
Upgrades and Backups Checklist
- Back up the data folder or volume before every upgrade.
- Change the image tag in
docker-compose.yml, then rundocker compose pull && docker compose up -d. - Watch
docker logs -f noderedfor nodes that fail to load after the upgrade. - Roll back by restoring the previous tag if needed; the data folder is unchanged.
- Rebuild nodes with native code after a Node.js major version change (
npm rebuildinside/data). - Keep
.envout of version control and store it in your secrets manager. - Test restores occasionally; a backup you have never restored is a guess.
If the MQTT node shows "connecting" after any of these steps, the Node-RED MQTT not connecting guide walks through DNS, ports, TLS and client ID problems that are common in containers.
Run Your Dockerised Node-RED with ConnectMQ
Containers handle Node-RED; a hosted MQTT broker handles the messaging layer so you do not have to run and patch a broker container as well. ConnectMQ offers TCP 1883, TLS 8883 and secure WebSocket 8084, MQTT 3.1.1 and 5.0, and a portal with a live topic explorer for checking what your container publishes. Sign up at app.connectmq.com for the free Serverless plan, no credit card required, and paste the generated credentials into the broker node. For a wider view of hosting options, see our cloud MQTT broker guide, and the Node-RED MQTT tutorial for building your first flows.
Frequently Asked Questions
Where does Node-RED store data in Docker?
Everything, including flows, credentials, settings.js, context and installed nodes, lives in /data inside the container. Mount it as a volume or bind mount so it survives container recreation.
Why can't my Node-RED container connect to an MQTT broker on localhost?
Inside a container, localhost refers to the container itself. Use the broker's real hostname, a Compose service name or host.docker.internal on Docker Desktop.
How do I fix permission denied errors with a bind mount?
The container runs Node-RED as UID 1000. Change ownership of the host folder with sudo chown -R 1000:1000 <folder> and restart the container.
Can I run Node-RED in Docker on a Raspberry Pi?
Yes. The official image is published for ARM architectures, so the same commands and Compose file work on a Raspberry Pi running a supported OS.



