node.js hosting with SSL? - node.js

So say I have a node.js application that hosts both a HTTP and HTTPS server as described in the question: How to force SSL / https in Express.js
In my code I have the following:
// General configuration settings for production usage
app.configure(function () {
app.set('port', process.env.PORT || 3000);
app.set('sslport', process.env.SSLPORT || 4000);
...
}
http.createServer(app).listen(app.get('port'), function () {
winston.info('Express server listening on port ' + app.get('port'));
});
var options = {
key: fs.readFileSync('key.pem'),
cert: fs.readFileSync('cert.pem')
};
https.createServer(options, app).listen(app.get('sslport'), function () {
winston.info('Express server listening on port ' + app.get('sslport'));
});
Which works perfectly fine for a local running node server.
However, I want to publish my site to a cloud hosted provider like Azure Web Sites, Heroku, Nodejitsu, etc.
All of the cloud hosts seem to set a process.env.PORT value, but only the one. When my HTTPS server is created this usually results in the app crashing, as the PORT is already in use / access denied / etc.
So how do I create / host a site with a secure login page with only one port to work with!?

If you use Heroku you get SSL without needing to specify a port in nodejs. All you need to do is listen on the heroku PORT environment variable for http requests. Once uploaded to heroku you can address your heroku app using either https (on 443) or http (on port 80). Heroku routes either to your server.
Similarly if using elastic load balancing with EC2 you can make use of SSL termination at the load balancer, and again route to your node server listening on port 80 using using http. http://aws.amazon.com/elasticloadbalancing
In both cases you can use either self-signed or proper SSL certificates depending upon your need.

Related

How to serve a nodeJS app via HTTPS on AWS EC2?

I'm trying to run a hello world express app on an EC2 instance and serve it via HTTPS.
Here is the server code:
var express = require('express');
var app = express();
app.get('/', function (req, res) {
res.send('Hello World!\n');
});
const server = app.listen(3000, function () {
console.log('Example app listening on port 3000!');
});
server.keepAliveTimeout = 65000; // Ensure all inactive connections are terminated by the ALB, by setting this a few seconds higher than the ALB idle timeout
server.headersTimeout = 66000; // Ensure the headersTimeout is set higher than the keepAliveTimeout due to this nodejs regression bug: https://github.com/nodejs/node/issues/27363
I created an EC2 instance and let it run there. Additionally to get HTTPS, I fired up an Application Load Balancer with an SSL certificate. I created a listener on port 443 and forwarded it to port 3000 on my EC2. Lastly I set up a Route53 entry to point to that ALB.
All I get 24/7 is 502 Bad Gateway. Am I missing something basic here?
How to run the most basic express server via HTTPS?
For anyone who might stumble upon this some time later:
If you wish to terminate HTTPS on the load balancer and speak HTTP to your app behind it you need to select HTTP as prototoll and the port of your node app when creating a target group in the console.
For some reason I thought for hours this should be HTTPS and 443 when I want to accept HTTPS traffic.

What is best practice node.js recommended port in production environment?

I have created a chat app in node.js using port 4000. Everything works just fine, but when I rolled it out in production, I found that many corporate networks block outgoing port 4000. I considered using other ports that would be more likely to be open on a corporate network, but then found this list of ports blocked by chrome browser:
https://superuser.com/questions/188058/which-ports-are-considered-unsafe-by-chrome
Using ports such as 995 would result in a chrome error of "ERR_UNSAFE_PORT"
So it appears that the only ports allowed are 80 and 443 for a node.js server? What is the recommended best practice for choosing a port for your node.js application in a production environment?
My webserver is already using ports 80 and 443 for typical apache web serving. Do I need to create a dedicated server just for node.js?
I am using the following code to initiate the connection from the browser to the node.js server:
var socket = io.connect('https://duplex.example.com:4000');
and here is the code on the server side:
const https = require('https');
const fs = require('fs');
var express = require('express')
, bodyParser = require('body-parser');
var socket = require('socket.io');
var adminid = '';
var clientlist = new Array();
var port = 4000;
const options = {
cert: fs.readFileSync('./fullchain.pem'),
key: fs.readFileSync('./privkey.pem')
};
var app = express();
var server = https.createServer(options, app).listen(port, function(){
console.log("Express server listening on port " + port);
});
443 and 80 are the main ports for https and HTTP traffic respectively.
other ports can be used for WebSockets, but that doesn't sound like your use case.
What I have done in the past is use a reverse proxy, to discriminate on the incoming URL, and map the ports internally on my machine without the client needing to know.
NGINX is usually the easiest bet for this if you are on any sort of linux distro.
here is a blog about how to setup reverse proxy for a node app using nginx.
http://thejonarnold.com/configure-sails-js-with-subdomains-on-ubuntu/
the article references sailsjs, but there is nothing framework specific about the techique.
Most people don't expose their Node.js server directly to the internet but use Apache or Nginx as a frontend proxy.
Have your server bind to localhost only (or use firewall rules to only allow incoming 80 and 443.
server.listen('localhost', 4000)
Configure your reverse proxy. I'm using Caddy:
example.com {
root /var/www/example.com
# et cetera
}
duplex.example.com {
proxy / localhost:4000 {
websocket
}
}
When proxying websocket, you need to ensure the Connection and Upgrade headers aren't lost, which I've done with Caddy's shortcut here.
You could also use the same domain as the main site and only proxy a certain path.
Have the client socket.io connect to wss://duplex.example.com (on port 443). (I'm not familiar with socket.io to say why it uses an HTTPS URL instead of WSS, but I'll assume you have that working.)

Formatting node apps for AWS deployment

I'm trying to deploy a node.js app on aws EC2 Beanstalk. My problem is, I can't figure out how to move from my localhost testing environment to aws standard. Right now, my app works on port 8081 by using the following code.
var server = app.listen(8081, function () {
var host = server.address().address
var port = server.address().port
})
How would I change this server variable to work on an actual domain?
Assuming your intent is to provide a public-facing web application, your code will work as is, albeit with a few caveats:
Currently your server will listen on port 8081. Once deployed to AWS users would have to browse to www.somedomain.com:8081 to reach your application. (Assuming the host instance allows traffic on that port. See below).
If your intent is to have users reach your application at www.somedomain.com - without specifying a port - you'll want the server to listen on port 80 instead.
var server = app.listen(80, function () { ... }
In either case you'll need to ensure that the security group rules for the EC2 host instance allow incoming TCP traffic on the listening port. Likewise, if your EC2 host instance is behind a load balancer you'll need to allow incoming traffic on the appropriate ports there as well.
For something a little fancier, you can try deploying your application to Elastic Beanstalk using Docker and exposing port 8081 in the dockerfile. This way users would still reach it at www.somedomain.com (via http port 80) and you could continue to develop and test locally using port 8081.
One final note: you didn't provide much information about what your application is or how you intend to use it, so I'm making quite a few assumptions based only on the information provided.
This code works great for me with node on Elastic Beanstalk, and allows me to seamlessly switch between localhost and remote development without changing any code:
var port = process.env.PORT || 8081;
var server = app.listen(port, function () {
//server is started!!!
})

Express ssl address

I am building an express app that will run on my local network. I just started using a self signed certificut and an https server instead of just an http server. Before I implemented https, I could go to my app with 192.168.1.66 (local ip). But after implementing https, I now have to type https://192.168.1.66:80, otherwise my browser says "connection was reset" or something similar.
Below is my server creation code:
var port = process.env.PORT || 80;//is always 80 since I have not
//set process.end.PORT
var server = https.createServer(sslOptions, app).listen(port, function(){
console.log("listening on port 80");
});
Any ideas why?
It looks like this was a firewall issue on linux. I had turned off ufw, but failed to restart afterwards. After restarting and confirming that the firewall was off, it worked fine :)

NodeJS listening on HTTP and HTTPS for one single domain name

I use express and a server cloud on AWS (Amazon Web Server) and a DNS "mydomain.com".
Question: how can I avoid my users to have to writing in the Browser-URL: http://mydomain.com:4000 and https://mydomain.com:3000
This is my code:
sudo node app.js
var app = express();
var server = http.createServer(app).listen(4000, function() {
console.log('Express HTTP server listening on port ' + app.get('port'));
});
var server = https.createServer(credentials, app).listen(3000, function() {
console.log('Express HTTPS server listening on port 3000');
});
// redirect all http requests to https
app.use(function(req, res, next) {
if(!req.secure) {
return res.redirect(['https://mydomain.com', req.url].join(''));
}
next();
});
I want my user to be able to write my domain name using http and https with no port numbers. I already have a SSL certificate and everything is working fine, but I haven't been able remove the port-numbers and use both: https and http.
Any idea? please :)
I use MEAN stack (Mongo, Express, Angular, )
The only way to do that is to use the default ports for the protocols. That is, Port 80 for HTTP and Port 443 for HTTPS.
If you don't use the default protocol ports then the only way for the browser (or whatever client the users are using) to determine which port to connect to is for the user to specify it in the URL.
Edit - To address your comment above about different server objects
In the code in your question you create an HTTP server and then use the variable server to hold a reference to the object. You then create an HTTPS server and assign it to the same variable. If you use the server variable later in your code then you'll be dealing with the HTTPS server object, but will have no way to reference the HTTP server object.
To fix this, just use two different variables to hold the object references.
var httpServer = http.createServer ....
var httpsServer = https.createServer ....

Resources