Skip to main content

Nginx WebSocket reverse proxy keeps return 200 instead of 101




I'm currently trying to have a hack.chat on my personal server working.



Long story short, it consists of two servers. The first is a simple httpd server serving javascript and CSS. The second one, the chat system, is a node.js server which the javascript connects to using websocket. And here comes the problems.



I want it all to use port 80, with a different domain name on a single IP, using a separate server block in Nginx.



I followed the Nginx websocket doc but this is not working. When the websocket tries to connect, it always gets a 200 return code whereas, if I understood well, it should get 101 (switching protocol).



My Nginx version is 1.8.0 and my server is running on gentoo with linux 4.0.5




Here is a dump of the relevant nginx conf files :



nginx.conf:



user nginx nginx;
worker_processes 1;

error_log /var/log/nginx/error_log info;


events {
worker_connections 1024;
use epoll;
}

http {
include /etc/nginx/mime.types;
default_type application/octet-stream;

log_format main

'$remote_addr - $remote_user [$time_local] '
'"$request" $status $bytes_sent '
'"$http_referer" "$http_user_agent" '
'"$gzip_ratio"';

client_header_timeout 10m;
client_body_timeout 10m;
send_timeout 10m;

connection_pool_size 256;

client_header_buffer_size 1k;
large_client_header_buffers 4 2k;
request_pool_size 4k;

gzip on;
gzip_min_length 1100;
gzip_buffers 4 8k;
gzip_types text/plain;

output_buffers 1 32k;

postpone_output 1460;

sendfile on;
tcp_nopush on;
tcp_nodelay on;

keepalive_timeout 75 20;

ignore_invalid_headers on;


include /etc/nginx/sites-enabled/*;
}


sites-enabled/chat :



map $http_upgrade $connection_upgrade{
default upgrade;
'' close;
}


server{
listen 0.0.0.0:80;
server_name chat.axellink.fr;

location / {
proxy_pass http://127.0.0.1:6060;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;

}

access_log /var/log/nginx/chat_access;
error_log /var/log/nginx/chat_error debug;
}


When I take a look at the access_log, it effectively shows the 200 response and there is no error in the error_log. Unfortunately, the node.js server does not give me any log (or I don't know how to view it).



Thank you in advance for any response.




EDIT



Thx to mc0e, I managed to have the hack.chat server respond 101. By comparing what actually happens between nginx and node.js with what happens on a direct connection, I saw that on direct an header Upgrade: websocket is set but nginx does not. So I corrected my sites-enabled/chat to :



server{
listen 0.0.0.0:80;
server_name chat.axellink.fr;

location / {

proxy_pass http://127.0.0.1:6060;
proxy_http_version 1.1;
proxy_set_header Upgrade "websocket";
proxy_set_header Connection "Upgrade";
}

access_log /var/log/nginx/chat_access;
error_log /var/log/nginx/chat_error debug;
}



I also removed the map block as it used to set the Connection header to close instead of Upgrade.



Still doesn't work though. hack.chat gives back a 101 with Connection: Upgrade and Upgrade : websocket but somehow nginx gives back a 101 with Connection: keep-alive (as what I see in firefox) :/



EDIT



Did a ngrep on nginx communications, it does send the packet hack.chat gives back to him and firefox is complaining about cross-origin. I'll try to avoid cross origin.



LAST EDIT




Ok now that I'm home I did a test and it worked like a charm. Pretty sur that my last issue was because of my work proxy, let's hope it's cache or else everything would have been useless.



Here is the last of my conf that avoids cross origin :



server{
listen 0.0.0.0:80;
server_name chat.axellink.fr;

location / {

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;
proxy_pass http://127.0.0.1:8081;
}

location /chat/ {
proxy_pass http://127.0.0.1:6060;
proxy_http_version 1.1;

proxy_set_header Upgrade "websocket";
proxy_set_header Connection "Upgrade";
}

access_log /var/log/nginx/chat_access;
error_log /var/log/nginx/chat_error debug;
}

Answer



From my reading of the nginx websocket dock, when your nginx proxy sees the Upgrade headers, it passes them on to hack.chat. hack.chat then needs to respond with the 101 response.




First of all, you want to be able to debug the actual HTTP and hack.chat transactions, so you know whether the problem is in your client app, or on the web server, or with the hack.chat communications. This will also allow you to get the exact HTTP response, which you say you currently don't know how to get at. IF the problem is server side though, you may still be looking to get better logs of what went wrong.



You can capture the http traffic with tcpdump or ngrep. I'd go for ngrep. Doing it like this will give you output in your terminal.



ngrep 'Host: chat.axellink.fr' port 80


You probably want to run that on your web server, though if you have a desktop environment that can run ngrep you might chose to run it there. If you run it on the server, you can also capture the interaction between nginx and your chat server.




ngrep '.' port 6060


The terminal output is often enough to see what you need, but you can also use the '-O' flag to ngrep to write the data to a pcap dump file as tcpdump does with '-w'. You can then bring that file back to your desktop to look at it with a graphical client like wireshark.



You might be able to spot the problem from this, but if not, capture the various interactions and add them to your question.



Is there a problem with javascript asking for the hack.chat communication on a different domain to the one the javascript is served from? This might be relevant: https://stackoverflow.com/questions/20093070/unable-to-create-cross-domain-websocket-connection-to-node-js-socket-io-server


Comments

Popular posts from this blog

linux - iDRAC6 Virtual Media native library cannot be loaded

When attempting to mount Virtual Media on a iDRAC6 IP KVM session I get the following error: I'm using Ubuntu 9.04 and: $ javaws -version Java(TM) Web Start 1.6.0_16 $ uname -a Linux aud22419-linux 2.6.28-15-generic #51-Ubuntu SMP Mon Aug 31 13:39:06 UTC 2009 x86_64 GNU/Linux $ firefox -version Mozilla Firefox 3.0.14, Copyright (c) 1998 - 2009 mozilla.org On Windows + IE it (unsurprisingly) works. I've just gotten off the phone with the Dell tech support and I was told it is known to work on Linux + Firefox, albeit Ubuntu is not supported (by Dell, that is). Has anyone out there managed to mount virtual media in the same scenario?

hp proliant - Smart Array P822 with HBA Mode?

We get an HP DL360 G8 with an Smart Array P822 controller. On that controller will come a HP StorageWorks D2700 . Does anybody know, that it is possible to run the Smart Array P822 in HBA mode? I found only information about the P410i, who can run HBA. If this is not supported, what you think about the LSI 9207-8e controller? Will this fit good in that setup? The Hardware we get is used but all original from HP. The StorageWorks has 25 x 900 GB SAS 10K disks. Because the disks are not new I would like to use only 22 for raid6, and the rest for spare (I need to see if the disk count is optimal or not for zfs). It would be nice if I'm not stick to SAS in future. As OS I would like to install debian stretch with zfs 0.71 as file system and software raid. I have see that hp has an page for debian to. I would like to use hba mode because it is recommend, that zfs know at most as possible about the disk, and I'm independent from the raid controller. For us zfs have many benefits,

apache 2.2 - Server Potentially Compromised -- c99madshell

So, low and behold, a legacy site we've been hosting for a client had a version of FCKEditor that allowed someone to upload the dreaded c99madshell exploit onto our web host. I'm not a big security buff -- frankly I'm just a dev currently responsible for S/A duties due to a loss of personnel. Accordingly, I'd love any help you server-faulters could provide in assessing the damage from the exploit. To give you a bit of information: The file was uploaded into a directory within the webroot, "/_img/fck_uploads/File/". The Apache user and group are restricted such that they can't log in and don't have permissions outside of the directory from which we serve sites. All the files had 770 permissions (user rwx, group rwx, other none) -- something I wanted to fix but was told to hold off on as it wasn't "high priority" (hopefully this changes that). So it seems the hackers could've easily executed the script. Now I wasn't able