Question
Using NGINX to redirect socket.io (Node-Red) traffic based on a subrequest result (with SSL)
NGINX is acting as a reverse proxy for a number of Node-Red instances and should allow/deny access requests based on the result of a subrequest. When a client requests access to a specific Node-Red instance NGINX forwards the request to the authentication server using the httpauthrequest_module. The authentication server then allows/denies access based on the cookie contents.
If access is allowed (the subrequest replies with 200 status) NGINX forwards the request to the Node-Red instance using proxy_pass. If access is denied (the subrequest replies with 401 status) NGINX redirects the request to the login in page. This works correctly.
If a client was allowed to access a specific instance and the cookie expires/or it is deleted NGINX should then deny the request and redirect the client to the login page. This does not work correctly. Looking at the developer console in Chrome the request alternates between 302 and 304 status and specifically mentions socket.io polling. How do I redirect the socket.io traffic to the login screen if user access is denied?
The Node-Red instances are running in Docker containers. I am not providing the docker-compose file as it has not influence on the problem. The authentication server is working correctly as it replies with the correct status for both allowed and denied requests.
Below the nginx.conf file.
worker_processes 2;
events {
worker_connections 1024;
}
http {
server {
listen 80;
listen [::]:80;
server_name foo.bar;
return 302 https://foo.bar$request_uri;
}
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name foo.bar;
ssl on;
ssl_certificate /etc/nginx/ssl/fullchain.pem;
ssl_certificate_key /etc/nginx/ssl/privkey.pem;
ssl_session_timeout 1d;
ssl_session_cache shared:SSL:20m;
ssl_session_tickets off;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_ciphers 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!3DES:!MD5:!PSK';
ssl_stapling on;
ssl_stapling_verify on;
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-SSL on;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-NginX-Proxy true;
#Upgrade websockets to work over http
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
#Redirect unauthorized attempts to login URL
location @login {
return 302 https://$server_name;
}
#NR instance for login page
location / {
proxy_pass http://nodered0:1880/;
proxy_intercept_errors on;
auth_request_set $auth_status $upstream_status;
error_page 401 = @login;
error_page 404 = @login;
}
#Admin interface of login page
location /admin/0/ {
proxy_pass http://nodered0:1880/admin;
auth_request /auth;
}
#Authentication route
location /auth {
proxy_pass http://nodered1:1880/auth/;
proxy_pass_request_body off; # no need to send the POST body
proxy_set_header Content-Length "";
proxy_set_header X-Original-URI $request_uri;
proxy_set_header Content-Length "";
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;
}
#Admin interface of authentication route
location /admin/1/ {
proxy_pass http://nodered1:1880/;
auth_request /auth;
error_page 401 = @login;
error_page 404 = @login;
}
location /user1/ui/ {
proxy_pass http://nodered100001:1880/ui/;
auth_request /auth;
proxy_intercept_errors on;
auth_request_set $auth_status $upstream_status;
error_page 401 = @login;
error_page 404 = @login;
}
location /user1/worldmap/ {
proxy_pass http://nodered100001:1880/worldmap/;
auth_request /auth;
proxy_intercept_errors on;
auth_request_set $auth_status $upstream_status;
error_page 401 = @login;
error_page 404 = @login;
}
location /admin/100001/ {
proxy_pass http://nodered100001:1880/;
auth_request /auth;
proxy_intercept_errors on;
auth_request_set $auth_status $upstream_status;
error_page 401 = @login;
error_page 404 = @login;
}
}
}
These answers are provided by our Community. If you find them useful, show some love by clicking the heart. If you run into issues leave a comment, or add your own answer to help others.
×