# NodeRED websockets and Nginx reverse proxy (subfolder)

**URL:** <https://discourse.nodered.org/t/nodered-websockets-and-nginx-reverse-proxy-subfolder/63998>\
**Category:** General\
**Tags:** nginx\
**Created:** [16 June 2022 07:00 UTC](https://discourse.nodered.org/t/nodered-websockets-and-nginx-reverse-proxy-subfolder/63998 "2022-06-16T07:00:04Z")\
**Posts on this page:** 11\
**Page:** 1

<div class="post-metadata">

**Author:** ![TheToto318](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/thetoto318/32/63255_2.png) [@TheToto318](https://discourse.nodered.org/u/TheToto318)\
**Post date:** [16 June 2022 07:00 UTC](https://discourse.nodered.org/t/nodered-websockets-and-nginx-reverse-proxy-subfolder/63998/1 "2022-06-16T07:00:04Z")

</div>

Hello everyone,

I'm writting this post because I'm trying to access nodeRED behind my Nginx reverse proxy, unfortunately I can't get the websockets to work. NodeRED load correctly but I get an error 502 and the below line appear when I debug the reverse proxy.

> upstream prematurely closed connection while reading response header from upstream

This is my NGINX config :

```auto
location ^~ /nodered/ {
        resolver 127.0.0.11 valid=30s;
        set $upstream_app 192.168.1.119;
        set $upstream_port 1880;
        set $upstream_proto http;
        proxy_pass $upstream_proto://$upstream_app:$upstream_port;
        error_log /config/log/nginx/nodered_error.log debug;

        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_http_version 1.1;
        proxy_cache_bypass $http_upgrade;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $proxy_protocol_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Forwarded-Host $host;
        proxy_set_header X-Forwarded-Port $server_port;
        proxy_read_timeout 300s;
        proxy_connect_timeout 75s;

        rewrite ^/nodered/(.*)$ /$1 break;
    }

    location ^~ /nodered/comms {
        resolver 127.0.0.11 valid=30s;
        set $upstream_app 192.168.1.119;
        set $upstream_port 1880;
        set $upstream_proto http;
        proxy_pass $upstream_proto://$upstream_app:$upstream_port;
        error_log /config/log/nginx/comms_error.log debug;

        
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_http_version 1.1;
        proxy_cache_bypass $http_upgrade;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $proxy_protocol_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Forwarded-Host $host;
        proxy_set_header X-Forwarded-Port $server_port;
        proxy_set_header Upgrade "websocket";
        proxy_read_timeout 300s;
        proxy_connect_timeout 75s;
    }

```

If anyone has an idea ..

Regards,  
Thomas

---

<div class="post-metadata">

**Author:** ![TotallyInformation](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/totallyinformation/32/31_2.png) [@TotallyInformation](https://discourse.nodered.org/u/TotallyInformation)\
**Post date:** [16 June 2022 08:44 UTC](https://discourse.nodered.org/t/nodered-websockets-and-nginx-reverse-proxy-subfolder/63998/2 "2022-06-16T08:44:19Z")

</div>

Mine looks a little different but then my config is different.

I use separate include files. I include a `common_proxy_headers.conf` for all paths and a `common_ws_proxy_headers.conf` file for Node-RED paths.

`common_proxy_headers.conf`

```auto
# Common reverse proxy settings
# Don't forget to also add proxy_pass url;

  proxy_set_header Forwarded "by=$host;for=$proxy_add_x_forwarded_for;host=$host;proto=$scheme";
  proxy_set_header Via "$scheme/1.1 $host:$server_port";

  proxy_set_header X-Real-IP $remote_addr;
  proxy_set_header Host $host;
  proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  proxy_set_header X-Forwarded-Proto $scheme;
  proxy_set_header X-Real-IP $remote_addr;
  proxy_set_header X-Forwarded-Port $server_port;
  proxy_set_header X-Forwarded-Host $host;

  # Proxy timeouts
  proxy_connect_timeout 60s;
  proxy_send_timeout 60s;
  proxy_read_timeout 60s;

  # If proxied responses happening too slowly, try turning off the buffering
  #proxy_buffering off;

```

`common_ws_proxy_headers.conf`

```auto
# Common headers for proxy of websockets

proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";

```

---

<div class="post-metadata">

**Author:** ![TheToto318](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/thetoto318/32/63255_2.png) [@TheToto318](https://discourse.nodered.org/u/TheToto318)\
**Post date:** [16 June 2022 09:07 UTC](https://discourse.nodered.org/t/nodered-websockets-and-nginx-reverse-proxy-subfolder/63998/3 "2022-06-16T09:07:08Z")

</div>

I'm using the same parameters as you, it's weird Nginx should be able to forward the websocket requests

---

<div class="post-metadata">

**Author:** ![TotallyInformation](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/totallyinformation/32/31_2.png) [@TotallyInformation](https://discourse.nodered.org/u/TotallyInformation)\
**Post date:** [16 June 2022 09:14 UTC](https://discourse.nodered.org/t/nodered-websockets-and-nginx-reverse-proxy-subfolder/63998/4 "2022-06-16T09:14:30Z")

</div>

Do you have Node-RED set to trust the proxy?

---

<div class="post-metadata">

**Author:** ![TheToto318](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/thetoto318/32/63255_2.png) [@TheToto318](https://discourse.nodered.org/u/TheToto318)\
**Post date:** [16 June 2022 09:15 UTC](https://discourse.nodered.org/t/nodered-websockets-and-nginx-reverse-proxy-subfolder/63998/5 "2022-06-16T09:15:53Z")

</div>

Oh, didn't know that it will have to be made. How can I do that ?

Also, I had the same problem when I used no authentication for nodeRED

---

<div class="post-metadata">

**Author:** ![TotallyInformation](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/totallyinformation/32/31_2.png) [@TotallyInformation](https://discourse.nodered.org/u/TotallyInformation)\
**Post date:** [16 June 2022 11:15 UTC](https://discourse.nodered.org/t/nodered-websockets-and-nginx-reverse-proxy-subfolder/63998/6 "2022-06-16T11:15:13Z")

</div>

It is in settings.js - there are several things you can change:

```auto
    /** By default, the Node-RED UI accepts connections on all IPv4 interfaces.
     * To listen on all IPv6 addresses, set uiHost to "::",
     * The following property can be used to listen on a specific interface. For
     * example, the following would only allow connections from the local machine.
     * This can be useful security when putting NR behind a reverse proxy on the same device.
     */
    //uiHost: process.env.HOST || '127.0.0.1',

    /** The following property can be used to pass custom options to the Express.js
     * server used by Node-RED. For a full list of available options, refer
     * to http://expressjs.com/en/api.html#app.settings.table
     */
    httpServerOptions: {
        // http://expressjs.com/en/api.html#trust.proxy.options.table
        'trust proxy': '127.0.0.1/8, ::1/128', //true, // true/false; or subnet(s) to trust; or custom function returning true/false. default=false
        'x-powered-by': false,
    },

    // I think you can do this instead of setting the server options
    // - I prefer to set the ExpressJS server options directly
    /** If you need to set an http proxy please set an environment variable
     * called http_proxy (or HTTP_PROXY) outside of Node-RED in the operating system.
     * For example - http_proxy=http://myproxy.com:8080
     * (Setting it here will have no effect)
     * You may also specify no_proxy (or NO_PROXY) to supply a comma separated
     * list of domains to not proxy, eg - no_proxy=.acme.co,.acme.co.uk
     */

```

If you use uibuilder with its optional custom server, that also has server options and you can add the same trust proxy option to it.

---

<div class="post-metadata">

**Author:** ![TheToto318](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/thetoto318/32/63255_2.png) [@TheToto318](https://discourse.nodered.org/u/TheToto318)\
**Post date:** [16 June 2022 12:01 UTC](https://discourse.nodered.org/t/nodered-websockets-and-nginx-reverse-proxy-subfolder/63998/7 "2022-06-16T12:01:54Z")

</div>

Added the trusted proxy.  
Still not working, connection refused...  
I don't understand.

---

<div class="post-metadata">

**Author:** ![TotallyInformation](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/totallyinformation/32/31_2.png) [@TotallyInformation](https://discourse.nodered.org/u/TotallyInformation)\
**Post date:** [16 June 2022 12:13 UTC](https://discourse.nodered.org/t/nodered-websockets-and-nginx-reverse-proxy-subfolder/63998/8 "2022-06-16T12:13:42Z")

</div>

You might need to try to up the node-red logging to trace level to see if something reports why it is doing that.

Might also be worth setting up a different proxy temporarily - that's to say, a simplified location.

Here is the relevant section of my config that I didn't share before in case it helps:

```auto
# Deal with all other Node-RED user endpoints - e.g. uibuilder
# Takes over the whole root url which means you can't use it for anything else
# Better to set httpNodeRoot to something (e.g. 'nr') and then just proxy that (e.g. '/nr/')
location / {
  # A full set of headers have to be redone for every context that defines another header
  include /etc/nginx/conf.d/includes/common_security_headers.conf;

  # Reverse Proxy
  #proxy_pass https://localhost:1880/; # <== CHANGE TO MATCH Node-RED's base URL
  include /etc/nginx/conf.d/includes/common_proxy_headers.conf;

  
  # Proxy the Node-RED Editor https://my.public.domain/red/ to http://localhost:1880/red/
  location /red/ {
    
    # ==> Of course, you could have a separate auth here! <==

    # Reverse Proxy for websockets
    include /etc/nginx/conf.d/includes/common_ws_proxy_headers.conf;

    # Reverse Proxy
    proxy_pass https://localhost:1880/red/; # <== CHANGE TO MATCH THE EDITOR's URL
    
    # Tell upstream which proxy was used
    proxy_set_header X-JK-Proxy "RED";
    # Tell client which proxy was used
    add_header X-JK-Proxy "RED";

    # Proxy the Node-RED Dashboard https://my.public.domain/red/dash/ to http://localhost:1880/ui/
    location /red/dash/ {

      # ==> Feel free to have different auth here <==

      # Reverse Proxy
      proxy_pass https://localhost:1880/ui/; # <== CHANGE TO MATCH THE EDITOR's URL
      
      # Tell upstream which proxy was used
      proxy_set_header X-JK-Proxy "RED-DASH";
      # Tell client which proxy was used
      add_header X-JK-Proxy "RED-DASH";
    }

    # Proxy the Node-RED Dashboard https://my.public.domain/red/ui/ to http://localhost:1880/ui/
    location /red/ui/ {

      # ==> Feel free to have different auth here <==

      # Reverse Proxy
      proxy_pass https://localhost:1880/ui/; # <== CHANGE TO MATCH THE EDITOR's URL
      
      # Tell upstream which proxy was used
      proxy_set_header X-JK-Proxy "RED-UI";
      # Tell client which proxy was used
      add_header X-JK-Proxy "RED-UI";
    }
  }
}

```

And the security headers:

```auto
# Default header properties
# These have to be respecified for EVERY server/location context if that context defines another header. 
# So we use an include file that won't be loaded by the nginx.conf file directly.

# don't allow the browser to render the page inside an frame or iframe and avoid clickjacking http://en.wikipedia.org/wiki/Clickjacking
# if you need to allow [i]frames, you can use SAMEORIGIN or even set an uri with ALLOW-FROM uri https://developer.mozilla.org/en-US/docs/HTTP/X-Frame-Options
add_header X-Frame-Options SAMEORIGIN;

# when serving user-supplied content, include a X-Content-Type-Options: nosniff header along with the Content-Type: header,
# to disable content-type sniffing on some browsers. https://www.owasp.org/index.php/List_of_useful_HTTP_headers
add_header X-Content-Type-Options nosniff;

# This header enables the Cross-site scripting (XSS) filter built into most recent web browsers.
# It's usually enabled by default anyway, so the role of this header is to re-enable the filter for 
# this particular website if it was disabled by the user.
# https://www.owasp.org/index.php/List_of_useful_HTTP_headers
add_header X-XSS-Protection "1; mode=block";

# Content Security Policy (CSP) - tell the browser that it can only download content from the domains you explicitly allow
# http://www.html5rocks.com/en/tutorials/security/content-security-policy/
# https://www.owasp.org/index.php/Content_Security_Policy
# Must be configured for your specific needs
#add_header Content-Security-Policy ........ ;

# You may want this in case something tries to refer from your site to something like Facebook https://scotthelme.co.uk/a-new-security-header-referrer-policy/
add_header Referrer-Policy "strict-origin-when-cross-origin";

# Configure for Strict Transport Security (HSTS) - only if https is in use - see map in default.conf
add_header Strict-Transport-Security $sts;

# NGINX seems to often ignore directive to not blab
add_header server 'home';

```

I don't actually open my home server to the Internet so it is OK for me to share these 😀  
And even if I did, I would only allow a connection from Cloudflare which I would use as a further layer of web protection.

---

<div class="post-metadata">

**Author:** ![TheToto318](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/thetoto318/32/63255_2.png) [@TheToto318](https://discourse.nodered.org/u/TheToto318)\
**Post date:** [16 June 2022 12:41 UTC](https://discourse.nodered.org/t/nodered-websockets-and-nginx-reverse-proxy-subfolder/63998/9 "2022-06-16T12:41:19Z")

</div>

I want to say thank you very much, I used your config and it worked, I think the thing that cause trouble is that I made an other location for the '/comms/' URL.  
This is my working config :

```auto
    location ^~ /nodered/ {
        resolver 127.0.0.11 valid=30s;
        set $upstream_app 192.168.1.119;
        set $upstream_port 1880;
        set $upstream_proto http;
        proxy_pass $upstream_proto://$upstream_app:$upstream_port;
        error_log /config/log/nginx/nodered_error.log debug;

        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Forwarded "by=$host;for=$proxy_add_x_forwarded_for;host=$host;proto=$scheme";
        proxy_set_header Via "$scheme/1.1 $host:$server_port";

        proxy_set_header X-Real-IP $proxy_protocol_addr;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Forwarded-Port $server_port;
        proxy_set_header X-Forwarded-Host $host;
        proxy_http_version 1.1;
        proxy_set_header X-JK-Proxy "RED";
        add_header X-JK-Proxy "RED";

        # Proxy timeouts
        proxy_connect_timeout 60s;
        proxy_send_timeout 60s;
        proxy_read_timeout 60s;

        rewrite ^/nodered/(.*)$ /$1 break;

```

Thanks again, have a great day !

---

<div class="post-metadata">

**Author:** ![TotallyInformation](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/totallyinformation/32/31_2.png) [@TotallyInformation](https://discourse.nodered.org/u/TotallyInformation)\
**Post date:** [16 June 2022 17:03 UTC](https://discourse.nodered.org/t/nodered-websockets-and-nginx-reverse-proxy-subfolder/63998/10 "2022-06-16T17:03:36Z")

</div>

Glad it works. You probably don't need my custom header though 😀

```auto
proxy_set_header X-JK-Proxy "RED";
add_header X-JK-Proxy "RED";

```

---

<div class="post-metadata">

**Author:** ![system](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/1X/d073cd938eafa2e558d7c2cd59003b3ef4963033.png) [@system](https://discourse.nodered.org/u/system)\
**Post date:** [30 June 2022 17:04 UTC](https://discourse.nodered.org/t/nodered-websockets-and-nginx-reverse-proxy-subfolder/63998/11 "2022-06-30T17:04:32Z")

</div>

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.
