How to enable SSL connection a NodeJS (Express) based Server - node.js

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.

Related

Config Self-Signed Cert to work with node,js

So I am currently working on a project that is looking to add SSL security to an web-app running on node.js that is being contained inside a Ubuntu core snap.
I am not a programmer so I am struggling to find a way to have the the app use the cert, let alone find a way to include it in the snap so that it will be part of the snap install process.
I understand that this might have to be separate processes but not having adequate footing to start from is making that hard to see.
Any direction in this would be helpful.
I think, Snaps are containerised software packages that are simple to create and install, which are similar to apt, yum, dnf, pkg. I'm not sure how it is linked to running Node.js server on SSL. TO run node server on SSL, you need to create or have SSL certificates. You can do something like this:
var https = require('https');
var fs = require('fs');
var https_options = {
key: fs.readFileSync("/path/to/private.key"),
cert: fs.readFileSync("/path/to/your_domain_name.crt"),
ca: [
fs.readFileSync('path/to/CA_root.crt'),
fs.readFileSync('path/to/ca_bundle_certificate.crt')
]
};
https.createServer(https_options, function (req, res) {
res.writeHead(200);
res.end("Welcome to Node.js HTTPS Servern");
}).listen(80)

How to automatically reload updated SSL certificates in Node.js Application

I created nodejs application and I'm using Lets Encrypt SSL certificates. Following is my Code
var express = require(‘express’);
var https = require(‘https’);
var fs = require(‘fs’);
var option = {
key: fs.readFileSync(‘/etc/letsencrypt/live/$DOMAIN/privkey.pem’),
cert: fs.readFileSync(‘/etc/letsencrypt/live/$DOMAIN/fullchain.pem’)
};
const app = express();
app.use((req, res) =>
{
res.end(‘Hello World’);
});
https.createServer(option, app).listen(8000);
I have used pm2 to start this application using following command
sudo pm2 start app.js --watch
I am updating SSL certificates by using following cronjob
0 8 * * * sudo certbot renew
I want to reload SSL certificates automatically whenever certbot renews SSL certificates. How can I achieve this?
You can use the flag --post-hook to restart your application after every renewal.
certbot renew --post-hook "pm2 restart app_name"
Update #1
Please note that the command we are running is in crontab and any global program has to be referenced with the full path. You can use the which command to find the executable file path for the command.
For those of us who can't afford to or would rather not restart our servers to reload certs and that aren't comfortable with Dylan Landry's SNI-based approach, there has been a purpose-built way of doing this built into node for a while now, via server.setSecureContext (where server is a standard node https server instance). See snippet below:
const app = express();
function readCertsSync() {
return {
key: fs.readFileSync(sslKeyPath),
cert: fs.readFileSync(sslCertPath) + fs.readFileSync(sslFullChainPath)
}
}
let httpd = https.createServer(readCertsSync(), app).listen(port, onReady);
// Refresh httpd's certs when certs change on disk. The timeout stuff
// "ensures" that all 3 relevant files are updated, and accounts for
// sometimes trigger-happy fs.watch.
let waitForCertAndFullChainToGetUpdatedTooTimeout;
fs.watch(sslKeyPath, () => {
clearTimeout(waitForCertAndFullChainToGetUpdatedTooTimeout);
waitForCertAndFullChainToGetUpdatedTooTimeout = setTimeout(() => {
httpd.setSecureContext(readCertsSync());
}, 1000);
});
The fs.watch and timeout code is admittedly a bit clunky and can be improved using something like chokidar and some more expansive logic to monitor the state of all 3 relevant files. I chose to keep things simple to focus on the interesting bit: setSecureContext.
For reference, see https://nodejs.org/api/tls.html#tls_server_setsecurecontext_options
Also, credit goes to nolimitdev who came up with most of this before setSecureContext was even a thing.
You can reload the new certs without restarting your server.
According to the issue Reload certificate files of https.createServer() without restarting node server #15115 , specifically this comment from mscdex:
FWIW you can already do this with SNICallback():
const https = require('https');
const tls = require('tls');
const fs = require('fs');
var ctx = tls.createSecureContext({
key: fs.readFileSync(config.sslKeyPath),
cert: fs.readFileSync(config.sslCrtPath)
});
https.createServer({
SNICallback: (servername, cb) => {
// here you can even change up the `SecureContext`
// based on `servername` if you want
cb(null, ctx);
}
});
With that, all you have to do is re-assign ctx and then it will get used for any future requests.
Using the example above, you just need to do fs.readFileSync again on the cert path from within the SNICallback and attach them to the ctx object. But, you only want to do this when you know they've just changed. You can watch the files from javascript for changes. You can use fs.watch() for that or something from npm.

Issue from HTTPS installation in node js

I am using https package for running the program in https. I have proper ssl certificate and private key and bundle file. all these files included in my code. This https program also running without error. But when I connect front end to node js it doesn't connected. The error is "504 gateway Time out". Where is I make error? I host my code in azure.
const https = require('https');
//path for private key and certificate
let privateKey = fs.readFileSync('sslcert/server.key','utf8');
let certificate = fs.readFileSync('sslcert/server.crt','utf8');
var credential = {
key: privateKey,
cert: certificate,
};
var server = https.createServer(credential, app)
server.listen('8443',function() {
console.log('Listening on https://localhost:' + 8443);
});
Refer to this https://nodejs.org/api/net.html#net_server_listen_port_host_backlog_callback
So if you do not declare host for your server.listen() the default host should be 0.0.0.0 instead.
If you need to listen of specific address, you must define it after the port.
http.createServer(function (req, res) {
}).listen(8443, "0.0.0.0");
Your front server need to be on the same network subnet as your API.

Encrypting content sent with Node.js

I am trying to get HTTPS up on my node.js application. I made progress on this by creating certAccess group that contains both root and ec2-user, and then saying sudo chown ec2-user.certAccess /etc/pki/tls/private/serverKey.key. However, when I run this dummy code:
var fs = require('fs');
var https = require('https');
var app = require('express')();
var options = {
key : fs.readFileSync('/etc/pki/tls/private/serverKey.key').toString(),
cert : fs.readFileSync('/etc/pki/tls/certs/2_mikewarren.me.crt').toString()
};
app.get('/', function (req, res) {
res.send('Hello World!');
});
https.createServer(options, app).listen(8080, function () {
console.log(JSON.stringify(options, null, '\t'));
console.log('Started!');
});
and test it out in my browser (use <yourDomain>:8080), I get no response from server.
I go in and see the permissions of my private key and certificate, and see this:
The private key and certificate configuration, located in /etc/httpd/conf.d/ssl.conf looks like:
However, when I do the test in my browser (even typing https:// in front of the URL, which I shouldn't have to), I get no response from server.
What should I do?!?!?
I came up with solution. Here's what I did:
I added ca member to options and pointed to that chain cert as it, like this: ca : fs.readFileSync('/etc/pki/tls/certs/1_root_bundle.crt', 'utf8'). That solves the cert problem. As for the next part, I simply wrote line in BASH that redirects https (port 443) to the port I was using (which I, out of convenience, changed to 8443, because I already redirected http to 8080).
That got it working, but it still sucks that I have to still prefix URL with https://. I shouldn't have to! I think solution to that is to do what I already have done, but redirect http to port 8443, or proxy port 8080 to port 8443.

Problems installing SSL Certificates on Node.JS server

I bought SSL Certificates from Godaddy for our website, with two web servers on the same AWS EC2 instance - Apache Tomcat and Node/Express.
After installing the SSL Certificates on both the web servers, https://example.com is opening (Apache), but the GET request from Apache to Node is failing.
The GET request to Node is working fine with the self-generated certificate (though it shows a crossed out https). When we replace that with CA certificates, it is not working. Please see the relevant code below.
var https = require("https"); // https server core module
var fs = require("fs"); // file system core module
var express = require("express"); // web framework external module
// Setup and configure Express http server. Expect a subfolder called
“static” to be the web root.
var httpApp = express();
httpApp.configure(function() {
httpApp.use(express.static(__dirname + "/static/"));
});
// Start Express https server on port 443
var webServer = https.createServer(
{
key: fs.readFileSync("/pathtokeys/ssl.private.key"),
cert: fs.readFileSync("/pathtokeys/1.crt"),
cert: fs.readFileSync("/pathtokeys/2.crt"),
cert: fs.readFileSync("/pathtokeys/3.crt"),
passprase:"miljul123$$$"
},
httpApp).listen(4431);
// Start Socket.io so it attaches itself to Express server
var socketServer = io.listen(webServer, {"log level":1});
var rtc = apsrtc.listen(httpApp, socketServer);
Any thoughts or suggestions? Thanks.

Resources