# How to install Node-RED with Docker and a secured editor

> Run Node-RED in Docker on Ubuntu or Debian, lock the editor with a bcrypt password, publish it over HTTPS with Caddy and keep flows backed up and updated.

Difficulty: Beginner\
Tested on: Ubuntu 24.04 LTS, Ubuntu 26.04 LTS, Debian 12, Debian 13

Node-RED is a low-code programming tool for event-driven applications. You wire nodes together in a browser-based flow editor to connect devices, APIs and online services, which makes it popular for IoT, home automation, data collection and small integrations. Flows are stored as JSON and run on Node.js.

This guide runs Node-RED from the **official `nodered/node-red` Docker image**, which is the method Node-RED documents for containers. You keep all data in one folder, publish the editor only on `127.0.0.1`, protect it with a **bcrypt-hashed password**, and put **Caddy** in front of it for HTTPS. You also install extra nodes, enable the optional Git-based projects feature, and set up backups and updates. A short section explains the official Linux install script if you prefer to run Node-RED directly on the host.

## Prerequisites

- A server running **Ubuntu 24.04 LTS**, **Ubuntu 26.04 LTS**, **Debian 12** or **Debian 13** with Docker Engine and the Compose plugin. See [Install Docker on Ubuntu](/guides/install-docker-ubuntu) or [Install Docker on Debian](/guides/install-docker-debian).
- A non-root user with `sudo` rights and SSH key login, as set up in [Secure a new Linux server](/guides/secure-a-new-linux-server) and [Set up SSH keys](/guides/ssh-keys).
- A subdomain such as `nodered.example.com` whose A (and optionally AAAA) record points at the server.
- Caddy on the host, installed with [Caddy reverse proxy](/guides/caddy-reverse-proxy).

The Node-RED project does not publish minimum hardware requirements; it runs on devices as small as a Raspberry Pi. What you need depends on your flows and on the nodes you install. Treat these figures as a conservative starting point for a server that runs Node-RED next to a few other containers.

| Resource | Minimum (official) | Suggested starting point |
|---|---|---|
| CPU | Not published | 1 vCPU |
| RAM | Not published | 1 GB |
| Disk | Not published | 10 GB SSD |

## Step 1 — Create the data folder

Node-RED stores flows, credentials, settings and installed nodes in `/data` inside the container. Map that to a host folder so you can edit `settings.js` and back it up easily. The container runs as the `node-red` user with UID 1000, so the folder must belong to UID 1000:

```bash
sudo mkdir -p /opt/node-red/data
sudo chown $USER:$USER /opt/node-red
sudo chown -R 1000:1000 /opt/node-red/data
cd /opt/node-red
```

## Step 2 — Start Node-RED with Docker Compose

Create `/opt/node-red/compose.yaml`. It uses the official image, publishes port 1880 on the loopback address only and sets the timezone that inject nodes and time functions use:

```yaml
services:
  node-red:
    image: nodered/node-red:latest
    restart: unless-stopped
    environment:
      - TZ=Europe/Istanbul
    ports:
      - "127.0.0.1:1880:1880"
    volumes:
      - ./data:/data
```

Replace `Europe/Istanbul` with your own IANA timezone. The `latest` tag follows the newest release on the default Node.js version; the image also comes as `-minimal` variants without Python and build tools, Node.js-specific tags such as `latest-22`, and a Debian-based `latest-debian` image for nodes that do not build on Alpine. To pin a release, use a version tag from Docker Hub instead, for example `nodered/node-red:5.0.8`.

Start the container and look at the log:

```bash
docker compose up -d
docker compose logs node-red
```

You should see `Settings file  : /data/settings.js`, `User directory : /data` and a line saying that the server is now running on port 1880. On first start Node-RED copies a default `settings.js` into `/data`, which you edit in the next step. Check the editor from the server:

```bash
curl -I http://127.0.0.1:1880
```

The response should be `HTTP/1.1 200 OK`.

## Step 3 — Protect the editor with a password

Node-RED's documentation is explicit that the editor is **not secured by default**: anyone who can reach it can deploy flows, and flows can run commands. Turn on the `adminAuth` setting before the editor goes online.

First create a bcrypt hash of your password. The image contains the Node-RED admin tool, so you do not need Node.js on the host:

```bash
docker compose exec node-red npx node-red admin hash-pw
```

Type the password twice when prompted and copy the hash it prints. Then open `settings.js`:

```bash
sudo nano /opt/node-red/data/settings.js
```

Find the commented-out `//adminAuth` block in the Security section and replace it with the following, pasting your hash as the password value. `permissions: "*"` gives full access; a second user with `permissions: "read"` would get a read-only view:

```text
    adminAuth: {
        type: "credentials",
        users: [{
            username: "nodered-admin",
            password: "paste-the-bcrypt-hash-here",
            permissions: "*"
        }]
    },
```

Restart Node-RED and confirm that the admin API now asks for credentials:

```bash
docker compose restart node-red
curl -s http://127.0.0.1:1880/auth/login
```

The response now contains `"type":"credentials"`. If Node-RED does not start, a missing comma in `settings.js` is the usual cause; `docker compose logs node-red` shows the line. Access tokens expire after seven days by default; set `sessionExpiryTime` (in seconds) in `settings.js` to change that.

## Step 4 — Protect HTTP endpoints (optional)

Flows that use **HTTP In** nodes serve their own URLs, and these stay public even when the editor is locked. If they should not be open to everyone, set `httpNodeAuth`, which uses the same bcrypt hash format. Generate a separate hash with the command from Step 3 and add this line to `settings.js`:

```text
    httpNodeAuth: {user:"api-user", pass:"paste-the-bcrypt-hash-here"},
```

Static files served through `httpStatic` can be protected the same way with `httpStaticAuth`. Restart the container after every change to `settings.js`. For public webhooks that other services call, leave `httpNodeAuth` off and validate a secret header or token inside the flow instead.

## Step 5 — Publish Node-RED over HTTPS with Caddy

Add a site block to `/etc/caddy/Caddyfile`. Caddy proxies the WebSocket connection that the editor uses for live updates without extra settings:

```caddyfile
nodered.example.com {
    reverse_proxy 127.0.0.1:1880
}
```

Reload Caddy, allow only SSH and web traffic in the firewall, and test the result:

```bash
sudo systemctl reload caddy
sudo ufw allow OpenSSH
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable
curl -I https://nodered.example.com
```

You should get `HTTP/2 200` with a valid certificate. Open the address in a browser and log in with the user from Step 3. Port 1880 stays closed to the internet because the container only listens on `127.0.0.1`. If you use Nginx instead, the proxy must forward the `Upgrade` and `Connection` headers for WebSockets; see [Nginx with Certbot](/guides/nginx-reverse-proxy-certbot).

## Step 6 — Install additional nodes

The easiest way is the **Palette Manager**: open the main menu, choose **Manage palette**, switch to the **Install** tab and search for a module. The flow library at `flows.nodered.org` lists the available nodes. Packages are installed into `/data`, so they survive container updates.

From the command line, run `npm install` inside the container in `/data` and restart Node-RED so the new nodes load:

```bash
cd /opt/node-red
docker compose exec node-red bash -c "cd /data && npm install node-red-node-email"
docker compose restart node-red
```

The `-minimal` image variants have no Python or build tools and cannot install nodes that compile native code. Use the default or `-debian` image if you need such nodes.

## Step 7 — Enable projects with Git (optional)

The projects feature turns your flows into a Git repository: you commit changes from the editor's History tab and push them to a remote such as a self-hosted Gitea. The official image already contains `git` and `ssh-keygen`, which the feature needs. Enable it with an environment variable:

```yaml
    environment:
      - TZ=Europe/Istanbul
      - NODE_RED_ENABLE_PROJECTS=true
```

Run `docker compose up -d` to apply the change. The editor then offers to create your first project. When it asks for a credentials encryption key, choose a strong one and store it in your password manager: the key is not saved in the repository, and anyone who clones the project needs it to decrypt the credentials.

## Alternative: install without Docker

Node-RED also maintains an official install script for Debian-based systems, including Ubuntu and Debian. It removes an existing Node-RED install, makes sure Node.js 20 or newer is present (installing Node.js 22 LTS from NodeSource if it is missing), installs the latest Node-RED with npm and sets it up as the `nodered` systemd service with helper commands such as `node-red-start`, `node-red-stop` and `node-red-log`. This route is useful when flows need direct access to hardware such as serial devices.

Download the script, read it, then run it as your normal sudo user. `--help` lists its options:

```bash
sudo apt install build-essential git curl
curl -fsSL https://github.com/node-red/linux-installers/releases/latest/download/install-update-nodered-deb -o install-nodered.sh
less install-nodered.sh
bash install-nodered.sh
sudo systemctl enable --now nodered.service
```

The official one-line equivalent pipes the same file straight into `bash`. With this method the user directory is `~/.node-red`, `node-red admin hash-pw` works directly on the host, and Node-RED listens on all interfaces by default. Set `uiHost: "127.0.0.1",` in `~/.node-red/settings.js` so that only Caddy can reach port 1880, configure `adminAuth` as in Step 3 and restart with `node-red-restart`. Run the script again to upgrade.

## Back up and restore

Everything Node-RED needs is in `/opt/node-red/data`: `flows.json`, the encrypted credentials file `flows_cred.json`, `settings.js`, `package.json` with the list of installed nodes, the nodes themselves and the key Node-RED generated to encrypt credentials. Archive the whole folder, hidden files included, together with `compose.yaml`:

```bash
sudo mkdir -p /opt/backups
sudo tar czf /opt/backups/node-red-$(date +%F).tar.gz -C /opt/node-red data compose.yaml
sudo chmod 600 /opt/backups/node-red-*.tar.gz
```

The archive can be taken while Node-RED runs. Copy it to another machine or object storage, because a backup that stays on the same server is lost with the server.

To restore, stop the container, replace the folder and fix the ownership:

> **Warning**
>
> The next commands delete the current data folder. Make sure the archive you restore from is complete and readable first, for example with `tar tzf`.

```bash
cd /opt/node-red
docker compose down
sudo rm -rf /opt/node-red/data
sudo tar xzf /opt/backups/node-red-2026-10-09.tar.gz -C /opt/node-red
sudo chown -R 1000:1000 /opt/node-red/data
docker compose up -d
```

Without the generated credential key, the flows load but every saved credential is lost. If you move flows between servers often, set your own `credentialSecret` in `settings.js` and keep it in your password manager.

## Update Node-RED

Read the release notes on the Node-RED blog before a new major version; Node-RED 5, for example, requires Node.js 22 or newer, which the Docker image already provides. Back up the data folder, then pull the new image and recreate the container:

```bash
cd /opt/node-red
docker compose pull
docker compose up -d
docker compose logs --tail=20 node-red
```

The log shows the new Node-RED and Node.js versions. If you pinned a version tag, change it in `compose.yaml` first. Installed nodes stay in `/data`; update them from **Manage palette**, where outdated modules show an update button. If a node with native code fails after a Node.js upgrade, rebuild it with `docker compose exec node-red bash -c "cd /data && npm rebuild"`.

## Troubleshooting

### Error: EACCES: permission denied on /data

The host folder does not belong to UID 1000, the user inside the container. Run `sudo chown -R 1000:1000 /opt/node-red/data` and start the container again. This often happens after restoring a backup as root or copying files in with `sudo cp`.

### The editor shows Lost connection to server

The browser cannot keep the WebSocket connection to Node-RED open. Caddy handles WebSockets automatically; with Nginx you must pass the `Upgrade` and `Connection` headers and use HTTP/1.1 for the proxy connection. Also check that nothing between the browser and the server, such as a CDN or firewall, blocks WebSockets.

### Forgot the editor password

Generate a new hash with `docker compose exec node-red npx node-red admin hash-pw`, replace the `password` value in `/opt/node-red/data/settings.js` and run `docker compose restart node-red`. Flows and credentials are not affected.

### A node fails to install from the palette

Read the error in `docker compose logs node-red`. Nodes with native components need Python and build tools, which the `-minimal` images do not contain; switch to the default or `-debian` tag. Also check that the node supports your Node-RED and Node.js versions.

### Node-RED crashes on start after deploying a flow

A faulty flow or node can stop the runtime from starting. Set `NODE_RED_ENABLE_SAFE_MODE=true` in the `environment` list and run `docker compose up -d`: Node-RED starts without running the flows, so you can fix or delete the problem in the editor. Remove the variable again afterwards.

## Next steps

- Compare Node-RED with [n8n](/guides/install-n8n) for API-centric workflow automation.
- Connect Node-RED to your smart home with [Home Assistant in Docker](/guides/home-assistant-docker).
- Find servers for your automation stack on the [Node-RED hosting](/node-red-hosting) page.
- Read the official [Node-RED documentation](https://nodered.org/docs/) for flow design, the admin API and security settings.

## Frequently asked questions

### Is the Node-RED editor password protected by default?

No. Node-RED's documentation states that the editor is not secured by default, so anyone who can reach port 1880 can change and deploy flows. Set adminAuth in settings.js before you expose the editor, and publish the port only on 127.0.0.1.

### Should I use Docker or the official install script?

Both are official. Docker keeps Node.js and Node-RED inside one image and makes updates a simple pull. The Linux install script installs Node.js and Node-RED directly on the server and creates a systemd service, which suits hardware access such as serial ports.

### How do I install extra nodes in Docker?

Use Manage palette in the editor menu, which installs packages into the /data folder. From the command line you can run npm install inside the container in /data and restart Node-RED. Nodes with native code need the default image, not the minimal variant.

### What do I need to back up for Node-RED?

Everything lives in the /data folder: flows.json, the encrypted credentials file, settings.js, package.json and the installed nodes, plus the generated credential key. Archive the whole folder, hidden files included, and keep a copy off the server.

### Does Node-RED run on a HyperDC server?

Yes. This guide works on a HyperDC Linux VPS, VDS or dedicated server with root access running Ubuntu 24.04, Ubuntu 26.04, Debian 12 or Debian 13. Node-RED itself is light, so size the server for the flows and other services you run.

---

Source: <https://hyperdc.com/guides/tutorials/install-node-red>\
Updated: 2026-10-09
