socketio / socket.io

Realtime application framework (Node.JS server)
https://socket.io
MIT License
60.53k stars 10.09k forks source link

Sockets are not working with CloudFlare (Solved by myself) #2580

Closed salmanaligeek closed 8 years ago

salmanaligeek commented 8 years ago

I have nodejs web socket server running on port 3000 on my Debian based VPS. I am currently using free plan of cloudflare.

socket.mydomain.com is gray record in CloudFlare and sockets are working with this URL but I don't want to work this way because I don't want to expose my server's IP address. Main problem is that sockets are not working on main orange record in cloudflare. Cloudflare have sockets support in free plan too but why these are not working? What I am doing wrong?

I have Laravel application and it was not working with Cloudflare initially and I had to install https://github.com/fideloper/TrustedProxy to work with cloudflare.

I tried to follow this guide but no luck: http://expressjs.com/en/guide/behind-proxies.html

I have been trying to solve this issue for weeks.

Here is the nodejs socket server codes:

var express = require('express');
var https = require('https');
var http = require('http');
var app = express();
var port = '3000';

//app.enable('trust proxy fn');
//app.set('trust proxy fn', 'loopback, linklocal, uniquelocal');
app.set('trust proxy fn', [
    // Ipv4
    '103.21.244.0/22',
    '103.22.200.0/22',
    '103.31.4.0/22',
    '104.16.0.0/12',
    '108.162.192.0/18',
    '131.0.72.0/22',
    '141.101.64.0/18',
    '162.158.0.0/15',
    '172.64.0.0/13',
    '173.245.48.0/20',
    '188.114.96.0/20',
    '190.93.240.0/20',
    '197.234.240.0/22',
    '198.41.128.0/17',
    '199.27.128.0/21',
    // Ipv6
    '2400:cb00::/32',
    '2405:8100::/32',
    '2405:b500::/32',
    '2606:4700::/32',
    '2803:f800::/32',
]);

var server = http.createServer(app);

var io = require('socket.io')(server);
var Redis = require('ioredis');
var redis = new Redis({password: "myredispassword"});

server.listen(port, function () {
    var addr = server.address();
//  console.log(addr);
    console.log('   server listening on ' + addr.address + ':' + addr.port);
});

//function handler(req, res) {
//  console.log(req);
//  res.writeHead(200);
//  res.end('');
//}

io.on('connection', function (socket, req) {
//  console.log(socket);
//  console.log(req);
});

redis.psubscribe('*', function (err, count) {
    //
});

redis.on('pmessage', function (subscribed, channel, message) {
    message = JSON.parse(message);
    io.emit(channel + ':' + message.event, message.data);
});

Client-side code:

<script src="{{ asset('assets/js/socket.io.js') }}"></script>
//  var socket = io('<?php echo url('/'); ?>:3000', {secure: false, port: 3000}); // does not work
var socket = io('socket.mydomain.com:3000', {secure: false, port: 3000}); // works but prone to DDoS

socket.on('test-event:App\\Events\\TestEvent', notifyUser_mine);
</script>
ejancorp commented 7 years ago

How did you solve this? thank you

innovak commented 7 years ago

The 3000 port is not supported by Cloudflare, try to use this port: 80,8080,8880,2052,2082,2086,2095. ref: https://support.cloudflare.com/hc/en-us/articles/200169156-Which-ports-will-CloudFlare-work-with-

salmanaligeek commented 7 years ago

@ejancorp Used port 8443 for SSL and 8880 for non-ssl socket connections.

ATNoosh commented 6 years ago

But when I use 8443 port for ssl connections, shows this error: handshake error 525

coderovich commented 5 years ago

In case of 525, 522 or 520 HTTP errors If you are using any TLS port different from 443 don't forget to open this port on your origin server. For example, if your socket.io (or any other websocket) app listen on 2053 port, you have to open it like this: iptables -A INPUT -p tcp -m tcp --dport 2053 -j ACCEPT

hope it helps

yingshaoxo commented 4 years ago

I've been spending a whole night to solve this problem when I start to use https or wss or ssl. It always says connection stopped before establish with 400 error code.

Just a minutes ago, I found a solution for that:

0. Cloudflare

At the SSL/TLS tab:

If you are not sure what you are doing, just go to DNS tab, set DNS only

1. Make sure you have a right proxy configuration.

server {
    listen 80;
    server_name ai-tools-online.xyz;
    return 301 https://ai-tools-online.xyz$request_uri;
}

server {
    listen 443 ssl http2;

    ssl_certificate       /data/v2ray.crt;
    ssl_certificate_key   /data/v2ray.key;
    ssl_protocols         TLSv1.2 TLSv1.3;
    #ssl_ciphers           3DES:RSA+3DES:!MD5;
    server_name ai-tools-online.xyz;

    location / {
        proxy_pass http://127.0.0.1:5000;
    }

    location /socket.io {
        proxy_http_version 1.1;
        proxy_buffering off;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "Upgrade";
        proxy_pass http://127.0.0.1:5000/socket.io;
    }
}

ai-tools-online.xyz is your domain, http://127.0.0.1:5000 is your socket server.

2. Make sure your server Cross-Origin Controls is set to '*' to allow Cross-Origin Access

For flask-socketio, is to use flask_socketio.SocketIO(app, cors_allowed_origins = '*')

3. You must restart the nginx to let the new config work

systemctl restart nginx

4. For more details about how to set caddy, see the following links:

https://github.com/yingshaoxo/Web-Math-Chat#reverse-proxy-configuration-for-https https://caddy.community/t/using-caddy-0-9-1-with-socket-io-and-flask-socket-io/508/6 https://www.nginx.com/blog/nginx-nodejs-websockets-socketio/

iamsarthakjoshi commented 3 years ago

@yingshaoxo I'm having a bizarre problem with socket.IO, Nginx reverse proxy and Cloudflare. Everything looks fine; even the browser Networks show socket.io connection being established, but when I trigger events from the server-side, nothing is received in the client-side (React.js).

Please help me!

Following are the setups and configs:

Ubuntu VM Server Open Ports:

SSL 443 NGINX 80 Other ports: 8443

Cloudflare

Nginx default config

server {
  listen 80;
  listen 443 ssl http2;
  server_name abc.xyz.so www.abc.xyz.so;
  root /var/www/html;

  location / {
    index  index.html index.htm;
    try_files $uri $uri/ /index.html /index.html?$query_string;
  }

  error_page   500 502 503 504  /50x.html;

  location = /50x.html {
    root   /var/www/html;
  }

  location /api {
    proxy_pass http://127.0.0.1:8443/api;
    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;
    proxy_buffering off;
    proxy_request_buffering off;
    proxy_http_version 1.1;
    proxy_intercept_errors on;
  }

  location /socket.io {
    include proxy_params;
    proxy_http_version 1.1;
    proxy_buffering off;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "Upgrade";
    proxy_pass http://127.0.0.1:8443/socket.io;
  }

  ssl_certificate /etc/nginx/certs/self-signed/abc.xyz.so.crt;
  ssl_certificate_key /etc/nginx/certs/self-signed/abc.xyz.so.key;
  ssl_dhparam /etc/nginx/certs/dhparam.pem;
}

Docker-compose:

version: '3.7'

networks: 
    xyz:

services:
    backend:
        build: .
        image: xyz_backend_mservice:latest
        volumes:
            - ./:/usr/src/app
        working_dir: /usr/src/app
        command: bash -c "gunicorn --worker-class eventlet -w 1 -b 0.0.0.0:8443 --preload application:app --reload --log-file=- --error-logfile gunicorn.error.log --access-logfile gunicorn.log --capture-output"
        ports:
            - 8443:8443
        environment:
            - FLASK_ENV=production
            - FLASK_APP=application.py
        networks: 
            xyz:

Server:

Dependencies

flask==1.0.2 eventlet==0.26.1 Flask-Socketio==4.3.1 gunicorn==20.0.4

Initializing socketio

socketio.init_app(app, cors_allowed_origins="*")

Triggering events

socketio.emit("trigger_db_fetch", "test_socket_io", broadcast=True)

Client:

"socket.io-client": "^2.3.0"

Initializing socketio

const socket = socketIOClient("https://abc.xyz.so/socket.io");

Receive data

socket.on('trigger_db_fetch', (data) => { console.log('trigger_db_fetch', data); });

This client-side event isn't triggered whenever the server emits the event. It's wrapped by componentDidMount() method. Locally (without Nginx and Cloudflare), everything works fine.

Browser Network XHRs:

mfmsajidh commented 2 years ago

I have the same issue @iamsarthakjoshi has.

@iamsarthakjoshi Did you overcome this issue ?