node.js, socket.io with SSL
Solution 1
Use a secure URL for your initial connection, i.e. instead of "http://" use "https://". If the WebSocket transport is chosen, then Socket.IO should automatically use "wss://" (SSL) for the WebSocket connection too.
Update:
You can also try creating the connection using the 'secure' option:
var socket = io.connect('https://localhost', {secure: true});
Solution 2
The following is how I set up to set it up with express:
var app = require('express')();
var https = require('https');
var fs = require( 'fs' );
var io = require('socket.io')(server);
var options = {
key: fs.readFileSync('./test_key.key'),
cert: fs.readFileSync('./test_cert.crt'),
ca: fs.readFileSync('./test_ca.crt'),
requestCert: false,
rejectUnauthorized: false
}
var server = https.createServer(options, app);
server.listen(8080);
io.sockets.on('connection', function (socket) {
// code goes here...
});
app.get("/", function(request, response){
// code goes here...
})
Update : for those using lets encrypt use this
var server = https.createServer({
key: fs.readFileSync('privkey.pem'),
cert: fs.readFileSync('fullchain.pem')
}, app);
Solution 3
On the same note, if your server supports both http
and https
you can connect using:
var socket = io.connect('//localhost');
to auto detect the browser scheme and connect using http/https accordingly. when in https, the transport will be secured by default, as connecting using
var socket = io.connect('https://localhost');
will use secure web sockets - wss://
(the {secure: true}
is redundant).
for more information on how to serve both http and https easily using the same node server check out this answer.
Solution 4
If your server certificated file is not trusted, (for example, you may generate the keystore by yourself with keytool command in java), you should add the extra option rejectUnauthorized
var socket = io.connect('https://localhost', {rejectUnauthorized: false});
Solution 5
Depending on your needs, you could allow both secure and unsecure connections and still only use one Socket.io instance.
You simply have to instanciate two servers, one for HTTP and one for HTTPS, then attach those servers to the Socket.io instance.
Server side :
// needed to read certificates from disk
const fs = require( "fs" );
// Servers with and without SSL
const http = require( "http" )
const https = require( "https" );
const httpPort = 3333;
const httpsPort = 3334;
const httpServer = http.createServer();
const httpsServer = https.createServer({
"key" : fs.readFileSync( "yourcert.key" ),
"cert": fs.readFileSync( "yourcert.crt" ),
"ca" : fs.readFileSync( "yourca.crt" )
});
httpServer.listen( httpPort, function() {
console.log( `Listening HTTP on ${httpPort}` );
});
httpsServer.listen( httpsPort, function() {
console.log( `Listening HTTPS on ${httpsPort}` );
});
// Socket.io
const ioServer = require( "socket.io" );
const io = new ioServer();
io.attach( httpServer );
io.attach( httpsServer );
io.on( "connection", function( socket ) {
console.log( "user connected" );
// ... your code
});
Client side :
var url = "//example.com:" + ( window.location.protocol == "https:" ? "3334" : "3333" );
var socket = io( url, {
// set to false only if you use self-signed certificate !
"rejectUnauthorized": true
});
socket.on( "connect", function( e ) {
console.log( "connect", e );
});
If your NodeJS server is different from your Web server, you will maybe need to set some CORS headers. So in the server side, replace:
const httpServer = http.createServer();
const httpsServer = https.createServer({
"key" : fs.readFileSync( "yourcert.key" ),
"cert": fs.readFileSync( "yourcert.crt" ),
"ca" : fs.readFileSync( "yourca.crt" )
});
With:
const CORS_fn = (req, res) => {
res.setHeader( "Access-Control-Allow-Origin" , "*" );
res.setHeader( "Access-Control-Allow-Credentials", "true" );
res.setHeader( "Access-Control-Allow-Methods" , "*" );
res.setHeader( "Access-Control-Allow-Headers" , "*" );
if ( req.method === "OPTIONS" ) {
res.writeHead(200);
res.end();
return;
}
};
const httpServer = http.createServer( CORS_fn );
const httpsServer = https.createServer({
"key" : fs.readFileSync( "yourcert.key" ),
"cert": fs.readFileSync( "yourcert.crt" ),
"ca" : fs.readFileSync( "yourca.crt" )
}, CORS_fn );
And of course add/remove headers and set the values of the headers according to your needs.
Related videos on Youtube
Beyond
Updated on September 17, 2021Comments
-
Beyond over 2 years
I'm trying to get socket.io running with my SSL certificate however, it will not connect.
I based my code off the chat example:
var https = require('https'); var fs = require('fs'); /** * Bootstrap app. */ var sys = require('sys') require.paths.unshift(__dirname + '/../../lib/'); /** * Module dependencies. */ var express = require('express') , stylus = require('stylus') , nib = require('nib') , sio = require('socket.io'); /** * App. */ var privateKey = fs.readFileSync('../key').toString(); var certificate = fs.readFileSync('../crt').toString(); var ca = fs.readFileSync('../intermediate.crt').toString(); var app = express.createServer({key:privateKey,cert:certificate,ca:ca }); /** * App configuration. */ ... /** * App routes. */ app.get('/', function (req, res) { res.render('index', { layout: false }); }); /** * App listen. */ app.listen(443, function () { var addr = app.address(); console.log(' app listening on http://' + addr.address + ':' + addr.port); }); /** * Socket.IO server (single process only) */ var io = sio.listen(app,{key:privateKey,cert:certificate,ca:ca}); ...
If I remove the SSL code it runs fine, however with it I get a request to http://domain.com/socket.io/1/?t=1309967919512
Note it's not trying https, which causes it to fail.
I'm testing on chrome, since it is the target browser for this application.
I apologize if this is a simple question, I'm a node/socket.io newbie.
Thanks!
-
kanaka almost 13 yearsIs your client trying to connect to a 'wss://' prefixed URI.
-
Beyond almost 13 yearsnope it doesnt get there, it makes the request to domain.com/socket.io/1/?t=1309967919512 then dies.
-
kanaka almost 13 yearsHow are you specifying the address to connect to? "domain.com" sounds like a placeholder in the socket.io client-side library. Can you post your client Javascript code that you are using to connect?
-
Beyond almost 13 yearsthe project is on github: github.com/BCCasino/BCCasino
-
Beyond almost 13 yearsbasically becasue its node.js socket.io magically handles the client side stuff, all you do is run socket.connect
-
Beyond almost 13 yearsin github the code in question is test2.js and index.jade (backend and frontend respetively)
-
Samuel Robert about 8 yearsI was trying to make a connection using wss uri it gives me URISyntaxException. Any idea why?
-
-
Beyond almost 13 yearswe do this. we goto https : // www.thebitcoinwheel.com and it still makes a request to http automatically, this is something with the socket.io code and is the point of the question.
-
XiaoChuan Yu almost 11 years
{secure: true}
should not be needed if you specify 'https' in the url. Here is an excerpt from socket.io client sourcesecure: 'https' == uri.protocol
(version 0.9.16), it sets secure option to true if https is detected in the url. -
Chiara Coetzee over 10 yearsI tried this with an https URL and indeed
{secure: true}
was not required to function correctly. -
gabeio over 10 yearsI believe it would be prudent to assure that the connection is secure by using both secure:true and issuing an https url to the client side. This way no matter what you know it will be a secure connection.
-
Francisco Hodge over 7 yearsThis is the only solution that worked for me. Thanks for saving my time.
-
RozzA over 7 yearsworked good for me after a bit of trial and error with the certs
-
Hugo Rune over 6 yearsThis solution worked perfect for me, thanks. If you're using the free certs from letsencrypt.org then you can use the following code..
var server = https.createServer({ key: fs.readFileSync('/etc/letsencrypt/live/domain.name/privkey.pem'), cert: fs.readFileSync('/etc/letsencrypt/live/domain.name/cert.pem'), ca: fs.readFileSync('/etc/letsencrypt/live/domain.name/chain.pem'), requestCert: false, rejectUnauthorized: false },app); server.listen(3000);
-
Harsha Jasti almost 6 yearsThanks a lot for this answer. It has been of tremendous help to me.
-
bvdb about 5 yearswould be appreciated if you added an example explaining how you used the keytool to create that key for node. 'Cause keys are so complicated and there just aren't enough tutorials about it.
-
clevertension about 5 yearskeytool is a tool inside the Java Development Kit (JDK). you can referer this docs.oracle.com/javase/10/tools/…
-
Pablo Pazos over 4 yearsI cracked my head looking for a solution in SocketIO and the issue was to config express, fantastic...
-
Martin Schneider over 4 years"
rejectUnauthorized: false
WARNING: it leaves you vulnerable to MITM attacks!" -
Eric over 4 yearsThanks, worked like a charm with letsencrypt and .pem files