28

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

Dan Dascalescu
  • 143,271
  • 52
  • 317
  • 404
gpasse
  • 4,380
  • 7
  • 44
  • 75

6 Answers6

72

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).

Community
  • 1
  • 1
Dan Dascalescu
  • 143,271
  • 52
  • 317
  • 404
  • 2
    Thanks Dan. Enable websocket is the way to go. Also upgrade nginx to 1.4 or later to get websocket. – Phuoc Do May 12 '14 at 06:21
  • Would be nice to also have this for Apache. – the Jun 18 '14 at 15:12
  • 1
    @KasperSouren: for the vast majority of cases, Apache is overkill. I see no reason to use it. More at http://www.wikivs.com/wiki/Apache_vs_nginx – Dan Dascalescu Oct 11 '14 at 23:31
  • Apache is definitely overkill but it's overkill that I have running on most of my servers because it's easier to set up with stuff like MediaWiki, Drupal and WordPress. – the Oct 12 '14 at 12:49
  • Nginx is easy to setup with any PHP application by using `fastcgi_pass`. It takes about 5 lines. Here's my [full nginx config file for Wordpress](http://pastebin.com/irQuxpt2). You may want to consider the trade-off between spending an hour or two to grok the relevant nginx docs, and having much faster performance for all of your sites, from now on, by switching from Apache. – Dan Dascalescu Oct 12 '14 at 18:38
  • 1
    Great answer! Thank you very much. I lost 2 days with apache to get websocket working - I failed. Than I found this answer and after switching to nginx everything started to work nearly immediately. – Marcin Wieczorek Mar 08 '15 at 22:01
8

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.
nate-strauser
  • 2,763
  • 1
  • 16
  • 16
  • 2
    set it to 1? export DISABLE_WEBSOCKETS=1 ? – grgry Jul 18 '13 at 19:23
  • 2
    i do DISABLE_WEBSOCKETS=true - pretty sure any value will work given the meteor verbage - just needs to be set as an environment variable – nate-strauser Jul 18 '13 at 23:39
  • I notice on my app if I access it from mobile over cell network without websockets, images fail to load... is there a way to get around this, without websockets? – ewindsor Oct 14 '13 at 21:32
  • 5
    Hate to downvote, but you [don't need to disable Websockets](http://stackoverflow.com/a/22750356/1269037) – Dan Dascalescu May 13 '14 at 01:51
  • 2
    Downvote - sorry. This answer is just incorrectly marked as best answer which isn't the true. Much better answer is from Dan Dascalescu, who describes how to configure nginx to get Websocket working. Please refer to this answer: http://stackoverflow.com/a/22750356/581768 – Marcin Wieczorek Mar 08 '15 at 21:55
1

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.

1

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.

jazzed
  • 382
  • 3
  • 6
  • thanks for sharing the insight jazzed. can you elaborate more on why it is better, possibly describe or reference some of the technical details of the setup? – grgry Dec 08 '19 at 01:04
0

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;
    }
}
Kyo
  • 61
  • 6
0

The solution is, not only you have to add these two lines:

proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;

into your Nginx config, you must put them in here:

location / {
    ...
    ...
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection $connection_upgrade;
}

Spends hours to figure it out!

Behnia FB
  • 53
  • 4