Socket IO websockets issues - node.js

I have a node express webserver starting up on my debian linux box on port 8080-8083 using pm2 cluster.
I have an nginx reverse proxy server setup on the server to redirect correctly to the node-express server, with the following /etc/nginx/sites-available/default
server {
listen 80;
listen [::]:80;
server_name a.registered.dns.domain.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name a.registered.dns.domain.com;
ssl_certificate /home/admin/certs/a.registered.dns.domain.com.chained.crt;
ssl_certificate_key /home/admin/certs/a.registered.dns.domain.com.key;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_ciphers 'EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH';
location / {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
proxy_pass http://nodes;
}
location /socket.io {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
proxy_pass http://nodes;
# enable WebSockets
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_cache_bypass $http_upgrade;
}
}
upstream nodes {
# enable sticky session based on IP
ip_hash;
server 127.0.0.1:8080 fail_timeout=20s;
server 127.0.0.1:8081 fail_timeout=20s;
server 127.0.0.1:8082 fail_timeout=20s;
server 127.0.0.1:8083 fail_timeout=20s;
}
This creates the websocket just fine between the server and the client as seen here.
upgrades the connection from the long polling to the websocket with the status 101. If I do something from the site that sends an emit over the socket, the server receives it and acts on it appropriately. So Far So Good.
However, if I do something elsewhere that causes the server to emit out to the client, I can see using DEBUG='socket.io*' pm2 restart http-server --update-env on the server that the socket information is received and emitted out, the client never receives the data packet it should. can confirm this by running localStorage.debug = '*'; from the console in my chrome dev tools.
Saw the emit out and nothing but ping and pong packets on the websocket.
This all works correctly if I open ports 8080-8083 and use only an http connection. So it feels as if there is some issue with the nginx reverse proxy for the ssl connection of my site.

Related

Socket proxy-pass from https to http

We have recently configured https for our backend server and are now running into some issues with socket. It seems that the sockets sort of work but it doesn't seem to transfer data between devices as intended. The socket is on port 3000 and instead of configuring SSL certification with sockets I just proxy_passed HTTPS requests to localhost port 3000. My suspicion is that it is linked to my nginx config any ideas where I might be going wrong?
server {
server_name app.domain.com;
location / {
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
proxy_set_header Host $host;
proxy_pass http://localhost:3000;
}
listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/app.domain.com/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/app.domain.com/privkey.pem; # managed by Certbot
}

nodejs nginx 502 gateway error

I am trying to use a nodejs app behind an nginx reverse proxy to handle the ssl
I have my app running on localhost:2000. I can confirm this as working with a curl command.
This is my nginx setup:
# the IP(s) on which your node server is running. I chose port 3000.
upstream dreamingoftech.uk {
server 127.0.0.1:2000;
keepalive 16;
}
# the nginx server instance
server {
listen 0.0.0.0:80;
server_name dreamingoftech.uk;
return 301 https://$host$request_uri;
}
#HTTPS
server {
listen 443 ssl http2;
server_name dreamingoftech.uk;
access_log /var/log/nginx/dreamingoftech.log;
error_log /var/log/nginx/dreamingoftech.error.log debug;
ssl_certificate /etc/letsencrypt/live/dreamingoftech.uk/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/dreamingoftech.uk/privkey.pem;
include snippets/ssl-params.conf;
# pass the request to the node.js server with the correct headers and much more can be added, see nginx config options
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-Forwarded-Proto https;
proxy_set_header X-NginX-Proxy true;
proxy_pass http://dreamingoftech.uk/;
proxy_redirect off;
#proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "";
proxy_ssl_session_reuse off;
proxy_cache_bypass $http_upgrade;
}
}
if I now curl https://dreamingoftech.uk, it takes a while but I do get the webpage delivered. albeit with the message:
curl: (18) transfer closed with 1 bytes remaining to read
However when viewed from a browser I get a 502 gateway error.
I have checked the error log and this is the result: ERROR LOG
I can't understand why the reverse proxy is adding such a time delay into the process. Any ideas would be greatly appreciated.
PS: in the upstream config I have tried localhost instead of 127.0.0.1 to no avail
I have almost the same configuration. Can you try the following
You can redirect all http to https
server {
listen 80;
return 301 https://$host$request_uri;
}
or for a specific site like this
server {
server_name dreamingoftech.uk;
return 301 https://dreamingoftech.uk$request_uri;
}
but choose only one for your case
and then you make sure you node server is running on http mode and not https.
Also you mentioned that you run node on port 3000, then use port 3000 and not 2000 as I can see in your config.
After you confirm the above redirect all packets into localhost like this
server {
listen 443;
server_name dreamingoftech.uk;
ssl_certificate /etc/letsencrypt/live/dreamingoftech.uk/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/dreamingoftech.uk/privkey.pem;
ssl on;
ssl_session_cache builtin:1000 shared:SSL:10m;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers HIGH:!aNULL:!eNULL:!EXPORT:!CAMELLIA:!DES:!MD5:!PSK:!RC4;
ssl_prefer_server_ciphers on;
location / {
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-Proto $scheme;
# Fix the “It appears that your reverse proxy set up is broken" error.
proxy_pass http://localhost:3000;
proxy_read_timeout 90s;
proxy_redirect http://localhost:3000 https://dreamingoftech.uk;
}
}
Create a file and sum the above code put it in sites-available with a name like dreamingoftech.uk and the use ln -s to create a softlink into sites-enabled. go to your nginx.conf and make sure you include folder sites-enabled
Then must restart nginx to check if it works
#Stamos Thanks for your reply. I tried that but unfortunately it didn't work. I decided to try the most basic node app I could still using the basic modules I am using.
I tried this and it worked straight away.
The problem is with my app therefore. I will spend time rebuilding and testing step by step until I find the issue,
Thanks for your time!

Socket.io disconnects on http request

I'm running nginx for my node.js application on a AWS EC2 instance. I want to use websockets (socket.io) and normal http request/response. My problem is, whenever I have an active socket connection from my mobile device to the server and try to make a normal http request, the mobile device's socket.io error function is called with the message "502 Bad Gateway".
Only socket works. Only normal http request works as well.
I figured out, that this problem occurred after I setup nginx to use https only.
Here is my nginx config in /sites-enabled /sites-available:
server {
listen 80;
listen 443 ssl;
server_name example.com www.example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf;
if ($scheme != "https") {
rewrite ^ https://$host$request_uri? permanent;
}
location / {
proxy_pass http://127.0.0.1:3000;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_http_version 1.1;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
}
}
Nginx error log:
[error] 14117#14117: *50 upstream prematurely closed connection while reading response header from upstream, client: 78.94.9.226, server: example.com, request: "GET /socket.io/?transport=polling&b64=1&sid=rgXMQhL6mbSET8ktAAAA HTTP/1.1", upstream: "http://127.0.0.1:3000/socket.io/?transport=polling&b64=1&sid=rgXMQhL6mbSET8ktAAAA", host: "example.com"
iOS error log:
LOG SocketIOClient: Handling event: error with data: ["Got unknown error from server <html>\r\n<head><title>502 Bad Gateway</title></head>\r\n<body bgcolor=\"white\">\r\n<center><h1>502 Bad Gateway</h1></center>\r\n<hr><center>nginx/1.10.3 (Ubuntu)</center>\r\n</body>\r\n</html>\r\n"]
If you need any more information, let me know!
I fixed the problem by myself. It was a really dumbass problem. I created a file inside my node.js server folder called access.log and told the morgan logger to write into the file. The thing I forgot was, that I'm using PM2 to restart the server whenever there is a change in code inside the server folder. So PM2 restarted the server every time I made a http request and the socket disconnected.
Change your nginx config into two blocks
server {
listen 80;
listen 443 ssl;
server_name example.com www.example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf;
if ($scheme != "https") {
rewrite ^ https://$host$request_uri? permanent;
}
location /socket.io {
proxy_pass http://127.0.0.1:3000;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_http_version 1.1;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
}
location / {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
}
}
You want to only upgrade connection for socket.io and not other urls

Cross-domain WebSocket connection failed during WebSocket handshake: Unexpected response code: 400

I am trying to use socket.io in a Node js application. I have the application sitting on a subdomain and the front-end running on the www version of the domain.
Running the front-end and Node js service on the same domain is not an option.
Sending data back and forth from the client to the server seems to be working. I have sent data both ways and it has worked fine.
However, In the console of the browser I get the following error.
WebSocket connection to 'wss://subdomain.domain.com/socket.io/?EIO=3&transport=websocket&sid=6bNHWyXcCdlMI0HHAAAB' failed: Error during WebSocket handshake: Unexpected response code: 400
My Nginx configuration looks like this:
# HTTP - redirect all requests to HTTPS:
server {
listen 80;
listen [::]:80 default_server ipv6only=on;
return 301 https://$host$request_uri;
}
# HTTPS - proxy requests on to local Node.js app:
server {
listen 443;
server_name subdomain.domain.com;
ssl on;
# Use certificate and key provided by Let's Encrypt:
ssl_certificate /etc/letsencrypt/live/subdomain.domain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/subdomain.domain.com/privkey.pem;
ssl_session_timeout 5m;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_ciphers '*******';
# Pass requests for / to localhost:3000:
location / {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-NginX-Proxy true;
proxy_pass http://localhost:3000/;
proxy_ssl_session_reuse off;
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
proxy_redirect off;
proxy_http_version 1.1;
proxy_set_header Connection "upgrade";
}
}
Both the client and the Node js are using https.
Does anyone know what is causing this issue and how it could be fixed?
Thank you
It looks like you forgot about Upgrade header. It's required if you want to use Nginx as a reverse proxy for WebSockets.
As said here, just try to add one more header:
proxy_set_header Upgrade $http_upgrade;

Socket.io lost connection after few minutes but only with NGINX proxy enabled

I have a problem with socket.io. When I start my Nodejs App Sockets works correctly but after few minutes the connection to websocket is closed and after reconnecting Socket.io fires emit again.
I'm using NGINX Proxy and I have noticed that bypassing NGINX the problem is solved, which configuration I need to edit? I think that the problem is my nginx configuration.
This is my NGINX default config:
server {
listen 80; #listen for all the HTTP requests
server_name example.com www.example.com;
return 301 https://www.example.com$request_uri; }
server {
server_name example.com;
listen 443 ssl http2;
#Optimize Webserver work
#client_max_body_size 16M;
keepalive_timeout 20;
ssl on;
ssl_certificate /root/social/ssl/cert.pem;
ssl_certificate_key /root/social/ssl/key.pem;
location / {
proxy_pass http://localhost:5430;
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;
}
}
upstream io_nodes {
server 127.0.0.1:5430;
keepalive 20;
}
Please help
You should add another parameter:
proxy_read_timeout 96000;
The default value is 60s. You will get a message "lost connect" after 60s idles with the default value.

Resources