Socket.IO + NodeJS + HTTPS = Fail

Salut! Tot caut pe net de 2 zile o solutie, dar nu am gasit nimic care sa ma ajute, poate imi scapa mie ceva…

Am un https://domeniu.ro care are conexiune secure (https) facuta cu certbot. Tot ce vine pe https://domeniu.ro se face proxypass in nginx catre portul 3000 unde este o aplicatie nodejs pornita.

In nodejs eu doresc sa folosesc socket.io pentru a comunica cu front-end-ul.

//server.js
const https = require('https')
const express = require('express')
const app = express()
var fs = require('fs');

var server = https.createServer({
    key: fs.readFileSync('/etc/letsencrypt/live/domeniu.ro/privkey.pem'),
    cert: fs.readFileSync('/etc/letsencrypt/live/domeniu.ro/fullchain.pem')
    requestCert: true,
    rejectUnauthorized: false
}, app);

server.listen(3000, console.log(`Server started on port 3000`)).on('error', function (err) {
    console.log(err)
});

const io = require("socket.io").listen(9957);

io.on('connection', (socket) => {
//code
})

front-end:

<script src="/socket.io/socket.io.js"></script>
<script type='text/javascript'>
var socket = io.connect(':9957', {
    secure: true
})
</script>

Iar in consola din chrome imi da asta:
index.js:83 GET https://domeniu.ro:9957/socket.io/?EIO=3&transport=polling&t=NGB40aK net::ERR_SSL_PROTOCOL_ERROR

Adauga certificatul, cheia si aici.

1 Like

Asigura-te ca in nginx.conf ai:

    # websocket support
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    proxy_cache_bypass $http_upgrade;

Configurarea SSL-ului o faci in nginx, si faci proxy_pass http://localhost:3000. In Node.js folosesti modulul http, nu https.

Ca sa fie mai simplu pune config-ul de la nginx daca nu te descurci.

4 Likes

Dupa foarte multe incercari, vad ca merge cu require(‘http’) in loc de require(‘https’).

Desi functioneaza, raman cu o eroare in consola:

index.js:83 WebSocket connection to ‘wss://domeniu.ro/socket.io/?EIO=3&transport=websocket&sid=G_6fXG05GZ41tU-2AAAA’ failed: Error during WebSocket handshake: Unexpected response code: 400

In final codul arata asa:

//server.js
var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);

http.listen(PORT, console.log(`Server started on port ${PORT}`)).on('error', function (err) {
    console.log(err)
});

io.on('connection', function (socket) {
    console.log("new conn", socket.id)
});

Si pe front-end

<script src="/socket.io/socket.io.js"></script>
<script type='text/javascript'>
var socket = io()
</script>

Finally! Totusi raman cu acea eroare de handshake…

Stiu ca mi-a dat si mie ceva batai de cap combinatia asta [node + socket.io + HTTPS].
Vad ca eu foloseam requestCert: false.
Nu lucrez destul de des cu node sau socket.io cat sa-ti dau un sfat, dar poate te ajuta in vreun fel codul de mai jos.

var fs = require( 'fs' );
var https = require('https');

var io = require( "./node_modules/socket.io" )
	.listen(
		https
			.createServer( {
				key: fs.readFileSync( "/etc/letsencrypt/live/vodafone/privkey.pem" ),
				cert: fs.readFileSync( "/etc/letsencrypt/live/vodafone/fullchain.pem" ),
				requestCert: false,
				rejectUnauthorized: false,
			} )
		.listen( 1919 )
	)
;
2 Likes

Eroarea este din nginx asigura-te ca ai headerele de mai sus si proxy_set_header Host $host;.

1 Like

Mai omule, ți s-a explicat mai sus.

Nginx face treaba SSL cu clientul. Atât.

Aplicația ta node va asculta pe orice port vrei, nu contează.

Nginx va sta doar de proxy între lume și portul http al aplicației.

Dacă faci aplicația nodejs să lucreze pe https direct, nu mai ai nevoie de nginx dar trebuie configurat certificatul in aplicația node (care nu cred că e dificil).

Tu aici încerci să pui ssl și între nginx și aplicație care complică problema și mai mult.

Ori una, ori alta, abia apoi poți începe debuggingul.

Eroarea poate fi de la nginx ca și client ssl pentru aplicație, nu in conexiunea cu clientul final.

Am configurat și eu websockets pentru ssl și prin nginx a mers perfect din prima.

4 Likes

In felul asta nu imi mai arata eroarea cu handshake de mai sus. Mersi!

LE: Pana acum problema ce o vad la solutia asta este ca daca doi useri diferiti incarca pagina, serverul de node incearca pentru fiecare sa porneasca un server pt socket io pe portul 1919, iar pentru al doilea user nu mai are cum sa il porneasca pentru ca portul e ocupat.

LLE: Am rezolvat prin crearea unei noi aplicatii node unde am pornit server de socket.io. Initial era ca un middleware inclus pe fiecare route, deci server-ul pt socket.io pornea la fiecare refresh. Acum sta pornit mereu ca o aplicatie standalone si face bridge intre mqtt si client.

1 Like