Express Web API https server crashing on first request - node.js

I am running a development Web API server on Node.js in Express environment. The server uses the Greenlock module for automatic Let's Encrypt certificate issuance.
When I run npm start prod, de server starts successfully and from the console log I can see that the server is listening on ports 80 and 443 for https connections:
Listening on 0.0.0.0:80 for ACME challenges, and redirecting to HTTPS
Listening on 0.0.0.0:443 for secure traffic
Ready to Serve:
web*****.club
ACME Directory URL: https://acme-v02.api.letsencrypt.org/directory
The NameSilo domain web*****.club points to my router's public ip address through an A record, and in the router, port 443 is mapped to port 443 and forwarded to one of the computers on my LAN where the API server resides.
As soon as I make a https API request from a webpage, the server crashes and it produces the following output:
Error cert_issue:
read ECONNRESET
code: ECONNRESET
Error: read ECONNRESET
at TCP.onStreamRead (internal/stream_base_commons.js:209:20)
The certificate issuance seems to be ok, because in the .config/acme dir the Let's Encrypt certificate with the private and the public key is added directly after the https request.
(Edit)
The server works, when accessed over https locally, and also when accessed locally over http.
It now also works from the domain name. I made a https server for port 443, without Greenlock, issued certificate cert.key/pem with help of openssl:
openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout cert.key -out cert.pem -sha256
used the following code in server.ts:
const express = require('express');
var app = require("../dist/app.js");
const https = require('https');
const fs = require('fs');
const port = 443
const httpsOptions = {
key: fs.readFileSync('./security/cert.key'),
cert: fs.readFileSync('./security/cert.pem')
}
const server = https.createServer(httpsOptions, app)
.listen(port, () => {
console.log('https server running on localhost at ' + port)
})
Thanks for your assistance!

Related

How to run NODE.JS (Socket.io) - CENTOS 7 with SSL domain?

My socket.io project "xampp" works fine for localhost.
I have a Centos 7 (cPanel) server. I did everything when I threw files into my server. I wrote the command "nodemon server.js" and the server is running. But I am having SSL-related problems with Client.
My site has SSL. I'm using CloudFlare. For this reason, the client cannot communicate with the server.
My project is running when I disable SSL.
How does Socket.io work with SSL?
CLOUDFLARE:
CHROME CONSOLE LOG:
Client CODE:
var socket = io.connect('https://example.com:1347');
Server.js CODE
var server = require('https').createServer(),
io = require('socket.io')(server),
port = 1337;
server.listen(port);
Firstly if you use CloudFlare. You should know SSL Ports.
HTTPS ports supported by Cloudflare:
443 2053 2083 2087 2096 8443
Use whichever port is empty on your server. Recommended: (8443)
Connect to your server with PUTTY. Then locate the directory of the domain on your server. If you are using cpanel. Follow this road.
cd /home/domainname/public_html
You will come to the site's home directory.
Then you need to create the necessary files for SSL to the server. Enter the individual commands below.
openssl genrsa -out privatekey.pem 2048
openssl req -new -key privatekey.pem -out certrequest.csr
openssl x509 -req -in certrequest.csr -signkey privatekey.pem -out certificate.pem
Client CODE:
var socket = io.connect('https://example.com:8443', {secure: true});
Server.js CODE
var fs = require('fs');
var https = require('https');
var options = {
key: fs.readFileSync('privatekey.pem'),
cert: fs.readFileSync('certificate.pem')
};
var server = https.createServer(options);
var io = require('socket.io').listen(server);
var port = 8443; // Enter any of the cloudflare ports.
server.listen(port, function(){
console.log('listening : ' + port);
});

Difference between https://<ip> and <ip>:443

I'm currently trying to understand the difference between 2 similar curl commands.
I spun up an AWS EC2 Ubuntu instance, and installed node.js on the instance. I then created a new directory called test-server. From within this directory, I ran npm init, then npm install express. I then wrote a simple web listener called test-server.js, which looks like this:
const express = require('express')
const app = express()
app.get('/', function(req, res){
console.log('Got a request!')
res.send('Request received!\n')
})
app.listen(443, function(){
console.log('Server started')
})
Finally, I started the server with the command sudo node test-server.js, and the server started successfully.
Using aws ec2 authorize-security-group-ingress, I allowed communication from my local IP address to the instance over port 443. I then attempted to test the connection using the following 2 curl commands: curl <ip>:443 and curl https://<ip>. The first command gave the expected output of Request received!. However, I received this error from the second command: curl: (35) OpenSSL SSL_connect: SSL_ERROR_SYSCALL in connection to <ip>:443.
Now, I'm FAR from a networking expert, but I would have expected both of these commands to function in the same way. Based on this result, I have 2 questions:
What is the difference between these 2 commands?
How can I change the configuration such that the second command works as well as the first?
Your application is serving regular HTTP on 443 port. In order to use https protocol you need to use encryption keys
var fs = require('fs');
var http = require('http');
var https = require('https');
var privateKey = fs.readFileSync('sslcert/server.key', 'utf8');
var certificate = fs.readFileSync('sslcert/server.crt', 'utf8');
var credentials = {key: privateKey, cert: certificate};
var express = require('express');
var app = express();
app.get('/', function(req, res){
console.log('Got a request!')
res.send('Request received!\n')
})
var httpsServer = https.createServer(credentials, app);
httpsServer.listen(443);
Command curl <ip>:443 is opening http connection to port 443 on givenip,curl https://<ip> is opening https connection to given ip.
If you want your traffic to be encrypted, stick to https:// version (and expanded code for server).
What is the difference between these 2 commands?
:443 is simply the port configuration, no different than :80. It just tells the server to serve content on that port. 443 is traditionally the port reserved for HTTPS connections, similar to how 80 is traditionally standard HTTP.
How can I change the configuration such that the second command works as well as the first?
You'll need to install a TLS cert. HTTPS indicates that a certificate is being used to secure the connection, and the absence of that certificate will cause the request to fail.

Running a simple HTTPS Node JS Server on Amazon EC2

I'm trying to create a simple https server on Amazon EC2 to test a third party API.
Here are the steps I've followed:
Created an Amazon EC2 instance, and opened up HTTP and HTTPS ports:
Created simple ssl credentials using
openssl genrsa 2048 > privatekey.pem
openssl req -new -key privatekey.pem -out csr.pem
openssl x509 -req -days 365 -in csr.pem -signkey privatekey.pem -out
server.crt
Created a simple node js server
var https = require('https');
var fs = require('fs');
var options = {
key: fs.readFileSync('./privatekey.pem'),
cert: fs.readFileSync('./server.crt')
};
https.createServer(options, function (req, res) {
res.writeHead(200);
res.end("hello world\n");
}).listen(8080);
When I run the server, and attempt to connect to it using url https://ec2-XX-XXX-XXX-XXX.compute-1.amazonaws.com/, I keep getting a connection refused.
A telnet test also produces:
Trying XX.XXX.XXX.XXX...
telnet: connect to address XX.XXX.XXX.XXX: Connection refused
telnet: Unable to connect to remote host
Can someone please tell me what I need to fix to enable https on this EC2 instance?
Change your listen(8080) to listen(443) unless you have a web server listening on 443 and sending request to node on 8080.

Node.js can't reacive data from telegram bot websocket

I am trying to set up a telegram bot with nodejs https server with self singed certificate.
ssl certificate:
openssl req -newkey rsa:2048 -sha256 -nodes -keyout key.pem -x509 -days 365 -out crt.pem -subj "/C=IR/ST=A.Sh/L=Tabriz/O=DominoSystem/CN=5.235.36.42"
The very simple server:
var options = {
key : fs.readFileSync(__dirname + '/key.pem'),
cert: fs.readFileSync(__dirname + '/crt.pem')
};
https.createServer(options, function (req, res) {
console.log('https server');
console.log(req.url);
res.end('yoo hooo');
}).listen(8443,'0.0.0.0');
The server is accessible from internet : https://5.235.36.42:8443/
Telegram bot setWebhook returns ok {"ok":true,"result":true,"description":"Webhook was set"}
I can see in my filewall logs and DU Meters "Open TCP Connections" that nodejs.exe is receiving a connection from one of telegram's data centers and it always have the status ESTABLISHED and sometimes SYN_RCVD and then closes with send&receive=0KB but my nodejs server is not receiving any requests.
I have allowed my firewall(Comodo) to ACCEPT all incoming connections on port 8443.
I have been bashing my head around for 2 days now :( can someone help me pliz...
Windows 8.1 x64, Nodejs 5.9.1
OK, fixed it myself, it seems that Telegram didn't like the certificate generated by openssl on windows (8.1).
I generated the certificate on my linux (CentOS6) server and now it works :D, both in the server and in the local dev machine.

Installing SSL Certificate On Node Server

I created a self-signed certificate and installed it on apache as well as on node.js(port 3000). On localhost both https://localhost and https://localhost:3000 works well.
So, I bought GoDaddy Standard SSL certificate and installed it on the server(http://gatherify.com). Now https://gatherify.com works well, but ssl on node isn't working.
When I access https://gatherify.com:3000 i get "The connection was interrupted".
I executed curl:
root#host [~]# curl -v -s -k https://gatherify.com:3000
* About to connect() to gatherify.com port 3000 (#0)
* Trying 108.160.156.123... connected
* Connected to gatherify.com (108.160.156.123) port 3000 (#0)
* Initializing NSS with certpath: sql:/etc/pki/nssdb
* warning: ignoring value of ssl.verifyhost
* NSS error -5938
* Closing connection #0
* SSL connect error
Any suggestions to fix this?
UPDATE
*SERVER SIDE :*
var io = require('socket.io'),
connect = require('connect'),
fs = require('fs'),
var privateKey = fs.readFileSync('cert/server.key').toString();
var certificate = fs.readFileSync('cert/server.crt').toString();
var options = {
key: privateKey,
cert: certificate
};
var app = connect(options).use(connect.static('../htdocs/node/'));
app.listen(3000);
var server = io.listen(app);
server.sockets.on('connection', function(socket) {
console.log("Connected");
});
CLIENT SIDE:
<html> <head>
<script type = "text/javascript" src = "https://gatherify.com:3000/socket.io/socket.io.js"></script>
<script type = "text/javascript">
var socket = io.connect('https://gatherify.com:3000', {secure:true});
</script>
</head><body></body></html>
If you want to run a node.js app on port 3000 with (behind) HTTPS, then you need to set up a proxy service on port 443 to proxy HTTPS requests to port 3000.
You didn't mention what server you have running on port 443 right now (is it Apache?) but you might want to
move that service to a new port (e.g. 4000), then run a node http proxy on port 443 that handles HTTPS.
Then set up a subdomain for the node.js app that you have running on port 3000 (e.g. blah.gatherify.com).
Then, using node http proxy, you will proxy all requests that are made to "gatherify.com" to port 4000, and all requests that are made to "blah.gatherify.com" to port 3000.
When all is set up properly, users can visit "https://gatherify.com" or "https://blah.gatherify.com" (without using :port numbers) and it'll all be secured with SSL. ;)
Install certificates Client Side (in Node.js)
If you need a node.js client to be able to recognize your self-assigned or cheaply-bought SSL certificates you can use ssl-root-cas, which is available on npm.
'use strict';
var https = require('https')
, cas
;
// This will add the well-known CAs
// to `https.globalAgent.options.ca`
require('ssl-root-cas').inject();
cas = https.globalAgent.options.ca;
cas.push(fs.readFileSync(path.join(__dirname, 'ssl', '01-cheap-ssl-intermediary-a.pem')));
cas.push(fs.readFileSync(path.join(__dirname, 'ssl', '02-cheap-ssl-intermediary-b.pem')));
cas.push(fs.readFileSync(path.join(__dirname, 'ssl', '03-cheap-ssl-site.pem')));
This will make your certs available to the core https module as well as modules that depend on it such as request and socket.io-client without deleting the normal ssl certs (which is the default behavior for some odd reason).

Resources