How to use HTTP/2 with Nest.js (Node) - node.js

I have read that Express 4.x is not compatible with Node.js native HTTP2 (from 8.4+), and I was hoping for more progess on Express 5.x than it has.
But as I started thinking that Express5.x will probably be released to late for my next Node.js project - I came over Nest.js.
Does anyone know if Nest.js can be used with native HTTP2 support ??
The only Node.js framework that I have heard of that supports this is Fastify.
Or are there any other out there ? Preferable one that support Express plugins.

You can use HTTP/2 (and SPDY) in NestJS using the node-spdy package:
Setup packages
yarn add spdy
yarn add -D #types/spdy
Generate certificate
H2 generally requires TLS, so generate a new key and certificate:
openssl req -x509 -newkey rsa:2048 -nodes -sha256 -keyout test.key -out test.crt
Modify startup
Next, modify main.ts:
// main.ts
async function bootstrap() {
const expressApp: Express = express();
const spdyOpts: ServerOptions = {
key: fs.readFileSync('./test.key'),
cert: fs.readFileSync('./test.crt'),
};
const server: Server = spdy.createServer(spdyOpts, expressApp);
const app: NestApplication = await NestFactory.create(
AppModule,
new ExpressAdapter(expressApp),
);
await app.init();
await server.listen(3000);
}
bootstrap();
Test client
$ curl -I -k https://localhost:3000/
HTTP/2 200
x-powered-by: Express
content-type: text/html; charset=utf-8
content-length: 12
etag: W/"c-Lve95gjOVATpfV8EL5X4nxwjKHE"
Notice HTTP/2 being sent in the response headers.

As Barry Pollard commented; using a webserver in front for static resources and the Webapp itself, and using Node.js for API purposes, is probably the best approach anyway.

Related

Creating a socket.io server for https connections

I have done instructions from this page: https://medium.com/#invingagan/an-express-https-server-with-a-self-signed-certificate-and-socket-io-42d1f02d4d1a
That is, I created a self signed certificate:
openssl req -nodes -new -x509 -keyout server.key -out server.cert
Then I use this server code:
var express = require('express');
var app = express();
var fs = require('fs');
app.use(express.static('public'));
const server = require('https').createServer({
key: fs.readFileSync('server.key'),
cert: fs.readFileSync('server.cert')
},
app);
var io = require('socket.io')(server);
server.listen(1437, function () {
console.log('https and websocket listening on *:1437');
});
However, when I try to connect using socket.io client, I got this error:
index.js:83 GET https://localhost:1437/socket.io/?framespersecond=15&audioBitrate=22050&EIO=3&transport=polling&t=NJLEHQL net::ERR_CERT_AUTHORITY_INVALID
If I just copy and paste the URL in the browser URL field, I received the same error, so this is not a problem of socket.io client but the server miss to configure something.
I tried by creating a CA file and specify it in the call to createServer but it did not work either.
Any help?
Jaime
It turned out there was a problem when generating the certificate using openssl.
I don't really know what happened, but since I have an already issued a self signed certificate (the one that is used by Visual Studio when developing sites to be debugged using IISEXPRESS), I have exported that certificate using Digicert utility and I could finally connect using socket.io.
Regards
Jaime

ERR_SSL_VERSION_OR_CIPHER_MISMATCH in node js

I recently purchased a personal ssl certificate from Positive ssl. After i got everything sorted out with activating it and the validation, I was finally able to download the certificate files.
The files i got were:
www.niknet.ddns.net.ca-bundle
www.niknet.ddns.net.crt
www.niknet.ddns.net.p7b
Before I only used .key and .crt
and it worked great but now i am using the .ca-bundle and the .crt file
this is the code i use to include those files into the ssl library in node js
var httpPort = process.env.PORT || 80;
var httpsPort = process.env.PORT || 443;
var server = http.createServer(app).listen(httpPort);
var server = https.createServer({
secureProtocol : 'TLSv1_2_server_method',
ciphers : "AES128-GCM-SHA256:RC4:HIGH:!MD5:!aNULL:!EDH",
honorCipherOrder : true,
ca: fs.readFileSync(__dirname + '/niknet_ddns_net.ca-bundle'),
cert: fs.readFileSync(__dirname + '/niknet_ddns_net.crt')
},app).listen(httpsPort);
var io = require('socket.io').listen(server);
but I can't for the life of me get the certificate to work properly.
I just get this error
ERR_SSL_VERSION_OR_CIPHER_MISMATCH
I've been reading other posts and have tried adding their code but nothing works.
I also read somewhere that the ssl or tls library for node.js is outdated and that my certificate could be too new. If that's true, are there any other third-party ssl libraries I could use?
run this command:
openssl req -nodes -new -x509 -keyout server.key -out server.cert
Just remember to set this to localhost:
Common Name (e.g. server FQDN or YOUR name) []: localhost
then
https.createServer({
key: fs.readFileSync('./ssl/server.key'),
cert: fs.readFileSync('./ssl/server.cert')
},app)
ERR_SSL_VERSION_OR_CIPHER_MISMATCH will appear if the added certificate are not indicated properly in the first argument of createServer().
tested key and crt with openssl using bellow command (try in browser https://hostname:8888).. and found the exact cipher missing.
openssl s_server -cert server.crt -key server.key -CAfile octopz.zende.sk.ca-bundle -accept 8888 -www
Then added to the nodejs code.
var server = https.createServer({
key: privateKey,
cert: certificate,
ca: certificateAuthority,
ciphers: [
"ECDHE-RSA-AES128-SHA256",
"DHE-RSA-AES128-SHA256",
"AES128-GCM-SHA256",
"RC4",
"HIGH",
"!MD5",
"!aNULL"
].join(':'),
}, app);
it worked!!
We have lots of dupes of this for other languages, but the closest I can find for nodejs is How to create an HTTPS server in Node.js? which is not specific or ERR_SSL_VERSION_OR_CIPHER_MISMATCH with node v7.9.0 https which is not answered. So:
SSL/TLS server including an HTTPS server needs a privatekey AND certificate/chain (with rare exceptions not applicable here). You can use a CA-issued cert (and chain) instead of a self-created (and usually self-signed) cert, as long as the CA-issued cert is for the same privatekey, but you must still provide the privatekey. You can use cert and key together, or you can combine the cert (and optionally chain) and key into a PKCS12-also-called-PFX file, and use pfx.
In addition to the Q you asked, and arguably offtopic for SO, don't use RC4. It's considered broken cryptographically, though still on average moderately difficult/costly in practice, and most standards for using SSL/TLS/HTTPS prohibit it for several years now, particularly rfc7465.

How to enable SSL connection a NodeJS (Express) based Server

Following is the script I found on NodeJS Official Website:
// curl -k https://localhost:8000/
const https = require('https');
const fs = require('fs');
const options = {
key: fs.readFileSync('test/fixtures/keys/agent2-key.pem'),
cert: fs.readFileSync('test/fixtures/keys/agent2-cert.pem')
};
https.createServer(options, (req, res) => {
res.writeHead(200);
res.end('hello world\n');
}).listen(8000);
I'm completely new to SSL thing. I read some tutorials on how to enable SSL on Nodejs but still quite not confident with the process.
I have a domain name (Godaddy), SSL (Namecheap) and Cloud Server (Digital Ocean with an application deployed on HTTP prefix).
Whenever I open my Login page of my website, Google Chrome mark it as "Not secure" so I wanted to add SSL to the website.
What things I need to do on the NodeJS server (Express) and what things I need to do on Namecheap? What will be the sequence of doing that? What are cmd lines to generate .pem .csr files?
I'm didn't found and comprehensive guide laying down all the steps in a concise manner so just laid down the steps concisely (if possible) with the links to the resources for further digging.
And also, how can I use express framework to create https server in liue of above script?
That script is correct for setting the certs for your https. If your site is public, as it seems, then you'll want to buy certs from your ssl service, Namecheap in your example. Then you would move them to your host and reference them in the options object in your example. However, you can generate your own ssl certs and that will work as well. Though, any users will be warned that they're not trusted since you self signed/created them. I suggest going with the Namecheap option.
Note: You only have an https server in your example and anyone attempting to access your site via http will receive a blank page. You'll need to also create an http server, via the following:
var http = require('http');
http.createServer(...);
I would suggest having the http server simply redirect to the https url.
My code and error is here:
no such directory found error:
key: fs.readFileSync('../private.key'),
cert: fs.readFileSync('../public.cert')
error, no such directory found
key: fs.readFileSync('./private.key'),
cert: fs.readFileSync('./public.cert')
Working code should be
key: fs.readFileSync(__dirname + '/private.key', 'utf8'),
cert: fs.readFileSync(__dirname + '/public.cert', 'utf8')
Complete https code is:
const https = require('https');
const fs = require('fs');
// readFileSync function must use __dirname get current directory
// require use ./ refer to current directory.
const options = {
key: fs.readFileSync(__dirname + '/private.key', 'utf8'),
cert: fs.readFileSync(__dirname + '/public.cert', 'utf8')
};
// Create HTTPs server.
var server = https.createServer(options, app);
This is my working code for express 4.0.
express 4.0 is very different from 3.0 and others.
4.0 you have /bin/www file, which you are going to add https here.
"npm start" is standard way you start express 4.0 server.
readFileSync() function should use __dirname get current directory
while require() use ./ refer to current directory.
First you put private.key and public.cert file under /bin folder,
It is same folder as WWW file.

Node auto reload code on https

I'm looking for a tool which can auto reload my node.js code but also can run on https for local development.
Both forever and nodemon can reload my code but can't run on https.
To generate a self-signed certificate, run the following in your shell:
openssl genrsa -out key.pem
openssl req -new -key key.pem -out csr.pem
openssl x509 -req -days 9999 -in csr.pem -signkey key.pem -out cert.pem
rm csr.pem
This should leave you with two files, cert.pem (the certificate) and key.pem (the private key). This is all you need for a SSL connection. So now you set up a quick hello world example (the biggest difference between https and http is the options parameter):
var https = require('https');
var fs = require('fs');
var options = {
key: fs.readFileSync('key.pem'),
cert: fs.readFileSync('cert.pem')
};
var a = https.createServer(options, function (req, res) {
res.writeHead(200);
res.end("hello world\n");
}).listen(8000);
NODE PRO TIP: Note fs.readFileSync - unlike fs.readFile,
fs.readFileSync will block the entire process until it completes. In
situations like this - loading vital configuration data - the sync
functions are okay. In a busy server, however, using a synchronous
function during a request will force the server to deal with the
requests one by one!
Reference : https://docs.nodejitsu.com/articles/HTTP/servers/how-to-create-a-HTTPS-server/

Setting up multiple HTTPS servers listening on the same port in Node

By not specifying a protocol, the following block will result in an HTTPS server that uses TLS 1.2:
var options = {
key: fs.readFileSync("security/server.key"),
cert: fs.readFileSync("security/server.crt")
};
https.createServer(options, app).listen(443);
However, one of my endpoints needs to act as a subscriber endpoint for the Fitbit API, which requires TLS 1.0. To do this, I need to set secureProtocol to TLSv1_method.
var options = {
key: fs.readFileSync("security/server.key"),
cert: fs.readFileSync("security/server.crt"),
secureProtocol: "TLSv1_method" // Fitbit subscription API requires TLS 1.0
};
https.createServer(options, app).listen(443);
What would be the best way to use TLS 1.0 for one endpoint and TLS 1.2 for all others? The answer may lie in the http-proxy module, but I'm having a hard time applying the documentation to my use case. Note that I am using different subdomains to differentiate the traffic.
If secureProtocol is not defined in the options, then by default node will create a https server that accepts connections on TLS 1.0, TLS 1.1 and TLS 1.2.
Example Server:
const https = require('https');
const fs = require('fs');
const options = {
key: fs.readFileSync('default-key.pem'),
cert: fs.readFileSync('default-cert.pem')
};
https.createServer(options, (req, res) => {
res.writeHead(200);
res.end('hello world\n');
}).listen(8000);
You can test this at the command line with curl:
Test for SSLv3 (will fail, it's disabled by default):
curl --sslv3 https://localhost:8000 -k
Test for TLSv1 (will work):
curl --tlsv1.0 https://localhost:8000 -k
Test for TLSv1.1 (will work):
curl --tlsv1.1 https://localhost:8000 -k
Test for TLSv1.2 (will work):
curl --tlsv1.2 https://localhost:8000 -k
Tested on node.js version 5.3.0 and 5.5.0 (latest stable).

Resources