node-red-dashboard icon indicating copy to clipboard operation
node-red-dashboard copied to clipboard

Dashboard 2.0 behind reverse proxy (nginx)

Open WoMec opened this issue 10 months ago • 10 comments

Hi,

I am trying to set up a reverse proxy with Nginx for the new Node-RED Dashboard 2.0. Previously, with Dashboard 1.0, I was able to access the dashboard easily by configuring Nginx to route requests based on the device's IP address or FQDN.

I would like to achieve the same setup for Dashboard 2.0, but I am facing issues with WebSocket connections. It seems that my Nginx configuration is not handling WebSockets correctly, and the dashboard does not work as expected.

Could you provide guidance on the correct Nginx configuration to ensure WebSocket support for Dashboard 2.0?

Thanks!

WoMec avatar Feb 05 '25 22:02 WoMec

@WoMec I don't use Nginx myself, but "perhaps" you can find something useful here

bartbutenaers avatar Feb 05 '25 23:02 bartbutenaers

Hello @WoMec I have this (I have just migrated to 2.0 this week) in my nginx.conf file (using docker-compose) and I have it working (in future I want to leave location at '/'). (see at bottom)

But THIRD PARTY NODES are NOT working. I get this errores in browser console

https://domain.net/resources/@flowfuse/node-red-dashboard-2-ui-led/ui-led.umd.js net
ERR_ABORTED 404 (Not Found)

@bartbutenaers do uou know if this is a "problem" of all third party nodes or a general "problem" of Dashboard 2.0?

server {
    listen 80;
    listen [::]:80;
    server_name domain.net;

    server_tokens off; #Disable the Nginx version in headers for security

    location /.well-known/acme-challenge/ {
        allow all;
        root /var/www/certbot;
    }

    location / {
        return 301 https://$server_name$request_uri;
    }

    #Logs for Nginx access and errors
    access_log /var/log/nginx/access.log;
    error_log /var/log/nginx/error.log;

    location ~ /\.ht { deny all; }

    location = /favicon.ico { log_not_found off; access_log off; }
    location = /robots.txt { log_not_found off; access_log off; allow all; }
}

server {
    listen 443 ssl;
    listen [::]:443 ssl;
    http2 on; # Activa HTTP/2 de forma explícita
    server_name domain.net;

    server_tokens off; #Disable the Nginx version in headers for security

    ssl_certificate /etc/letsencrypt/live/domain.net/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/domain.net/privkey.pem;

    ssl_session_timeout 1d;
    ssl_session_cache shared:MozSSL:10m; # about 40000 sessions
    ssl_session_tickets off;

    add_header X-Frame-Options "SAMEORIGIN" always;
    add_header X-XSS-Protection "1; mode=block" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header Referrer-Policy "no-referrer-when-downgrade" always;

    # Node-RED
    location /nr/ {
        proxy_pass http://nodered:1880/;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        # WebSocket support
        proxy_http_version 1.1;
        proxy_cache_bypass  $http_upgrade;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }

    #new nodered dashboard 2.0
    location /dash/ {
        proxy_pass http://nodered:1880/dashboard/;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header Referer "";
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_cache_bypass $http_upgrade;
     }

   #old nodered ui
    location / {
        proxy_pass http://nodered:1880/ui/;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }

    # Grafana Dashboard
    location /graf/ {
        proxy_pass http://grafana:3000/;
            proxy_set_header Host $http_host;
            proxy_set_header X-Real-IP $remote_addr;
    }

    # Logs for Nginx access and errors
    access_log /var/log/nginx/access.log;
    error_log /var/log/nginx/error.log;

    location ~ /\.ht { deny all; }

    location = /favicon.ico { log_not_found off; access_log off; }
    location = /robots.txt { log_not_found off; access_log off; allow all; }
}

ortegafernando avatar Feb 06 '25 16:02 ortegafernando

This may be the same problem https://github.com/FlowFuse/node-red-dashboard/issues/1024

colinl avatar Feb 06 '25 17:02 colinl

In my humble opinion, I think nowadays working with docker and nignx is a must. What do you think? Does it have a easy solution?

ortegafernando avatar Feb 06 '25 21:02 ortegafernando

@ortegafernando how are you installing your third-party nodes? Via the palette manager? or as global installs?

joepavitt avatar Feb 07 '25 13:02 joepavitt

@ortegafernando how are you installing your third-party nodes? Via the palette manager? or as global installs?

@joepavitt By pallete manager. If you need any log or something from me, please ask me

ortegafernando avatar Feb 07 '25 14:02 ortegafernando

@ortegafernando if you have a look at #1615 I think I have found the problem. If you setup httpAdminRoot to 'nr' and then proxy /nr to http://nodered:1880/nr/ then I think that may provide a workaround. That is if I understand the nginx config correctly.

colinl avatar Feb 11 '25 20:02 colinl

@WoMec is your problem solved with the help of @WoMec's sample configuration?

colinl avatar Feb 12 '25 09:02 colinl

@ortegafernando if you have a look at #1615 I think I have found the problem. If you setup httpAdminRoot to 'nr' and then proxy /nr to http://nodered:1880/nr/ then I think that may provide a workaround. That is if I understand the nginx config correctly.

Hi @colinl, this is what I have now in docker-compose.yml file:

  nodered:
    image: nodered/node-red:4.0
    container_name: nodered
    environment: #complete path will be ROOT/NODE_ROOT or ROOT/ADMIN_ROOT. Admin is where I edit, and Node is where they are exposed
#      - NODE_RED_HTTP_ADMIN_ROOT=/
#      - NODE_RED_HTTP_NODE_ROOT=/api
      - NODE_RED_HTTP_ROOT=/nr
    volumes:
      - ./nodered-data:/data
    restart: unless-stopped

And this is what browser console says when I access to dashboard 2.0 (everything works fine but third party nodes):

setup object:
{
    "RED": {
        "httpAdminRoot": "/",
        "httpNodeRoot": "/"
    },
    "socketio": {
        "path": "/dash/socket.io"
    },
    "basePath": "/dash"
}

Some page's information:
{
    "path": "/dash/router",
    "name": "Page:Router"
}

And errors:
https://mydomain.com/resources/@cgjgh/node-red-dashboard-2-ui-scheduler/ui-scheduler.umd.js
https://mydomain.com/dashboard/favicon.ico
https://mydomain.com/dashboard/favicon.svg

I have not changed anthing in settings.js so I supposed that httpAdminRoot is to default one ''. I am not an expert, but nginx will convert all '\nr' urls to 'http://nodered:1880/' so "in front of the eyes of nodered" httpAdminRoot is '', nothing related with '\nr'

In nginx.conf I have:

    # Node-RED
    location /nr/ {
        proxy_pass http://nodered:1880/;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        # WebSocket support
        proxy_http_version 1.1;
        proxy_cache_bypass  $http_upgrade;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }
    #new nodered dashboard 2.0
    location /dash/ {
        proxy_pass http://nodered:1880/dashboard/;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header Referer "";
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_cache_bypass $http_upgrade;
     }
   #old nodered ui
    location / {
        proxy_pass http://nodered:1880/ui/;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }

I have changed these last line in nginx.conf to:

   #old nodered ui -> NO. Change to make work dash2.0
    location / {
        proxy_pass http://nodered:1880/;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }

And now I can see third party nodes. But also I can acccess to admin (where we edit nodes) in both cases (of course I could delete the /nr/ entry in my nginx.conf file):

https://mydomain.com/
https://mydomain.com/nr

What I want finally want to have is this type of proxy:

admin (where I edit nodes): /nr
dashboard 2.0: /
old dashboard: /ui or forget it.

I make these changes:

   # Node-RED
    location /nr/ {
        proxy_pass http://nodered:1880/;
        ...
    }
    #new nodered dashboard 2.0
    location / {
        proxy_pass http://nodered:1880/dashboard/;
        ....
     }
   #old nodered ui
    location /ui/ {
        proxy_pass http://nodered:1880/ui/;
        ....
    }

/: I can not see anthing in mydomain.com, some errors about https://mydomain.com/sw.js /nr/: works perfectly /ui/: works perfectly

May be because dashboard 2.0 must be in a subpath of main nodered admin page?

I think that there are two problems:

  1. Dashboard 2.0 could be able to be in a different url path from nodered admin, not only in a subpath. I don't know if this is easy to solve by Flowfuse.
  2. Third party nodes need to work with relative path of the dashboard 2.0, not with a relative of root path. Does this problem Flowfuse related? or all people that develop third party nodes?

What do you think? Do you think that if FlowFuse solve the #1 all will work perfectly? thanks a lot for your help

ortegafernando avatar Feb 16 '25 08:02 ortegafernando

From your description I am convinced that the cause is that described in #1615 and that a fix for that would fix your issues. Please add a comment on that issue.

colinl avatar Feb 16 '25 09:02 colinl

I have read through this a couple times, and I am still missing something: Was there an answer on how to use a root location on the nginx reverse proxy for dashboard 2?

I would like to set up the nginx reverse proxy to have the root location location / to point to http://node-red:1880/dashboard. However, I only get a "blank page" when I do that. I can set ANY OTHER sub-path and it works fine; e.g. location /helpme (thanks to the above code from @ortegafernando !)

Am I just missing an nginx directive or is this the problem that's part of the backlog here or something else...?

My nginx.conf file:

server {
    listen 80;
    server_name _;  # This will match any hostname

    # Node-RED
    location /nr/ {
        proxy_pass http://node-red-tm:1880/;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        # WebSocket support
        proxy_http_version 1.1;
        proxy_cache_bypass  $http_upgrade;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }

    #new nodered dashboard 2.0
    location / {
        proxy_pass http://node-red-tm:1880/dashboard/;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header Referer "";
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_cache_bypass $http_upgrade;
     }

   #old nodered ui
    location /ui/ {
        proxy_pass http://node-red-tm:1880/ui/;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

** Additional context ** I do, when I load it as root momentarily see this Loading ... icon. But only for a millisecond:

Image

Let me know if I can share anything else about this.


Edit: Actually, with the location as root, if I explicitly type out the PATH of the Dashboard 2 PAGE, then that content will load; e.g. http://myhost/home for the home page will load the content. If I leave off the path for home; i.e. make it root, it has the same non-loading issue.

glossyio avatar Jun 10 '25 02:06 glossyio