Meteor WebSocket handshake error 400 with nginx - node.js

I managed to deploy meteor on my infrastructure (Webfactions).
The application seems to work fine but I get the following error in the browser console when my application starts:
WebSocket connection to 'ws://.../websocket' failed: Error during WebSocket handshake: Unexpected response code: 400

WebSockets are fast and you don't have to (and shouldn't) disable them.
The real cause of this error is that Webfactions uses nginx, and nginx was improperly configured. Here's how to correctly configure nginx to proxy WebSocket requests, by setting proxy_set_header Upgrade $http_upgrade; and proxy_set_header Connection $connection_upgrade;:
# we're in the http context here
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
# the Meteor / Node.js app server
server {
server_name yourdomain.com;
access_log /etc/nginx/logs/yourapp.access;
error_log /etc/nginx/logs/yourapp.error error;
location / {
proxy_pass http://localhost:3000;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host; # pass the host header - http://wiki.nginx.org/HttpProxyModule#proxy_pass
proxy_http_version 1.1; # recommended with keepalive connections - http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_http_version
# WebSocket proxying - from http://nginx.org/en/docs/http/websocket.html
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
}
}
This is an improved nginx configuration based on David Weldon's nginx config. Andrew Mao has reached a very similar configuration.
Remember to also set the HTTP_FORWARDED_COUNT environment variable to the number of proxies in front of the app (usually 1).

if you are receiving this error client side in the browser console, you can safely ignore it - it means that your hosting does not support websockets and meteor will fallback to using long polling instead
meteor apps deployed to heroku or any other platform without websockets will get the same error
update:
as of meteor v0.6.4 you can now set the environment variable DISABLE_WEBSOCKETS to prevent this attempt from occurring if you know it will fail
https://github.com/meteor/meteor/blob/devel/History.md
If you set the DISABLE_WEBSOCKETS environment variable, browsers will not attempt to connect to your app using Websockets. Use this if you know your server environment does not properly proxy Websockets to reduce connection startup time.

Concerning SEO: the failing websocket (code 400) also prevents Phantomjs for getting a decent pageload (and doesn't get terminated).
In my case, the new Nginx configuration from Dan prevents the failing of the websockets and lets Phantomjs load the page.

Found this in my search for this error when using AWS Elastic Load Balancer. Setting the environment variable works, but the better solution is to use the TCP protocol on the ELB instead of HTTPS. FYI.

We had the issue with disabled websocket when hosting Rocket Chat. Our users get "Websocket is disabled for this server" error when they tryed to connect to the server from mobile clients for iOS and Android.
Thanks to Dan's post, adding this lines to config helped us:
#websocket support
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
Thus way our config became like this:
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
server {
listen 443 ssl http2;
server_name our_rocketchat_domain_url.com;
ssl_certificate "/etc/letsencrypt/live/our_rocketchat_domain_url.com/fullchain.pem";
ssl_certificate_key "/etc/letsencrypt/live/our_rocketchat_domain_url.com/privkey.pem";
ssl_ciphers our_ciphers_list;
ssl_prefer_server_ciphers on;
ssl_protocols TLSv1.2 TLSv1.3;
access_log /var/log/nginx/our_rocketchat_domain_url.com.access.log;
error_log /var/log/nginx/our_rocketchat_domain_url.com.error.log warn;
location / {
proxy_buffers 16 4k;
proxy_buffer_size 2k;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Real-IP $remote_addr;
proxy_http_version 1.1;
proxy_pass http://ip_of_our_rocketchat:3000/;
#websocket support
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
}
}

Related

how can I deploy my mern website from my local machine?

I have a fully functioning MERN app working. I was wondering, how would I deploy my mern app to the world wide web from my local machine?
My research has concluded with XAMPP as a possible tool, but it seems the backend tooling is PHP not nodejs. Any ideas you guys have helps!
the idea is to host it locally not externally on the cloud.
Firstly, you need to buy vps server. After you need to upload full project to the server through ftp software and need to upload packages with npm install/update. After these are finished download nginx server to the server and be carefull about port of project. If your project will running for example on 3000 port you may change nginx configuration like this and restart nginx with followed command:
systemctl restart nginx
and nginx configuration write like this (added example domain):
server {
listen 80;
listen [::]:80;
server_name yourdomain.com;
root /var/projects/your_project_name;
add_header X-Frame-Options "SAMEORIGIN";
add_header X-XSS-Protection "1; mode=block";
add_header X-Content-Type-Options "nosniff";
index index.html;
charset utf-8;
location / {
proxy_pass http://localhost:3000/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
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_cache_bypass $http_upgrade;
}
}
For additional information about nginx configurations you may visit Nginx configurations

nginx + node + ssl + websockets, on one server

I've been able to find guides pertaining to various combinations of nginx, node, ssl, and websockets, but never all together and never on a single server.
Ultimately, this is what I'm after and I'm not sure if it's even possible:
single server (Ubuntu 14.04)
forced HTTPS (browsing to http://site forwards to https://)
node app is hosted on localhost:3000
node app uses web sockets
it's a single-page React app with no routing at all, so I don't need routes. I repeat, I'm only hosting one page with no navigation whatsoever.
With the below config, I have everything working except websockets - the client throws an error which doesn't happen if I browse straight to the node server and don't use nginx (browse to http://my.domain:3000):
bundle.js:26 WebSocket connection to 'wss://<my domain>/socket.io/?EIO=3&transport=websocket&sid=x1uQtRzF3gYYEvfIAAAi' failed: Error during WebSocket handshake: Unexpected response code: 400
server {
listen 80;
return 301 https://my/domain$request_uri;
}
server {
listen 443 ssl;
listen [::]:443;
ssl_certificate /path/cert.crt;
ssl_certificate_key /path/key.key;
ssl_session_cache shared:SSL:10m;
server_name blaze.chat;
location / {
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;
proxy_pass http://localhost:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Host $host;
proxy_redirect http://localhost:3000 https://my.domain;
}
}
Right, got it working... Found a lot of articles all showing similar things but missing these key lines:
proxy_set_header Connection "upgrade";
proxy_read_timeout 86400;
In my case, websockets won't work without those lines, contrary to many other posts where similar questions were asked. Not sure what the difference was. Ironically it is listed as a requirement in the Nginx Websocket Proxying doco... Should have started there, my bad.
http://nginx.org/en/docs/http/websocket.html
Side note, I am just using this on the root path of / which works fine.

How to setup nginx for multiple nodejs apps on a server (using socket.io with namespaces)

We have a nodejs app that currently uses socket.io ( with namespaces ). This app is used as a dashboard for a specific financial market. Each instance of app subscribe to a specific market data and provides a dashboard. Initially we were running 3 separate instances of this app configured for 3 separate markets on the server, all binding to separate ports for serving requests.
Since we plan to add more markets it makes sense to have a reverse proxy server where a single port (along with separate URI for each market) can be used. However, setting up nginx has been a nightmare for various reasons.
(a) each instance of app for a market can be in different development stage and hence can have different static files. Managing all static file via nginx seems painful ? What can be done to leave handling of the static files with the app itself.
(b) socket.io communication is a failure. We tried to look into network communication and it seems it keeps on getting 404 page not found error when trying to connect to socket.io server. Not sure why it is connecting via http::/localhost/server.io/ instead of ws://localhost/server.io/ ? Can somebody point us to a similar example ? Anything that needs to be taken care of ?
IN our case we have been trying the following inside nginx sites-available/default
location /app/ {
proxy_pass http://localhost:3000/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
#proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# kill cache
add_header Last-Modified $date_gmt;
add_header Cache-Control 'no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0';
if_modified_since off;
expires off;
etag off;
}
Using nginx as a reversed proxy should not give you a hard time. The great thing about nginx is that you can have multiple projects on the same server with different domains.
Here is an example of nginx with multiple projects:
server {
listen 80;
server_name yourdomain.com;
location / {
proxy_pass http://localhost:3000;
#Rember to set the header like this otherwise the socket might not work.
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 Host $host;
}
}
server {
listen 80;
server_name subdomain.yourdomain.com;
location / {
proxy_pass http://localhost:3001;
}
}
I'm not sure why your socket should fail. Perhaps the mistake is that you try to define the route on the client site. Try having the javascript like this:
var socket = io();
or if your socket runs on one of your other applications:
var socket = io('http://yourdomain.com');
And remember that your changes should be added to sites-enabled instead of sites-avaible

socket io with node js is not connecting through nginx proxy_pass

The issue is when i use nginx the socket is not establishing.Any one help me in steps to follow to integrate Socket oi with nginx.
i tried this
location /field {
# the following is required for WebSockets
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_set_header X-NginX-Proxy true;
# supposedly prevents 502 bad gateway error;
# ultimately not necessary in my case
proxy_buffers 8 32k;
proxy_buffer_size 64k;
# the following is required
proxy_pass
proxy_redirect off;
# the following is required as well for WebSockets
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
tcp_nodelay on; # not necessary
}
First of all check your nginx version. According to that page websockets supported after v1.3.13;
http://nginx.com/blog/nginx-nodejs-websockets-socketio/
Then compare your nginx conf with the below configuration as stated in the nginx blog;
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
upstream websocket {
server 192.168.100.10:8010;
}
server {
listen 8020;
location / {
proxy_pass http://websocket;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
}
}
http://nginx.com/blog/websocket-nginx/
Also check your firewall configuration for the port you chose for socket.io server. (I've read that some ISPs are blocking websocket connection for ports other than 80 & 443, please also check if server receive packets using tcpdump etc.)
If everyhing is okay up until now, check your nginx error logs (/var/log/nginx/error.log) to see if there are any socket.io related error messages. You can paste it here for further analysis.
Then if there is no socket error in nginx logs start your node app with DEBUG mode on as below;
DEBUG=* node yourfile.js
And check if any socket connection message is printed to console. You can also paste it for further analysis.

Nginx reverse proxy - passthrough basic authenication

I am trying to setup nginx as a reverse rpoxy server in front off several IIS web servers who are authenticating using Basic authentication.
(note - this is not the same as nginx providing the auth using a password file - it should just be marshelling everythnig between the browser/server)
Its working kind off - but getting repeatedly prompted for auth by every single resource (image/css etc) on a page.
upstream my_iis_server {
server 192.168.1.10;
}
server {
listen 1.1.1.1:80;
server_name www.example.com;
## send request back to my iis server ##
location / {
proxy_pass http://my_iis_server;
proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_pass_header Authorization;
proxy_redirect off;
proxy_buffering off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
This exact situation took me forever to figure out, but OSS is like that I guess. This post is a year old so maybe the original poster figured it out, or gave up?
Anyway, the problem for me at least was caused by a few things:
IIS expects the realm string to be the same as what it sent to Nginx, but if your Nginx server_name is listening on a different address than the upstream then the server side WWW-Authenticate is not going to be what IIS was expecting and ignore it.
The builtin header module doesn't clear the other WWW-Authenticate headers, particularly the problematic WWW-Authenticate: Negotiate. Using the headers-more module clears the old headers, and adds whatever you tell it to.
After this, I was able to finally push Sharepoint 2010 through Nginx.
Thanks stackoverflow.
server {
listen 80;
server_name your.site.com;
location / {
proxy_http_version 1.1;
proxy_pass_request_headers 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_pass_header Authorization; //This didnt work for me
more_set_input_headers 'Authorization: $http_authorization';
proxy_set_header Accept-Encoding "";
proxy_pass https://sharepoint/;
proxy_redirect default;
#This is what worked for me, but you need the headers-more mod
more_set_headers -s 401 'WWW-Authenticate: Basic realm="intranet.example.com"';
}
}
I had these same symptoms with nginx/1.10.3. I have a service secured under basic authentication, and nginx as a reverse proxy between the clients and the server. The requirement was that nginx would passthrough the authorization.
First request to the server did pass through the Authorization header. Second request simply blocked this header, which meant the client was only able to make one request per session.
This was somehow related to cookies. If I cleared the browser cookies, then the cycle repeated. The client was able to authenticate but just for the first request. Closing the browser had the same effect.
The solution for me was to change the upstream server from https to http, using:
proxy_pass http://$upstream;
instead of:
proxy_pass https://$upstream;

Resources