Nodered, Home Assistant and Tailscale

I’m moving my Home Assistant from a docker container to a proxmox VM running HAOS, and as part of that I’m moving Node-RED to its own container so I can move it to other proxmox hosts independently of HAOS.

I’m setting up a new Node-RED instance as part of moving Home Assistant out of docker and onto an HAOS VM. My requirements were:

  1. Run Node-RED in a separate VM so I can move it to other proxmox hosts if there is resource contention or I need to fail over
  2. Proper SSL certificate
  3. Easy access via my tailnet

Pre-requisites

To follow these instructions, you will need:

  1. Your own Tailnet. You can get a free tailnet at Tailscale.com.
  2. A server with docker installed that you can run docker compose on. I’m using a LXC container in my proxmox cluster, but you can run it on a standalone linux server.
  3. A working Home Assistant server.

Installation

Installing docker and Home Assistant are out of scope for this post. We will only be covering how to get Node-RED working with an existing Home Assistant server.

Get a Tailscale Auth key

  1. Log into the Tailscale admin page.
  2. Click the Settings tab. On the bottom left, you’ll see a Personal Settings, and under that, Keys.
  3. Click Generate Auth Key.
  4. Give it a description, and then click Generate Key
  5. Copy the key to someplace secure, it won’t be displayed again

Create a configuration file for tailscale serve

By default, node-red runs on port 1880. Because we’re running tailscale and node-red in the same docker network, the tailscale container will be able to connect to port 1880 on the node-red container and act as a proxy.

Save this as ts-config/nodered.json.

{
  "TCP": {
    "443": {
      "HTTPS": true
    }
  },
  "Web": {
    "${TS_CERT_DOMAIN}:443": {
      "Handlers": {
        "/": {
          "Proxy": "http://127.0.0.1:1880"
        }
      }
    }
  },
  "AllowFunnel": {
    "${TS_CERT_DOMAIN}:443": false
  }
}

Docker Compose

Now that we have an auth token and a configuration file for tailscale, we’re going to use docker compose to start up node-red and a ts-nodered containers. The ts-nodered sidecar will connect to tailscale, register itself as nodered.your-tailnet.ts.net, use Lets Encrypt to create a SSL certificate that is trusted by your browser, then finally start proxying SSL traffic from nodered.your-tailnet.ts.net into the node-red container.

This docker-compose file is based on the Node-RED Getting Started with Docker page. I added a ts-nodered container to act as a tailscale sidecar and made some other minor changes. I prefer to mount a local directory instead of using a docker volume to make backups easier. I can copy the directory into a .tar.bz2 or .zip file, and it’s also easier to edit the configuration files since I can do that from the host OS.

Save this as docker-compose.yaml

################################################################################
# Node-RED Stack or Compose
################################################################################
version: "3.7"

services:
  ts-nodered:
    image: tailscale/tailscale:latest
    # The hostname specified here will be registered in your tailnet. You will
    # be able to access Node-RED by entering nodered.your-tailnet.ts.net into
    # your browser
    hostname: nodered
    environment:
      # Set TS_AUTHKEY in the environment, you don't want it saved in
      # cleartext here
      - TS_AUTHKEY=${TS_AUTHKEY}
      - TS_STATE_DIR=/var/lib/tailscale
      - TS_SERVE_CONFIG=/config/nodered.json
      - TS_USERSPACE=true
    volumes:
      - ./ts-config:/config
      - ./ts-state:/var/lib/tailscale
    restart: unless-stopped

  nodered:
    container_name: node-red
    image: nodered/node-red:latest-debian
    # If you don't set the network_mode to the name of the tailscale sidecar
    # container, tailscale won't be able to connect to Node-RED and you will
    # have 500 errors
    network_mode: service:ts-nodered
    restart: unless-stopped
    environment:
      - TZ=America/Denver
# We specify the port in nodered.json so tailscale serve knows what port to
# proxy to. We don't actually activate external access to these ports since
# everything gets proxied by Tailscale.
#
#   ports:
#     - "1880:1880"
    volumes:
      - ./nodered:/data
      - ./externals:/externals
      - /etc/hostname:/etc/hostname:ro
      - /etc/localtime:/etc/localtime:ro
      - /etc/machine-id:/etc/machine-id:ro
      - /etc/timezone:/etc/timezone:ro

Start Node-RED

Prepare Your Node-RED Directory

First, prepare your directory. You need to make a few subdirectories and move tailscale’s configuration file into the ts-config subdirectory.

mkdir ts-config && mkdir ts-state

Move the nodered.json file into the ts-config directory. Your directory structure should look like this:

./docker-compose.yaml
./ts-config/nodered.json
./ts-state

Start the Node-RED containers

We’re going to pass the Tailscale auth token as an environment variable so we don’t have it visible in the configuration file. Run docker compose using the command below

export TS_AUTHKEY='yourReallyLongTailscaleAuthKey'
docker compose up -d ; docker compose logs -f

In a minute or two depending on your network connection, you’ll see a bunch of logs start scrolling. Eventually you should see a line like:

ts-nodered-1  | 2025/07/14 00:54:52 serve: creating a new proxy handler for http://127.0.0.1:1880

to show that the ts-nodered proxy is up and running, and another line similar to

node-red      | 13 Jul 18:54:52 - [info] Server now running at http://127.0.0.1:1880/

when the node-red container is ready. The containers start in parallel, so the order of those lines isn’t guaranteed. Once you’ve seen both lines, you can go to nodered.your-tailnet.ts.net in your browser and access the Node-RED web interface. The first time you do this, it’ll take a little longer while tailscale generates a SSL certificate for the host with Lets Encrypt.

There’s one last thing to do before we can consider this operational.

Make Node-RED require a login

Create your password hash

  1. Run docker exec -it node-red bash to get a shell inside the running node-red container
  2. Run node-red admin hash-pw. It will ask you for a password that will be used to log into your node-red, then print out a hash. Save that so we can update the node-red container’s configuration.

Update settings.js

Use your editor of choice to edit ./nodered/settings.js. You will find a commented out block that looks like

    //adminAuth: {
    //    type: "credentials",
    //    users: [{
    //        username: "admin",
    //        password: "$2a$08$zZWtXTja0fB1pzD4sHCMyOCMYz2Z6dNbM6tl8sJogENOMcxWV9DN.",
    //        permissions: "*"
    //    }]
    //},

Replace that with:

    adminAuth: {
        type: "credentials",
        users: [{
            username: "admin",
            password: "TheHashFromRunning_nNodered_admin_hash-pw",
            permissions: "*"
        }]
    },

Now we restart Node Red so it picks up the new admin user you created.

docker compose restart

Give it 15-30 seconds, then refresh your browser. It should now give you a login dialog and make you login as admin with the password you input to the node-red admin hash-pw command.

Connecting Node-RED to Home Assistant

Now that you have a running Node-RED instance, you need to connect it to your Home Assistant server.

Create an access token

To connect Node-RED to your Home Assistant (HA), we’re going to need an access token. To create an access token:

  1. Log into your HA instance
  2. Click on your username at the bottom of the sidebar
  3. Select the Security tab
  4. Scoll down to the Long Lived Access Tokens Section and click Ceate Troken.
  5. Name the new token. Store it someplace safe, it will only be displayed once.

Configure the connection between Node-RED and Home Assistant

  1. Log into your Node-RED instance
  2. Click the burger menu on the right side of the screen, and select Manage Palette
  3. Select the Palette tab from the dialog’s left side, then Install on the top
  4. Install the HA plugin. Make sure you pick the one named node-red-contrib-home-assistant-websocket. You do not want the one named node-red-contrib-home-assistant, it is old and abandoned. You will now see a bunch more HA-related nodes in the left sidebar.
  5. Scroll down, find the API node, and drag it onto the Flow palette.
  6. Double-click the new node. An Edit API node dialog will appear, click add new server. Keep the protocol as Websocket. Do not check the Using the Home Assistant Add-on, we’re running Node-RED outside the HAOS instance. Put in the DNS name or IP address of your Home Assistant server.
  7. Hit Done to save. It’ll switch to the properties tab, just click Done again.
  8. You’ll now see a Deploy button at the upper right of the screen. Click that so NR can activate the connection to your HA instance

You should be good to start writing Node-RED automations for your Home Assistant, but let’s verify that it’s working.

Verifying your Node-RED connection

  1. Drag a Current State node onto your flow palette.
  2. Double-click it to edit it
  3. You should see your Home Assitant connection is already selected in the Server entry
  4. Start typing an entity name in the Entity ID field. If things are working correctly, it will start auto-completing the name for you.

If it autocompleted, you’re good to go. Creating automations in NR is out of scope for this post, but there are a ton of videos on YouTube to show you how.

Congratulations, you now have Node-RED running independently from Home Assistant.