Reputation: 632
I have a small web app that's served with Express.js and connects to the backend with Socket.io. To make it public, I'm using Nginx as a reverse proxy and then Cloudflare at the very front. The app relies on the disconnect
event firing when the it's closed or reloaded to keep track of online users among other things. When going through Nginx and Cloudflare the disconnect event never fires on the backend. It does when developing locally.
Here's my Nginx config file:
server {
listen 80;
server_name colab.gq;
server_name www.colab.gq;
location / {
proxy_pass http://localhost:3000;
proxy_set_header X-Forwarded-For $remote_addr;
}
listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/colab.gq/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/colab.gq/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}
And here's a snippet of my server-side code:
io.on('connection', (socket) => {
// Stuff here
socket.on('disconnect', () => {
console.log('disconnected!')
// Stuff that relies on the disconnect event
})
})
When the user closes the tab or reloads the page the disconnect event should fire, but it never does when passing the connection through Nginx and Cloudflare. Thanks in advance for any help!
UPDATE: It seems like a few seconds after reloading/closing the disconnect event finally registers.
Upvotes: 0
Views: 866
Reputation: 2910
You have to add upgrade headers to your socket io path in nginx configuration it like this,
location ~* \.io {
.. your configuration
proxy_pass http://localhost:3000;
proxy_redirect off;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
Since you asked for a extension of the answer, first thing which you may already know is socket.io is a protocol that use Websockets protocol under the hood (so both are the same). As standards both Websockets protocols and HTTP protocols is listening on the same port 80 or 443. The default protocol is HTTP, if user wants to use websockets protocol he/she has to send a upgrade request from HTTP to WS protocol and there is some key authentication and steps.
That's why you need to put them in your nginx configuration.
Refer this if you need more information abouth Protocol upgrade mechanism.
Even though in my opinion, this is not a exact duplicate of this question, I feel obligated to give credits for @Paulo to providing the perfect answer even though is not accepted.
Upvotes: 1
Reputation: 36
What is probably happening is 2 things.
1st: Socket.io has a long timeout (hence the several seconds) and is looking to reconnect before declaring that it has been disconnected. Check for a reconnect_attempt or reconnecting event (note I have not used socket.io in a while, so I could be wrong on the timing for this)
2nd: You are not telling socket.io that it is disconnecting upon closing the browser window.
I would recommend adding an event listener to your javascript that will tell your server that it is being disconnected upon window close.
window.addEventListener('beforeunload', () => {
socket.disconnect();
}
Upvotes: 1