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
It is in settings.js - there are several things you can change:
/** 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.
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:
# 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:
# 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.
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 :