Node secure Websocket with IIS (Windows) - node.js

So I have created an application that uses a websocket in node.
In my server.js I use:
import http from "http";
import WebSocket from "websocket";
[...]
var httpServer = http.createServer(this.handleRequest);
httpServer.listen(port, function () {
console.log("Listening on port " + port);
});
var server = new WebSocket.server({httpServer: http_server});
[...]
This works, and creates a socket server on the same url.
Now, I'm trying to get this on a Windows server with IIS.
I start the application with "node server.js" and it is running on port 5003.
In IIS I use a rewrite rule to forward all incomming requests to the node server. Works perfect.
Now the problem. When I install an certificate with LetsEncrypt (Win-AMCE) the website is secure, but it won't connect to the websocket as the websocket is not secure.
According to some finds on the internet I need to use npm https
import http from "https";
import WebSocket from "websocket";
import fs from "fs";
[...]
const options = {
key: fs.readFileSync("my-site-key.pem"),
cert: fs.readFileSync("chain.pem")
};
var httpsServer = https.createServer(options,this.handleRequest);
httpsServer.listen(port, function () {
console.log("Listening on port " + port);
});
var server = new WebSocket.server({httpsServer: http_server});
[...]
The problem is, how do I get some valid certificate files. I cannot sign them self because another error will popup I guess. I cannot find the files Letsencrypt created.
So.... how do I create a secure websocket??

Related

Create server available on HTTP/HTTPs that can be used with PM2

I'm trying to create a Socket.IO server that has the following goals:
Accessible on the local network of virtual machines using HTTP (http://<server-local-ip>)
That can be accessed via browser by users through the HTTPs protocol, and that can also make the socket.io.js bundle available via HTTPs (https://socket-server.example.com)
That uses all available CPUs in the virtual machine (the server will run in just one virtual machine) - (Possible with PM2)
Have the ability to be automatically restarted in case of failure (Possible with PM2)
For that I created a script based on the Socket.IO help article teaching how to use PM2 and this question that teaches to use HTTP and HTTPs.
/**
* pm2 start basic.js -i 0
*/
const http = require("http");
const https = require("https");
const { Server } = require("socket.io");
const { createAdapter } = require("#socket.io/cluster-adapter");
const { setupWorker } = require("#socket.io/sticky");
const { readFileSync } = require("fs");
const httpServer = http.createServer();
const httpsServer = https.createServer({
key: readFileSync("./localhost-key.pem"),
cert: readFileSync("./localhost.pem")
});
const io = new Server(httpServer, {
cors: {
origin: "*",
methods: ["GET", "POST"]
}
});
io.adapter(createAdapter());
setupWorker(io);
io.on("connection", (socket) => {
console.log(`connect ${socket.id}`);
});
httpsServer.on("request", (req, res) => {
io.engine.handleRequest(req, res);
});
httpsServer.on("upgrade", (req, socket, head) => {
io.engine.handleUpgrade(req, socket, head);
});
httpServer.listen(8080);
httpsServer.listen(4430);
Using HTTP and HTTPs always throws an error.
Via HTTPs I can't load the socket.io.js bundle. But as this service will be available via browser, it will be necessary to make it available via HTTPs to users.
Direct access via HTTPs displays:
{
code: 0,
message: "Transport unknown"
}
This is just using the first part of the script, without trying to run with PM2 yet.
When placing the PM2 part next to the script, other errors appear:
I have to remove the code httpServer.listen(3000); for HTTP to work
When I connect to HTTPs the code never finds the session, so it keeps trying to reconnect endlessly.
socket.io.js via HTTPs remains unreachable
Even using HTTP socket.io.js and connecting with <script src="http://localhost:8080/socket.io/socket.io.js"></script> <script> const socket = io('https://localhost:3001');</script> nothing works
However, if I run all this over HTTP only, without requiring HTTPs, it works perfectly.
What am I doing wrong for HTTP/HTTPs not to work together?
Will I have to make the server available only in HTTP and create a proxy via NGINX to support HTTPs and call the HTTP server?

use proxy pass xampp for socket.io node js server

I been trying to open the website from my mobile. I made two servers. One using xampp and php to run the website and get data from database. The second server is for running web socket. Real time chat and drawing. So server1 is in port 3000 and server2 is in 8000. how can I open both server in my mobile?
I tried
I put this in httpd.conf:
ProxyPass /node http://localhost:8000
and then in the client side, I put:
var socket = io('http://localhost/node', { transports : ['websocket']});
I am getting error:
WebSocket connection to 'ws://localhost/socket.io/?EIO=4&transport=websocket' failed:
node js setup:
const http = require('http');
const socket = require('socket.io');
const port = process.env.PORT || "8000";
const server = http.createServer((req,res)=>{
res.end('I am connected!');
});
const io = socket(server);
io.on('connection',(socket,req)=>{
socket.emit('Welcome','Welcome to the websocket server!!');
});
server.listen(port);
xampp setup:
$login = new Login();
$user_data = $login->check_login($_SESSION['Trial_User_Id']);
[xampp window][1]

WebSocket is closed before the connection is established. Socket.io and React

I want to make an Chat application with Socket.io and I've followed this tutorial: https://youtu.be/ZwFA3YMfkoc. I am using React and Node.js
Everything works fine while using it locally and even on different devices on my Network. However if I am hosting my Backend on Heroku it doesn't work.
The error Message is:
WebSocket connection to 'URL' failed: WebSocket is closed before the connection is established.
(URL is the URL of my Backend with the Port). I am using SSL.
I've already tried to enable session affinity but it already was enabled.
My backend code is: (atleast the code that I think is important to the Problem)
const app = express();
const server = http.createServer(app);
const io = socketio(server);
app.use(cors());
server.listen(PORT, () => console.log("Server started on " + PORT));
My frontend code is written in React and is:
var connectionOptions = {
"force new connection": true,
reconnectionAttempts: "Infinity",
timeout: 10000,
transports: ["websocket"],
};
const ENDPOINT = "URL";
socket = io(ENDPOINT, connectionOptions);
So I've fixed my Problem.
The URL on the client side had to be without the Port.
So for example:
const ENDPOINT = "https://web.site.com";
and not:
const ENDPOINT = "https://web.site.com:1337";
Call socket.connect() or just add autoconnect: true in options you are providing.

Express.js. How to generate a valid ssl certificate?

I have a production ready express server. And 2 webapps working with it.
The express server is in the port : 1111
I have created two letsencrypt ssl for my nginx server, and im using it with the frontend sites for app.domain.com and domain.com, it works fine.
The point is that the backend isnt reached because it must be ssl too. But... how do I setup a valid ssl for my backend? I mean I cant do it with letsencrypt because its a backend server and it doesn't have ssl.
I have tried using the same certificates that i generated for domain.com in the express server using basically this code taken from other site
// Dependencies
const fs = require('fs');
const http = require('http');
const https = require('https');
const express = require('express');
const app = express();
// Certificate
const privateKey = fs.readFileSync('/etc/letsencrypt/live/yourdomain.com/privkey.pem', 'utf8');
const certificate = fs.readFileSync('/etc/letsencrypt/live/yourdomain.com/cert.pem', 'utf8');
const ca = fs.readFileSync('/etc/letsencrypt/live/yourdomain.com/chain.pem', 'utf8');
const credentials = {
key: privateKey,
cert: certificate,
ca: ca
};
app.use((req, res) => {
res.send('Hello there !');
});
// Starting both http & https servers
const httpServer = http.createServer(app);
const httpsServer = https.createServer(credentials, app);
httpServer.listen(80, () => {
console.log('HTTP Server running on port 80');
});
httpsServer.listen(443, () => {
console.log('HTTPS Server running on port 443');
});
But it worked randomly, a lot of times the request timed out because it took forever, and other times it worked, it was weird.
But now it suddenly even stopped working, so I dont know what to do there.
What type of certificate do I have to use?
Self signed ones are rejected by chrome, and I donty know how else to generate a letsencrypt one, if the express node server is running in an ip not a domain
Okey, the problem was with my nginx virtualhosts. I created a virtualhost api.domain.com
server
{
listen 443;
listen [::]:443;
server_name api.domain.com;
location /
{
proxy_pass https://127.0.0.1:1111;
}
}
And then run
sudo certbot --nginx -d api.domain.com
Then it started to work

node.js https server not loading responding

I am trying to start a https node.js server.
I started by creating a certificate and key following this guide:
http://gaboesquivel.com/blog/2014/nodejs-https-and-ssl-certificate-for-development/
and I placed them in my /app_name/security/keys directory.
To start my https server, I have the following:
const https = require('https'),
fs = require('fs');
if(app.get('env') === 'development') {
console.log('dev env!!'); //prints correctly
console.log('port: ' + port); //prints correctly
const options = {
key: fs.readFileSync('./security/keys/key.pem'),
cert: fs.readFileSync('./security/keys/cert.pem')
};
https.createServer(options, (req, res) => {
console.log('https good to go'); //this does not print out anything
}).listen(port);
}
When I go to https://localhost:3000, the page throws an error
This site can’t be reached
localhost unexpectedly closed the connection.
ERR_CONNECTION_CLOSED
But there's no error on the server side console. Furthermore, if i go to the regular localhost:3000, I get:
The localhost page isn’t working
localhost didn’t send any data.
ERR_EMPTY_RESPONSE
Can someone help?
Thanks in advance!
---- UPDATE ----
I'm running on port 443 now. Initially I got an error:
Error: listen EACCES 0.0.0.0:443 so I ran:
sudo NODE_ENV=development nodemon app
Which did not throw any errors. However, when I went to https://localhost:443, I get:
This site can’t be reached
localhost unexpectedly closed the connection.
I used express as a web server.
to install express:
npm install express --save
I took your code, added the usage in express, generated certificate using openssl, and executed it - all looked good, the server was up, listening to port 3000 over https.
My code (which is based on your code...):
var app = require('express')();
const https = require('https'),
fs = require('fs'),
port = 3000;
if(app.get('env') === 'development') {
console.log('dev env!!'); //prints correctly
console.log('port: ' + port); //prints correctly
const options = {
key: fs.readFileSync('/tmp/private.key'),
cert: fs.readFileSync('/tmp/publickey.crt')
};
https.createServer(options, (req, res) => {
console.log('https good to go'); //this does message appears!!! ^_^
}).listen(port);
}
Please pay attention to the way I defined app: var app = require('express')();
You can split this definition into two line if it's more readable:
var express = require('express');
var app = express();
So many problems with your code.
I tested this really quickly.
the keyword app and port is not defined, lines 4 and 7 respectively.
That will throw you a syntax error, preventing the code from continuing any further therefore server not starting up at all.
As I mentioned on my comment, use devtool to debug and use the following line on a CLI devtool server.js -w where the -w watches for file changes and reloads the server on the fly, while developing.
also assuming you named your entry file server.js

Resources