How do you write an SSL redirect in NodeJS running on AWS EC2 without using port 80 (http) or port 43 (https)? - node.js

I have two node servers on a single host. One HTTP server with the responsibility of redirecting to HTTPS, and one HTTPS server responsible for serving my application:
const express = require('express');
const https = require('https');
const http = require('http')
const fs = require('fs');
const app = express();
const httpsOptions = {
key: fs.readFileSync('./local-ssl/key.pem'),
cert: fs.readFileSync('./local-ssl/cert.pem'),
passphrase: '*****'
}
//other stuff
http.createServer(function (req, res) {
res.writeHead(301, { "Location": "https://" + req.headers['host'] + req.url });
res.end();
}).listen(80);
https.createServer(httpsOptions, app).listen(443)
This works great locally.
The issue is, when I deploy this code and run these servers on AWS EC2 you cannot start servers on ports 80 and 443. I am trying to figure out how I can get around this issue. If I run them on different ports, the servers will not respond, and worse, redirect incorrectly.
Example:
If I serve HTTP on 8081 and HTTPS on 8443, when a redirect occurs, the code redirects to
https://my-fun-url.com:8081
which of course does not work because I am not responding to HTTPS on port 8081.
Now, I've explored the option of port forwarding, but how would this work? If I forward ports 80 and 443 to internal ports (let's say) 3000 and 4000 the same redirection problem will occur.
I have scoured the internet for so long and to me this is a simple requirement for any web-app. I would very much appreciate some detailed guidance on my strategy.

If you want to keep ports 8081 and 8443, then you simply replace 8081 with 8443 in the host header:
httpsHost = req.headers.host.replace('8081', '8443');
res.writeHead(301, {
"Location": "https://" + httpsHost + req.url
});
Now, I've explored the option of port forwarding, but how would this work? If I forward ports 80 and 443 to internal ports (let's say) 3000 and 4000 the same redirection problem will occur.
Not exactly. When someone navigates to http://my-fun-url.com (80) the request is forwarded to 3000. Your http server will respond with a redirect to https://my-fun-url.com (443) which will be forwarded to 4000, and the https server will take it from there.
The difference between the two methods is that with ports 80 and 443 being the default, they are implied and therefore can be left out from the host part of the URL. Which makes the redirect easier as there's no port in the host to replace in the first place, just the protocol part (HTTP/HTTPS).

Related

Why do I have to type the ":80" in https://localhost:80 for my website to load?

I recently secured my website on node.js to use https instead of just plain http. However, once I did this, I realized that I had to type out the :80 suffix if I wanted to get to my website to load. Why is this? Doesn't chrome default to port 80 and shouldn't https://localhost suffice?
const port = 80;
https.createServer({
key: fs.readFileSync('./private/ssl/server.key'),
cert: fs.readFileSync('./private/ssl/server.cert')
}, app)
.listen(port, function () {
console.log('Server running on port: ' + port);
});
app.get('/', (req, res) => {
res.sendFile('index.html', { root: path.join(__dirname, './') });
});
app.use(express.static('./public'));```
The default port for HTTPS is 443, not 80.
Be aware that HTTPS uses port 443 by default, and that's probably the source of your confusion.
If you specify both https and :80 in your browser's address bar, you are making an HTTPS request to port 80, which is unusual.
What kind of reply you will be getting depends on your server's configuration.

Openshift - port to use on deployment

I have the following start.js file:
var express = require('express');
var app = express();
app.use(express.static('static'));
var server = app.listen(8080, function () {
var host = server.address().address;
var port = server.address().port;
console.log('Example app listening at http://%s:%s', host, port);
});
In my NodeJs application on Openshift. However, when I run rhc tail-a app-name
I can see that there is an error of :
Error: listen EADDRINUSE :::8080
I've tried 80 and 443, and received those errors:
Error: listen EACCESS 0.0.0.0:443
Or 80
Which port should I use as default on my app?
Thanks!
Use Nginx,
Nginx (pronounced "engine x") is a web server. It can act as a reverse proxy server for HTTP, HTTPS, SMTP, POP3, and IMAP protocols, as well as a load balancer and an HTTP cache.
It isn't good practice to run your application with root privileges or directly run your application on port 80 and your port 8080 is in use. Try different port and use reverse proxy.
But if you want to run on port 80 or 443, run your application with root privileges.

Having express.js or node accept an http connection over port 443

I have a REST API built with node that communicates over SSL. The server is built uses express and makes use of vhosts and cors. I have recently added a listener on port 80 as well so I can force HTTPS. As I test, I tried to access http://manage.domain.com:443/ but the request just hangs. Neither listeners seem to accept it. All I want to do is redirect that request to https.
I assume you already know this, but you'll need an https server (duh) to serve the HTTPS content. It doesn't matter what port you run it on; 443 is just the default port for HTTPS. If you want HTTP requests to redirect to HTTPS, you'll need both an http and an https server. Here's an example of how your app file should look:
var http = require('http'),
https = require('https'),
express = require('express')
fs = require('fs');
var domain = 'localhost';
var app = express();
app.get('*', function(req, res){
// redirect to HTTPS
res.redirect('https://' + domain + req.path);
});
http.createServer(app).listen(80, function(){
console.log('HTTP listening on port 80');
});
var appSecure = express();
// configure your app here
var options = {
key: fs.readFileSync('ssl_key.pem'),
cert: fs.readFileSync('ssl_cert.crt'),
};
https.createServer(options, appSecure).listen(443, function(){
console.log('HTTPS listening on port 443');
});
Obviously, you will need your SSL key and certificate to make this work.
As you probably know, most systems require elevated privileges to open a port less than 1025; so if you use port 80 and port 443, you'll have to run the app server with elevated privileges (if you're running on OSX/Linux/BSD, just do sudo node app.js).

HTTPS on Nodejitsu using Express

Okay. I have an app on express which also uses Socket.io and works fine via HTTP. However, now I have to move to HTTPS. Nodejitsu provide a lot of documentation on this. They suggest to use node-http-proxy (https://github.com/nodejitsu/node-http-proxy). Fine!
From the code for HTTP:
var server = http.createServer(app) // app is an Express instance
server.listen(config.port,config.hostip) // config.port is 80 for localhost and 3000 for Nodejitsu, config.hostip is 127.0.0.1 for localhost and 0.0.0.0 for Nodejitsu
I got this:
var server = http.createServer(app)
var options = {
https: {
key: fs.readFileSync(__dirname+"/ssl/privatekey.pem", 'utf8'),
cert: fs.readFileSync(__dirname+"/ssl/certificate.pem", 'utf8')
}
}
httpProxy.createServer(config.port, config.hostip, options).listen(3001,config.hostip)
var proxy = new httpProxy.HttpProxy({
target: {
host: config.hostip,
port: config.port
}
})
https.createServer(options.https, function (req, res) {
proxy.proxyRequest(req, res)
}).listen(3002,config.hostip)
server.listen(config.port,config.hostip)
When I finally deploy (no errors during deployment), I visit the page and see 502 error Socket hang up. OK, I might doing something wrong, so I just copy and paste the example from https://github.com/nodejitsu/node-http-proxy "Proxying to HTTP from HTTPS" to check if it works. But it doesn't - 502 error.
It works fine on my localhost though. I have also tried to launch standalone HTTPS server without node-https-proxy, but no luck. Please help, I cannot solve this for weeks.
Found by myself. Nodejitsu offers SSL by default, just visit your site via HTTPS://. For custom domains to apply SSL certs you need to subscribe for Business Plan.

EC2 hosted Node.js application - can't remotely connect to port

Update: Turns out the only problem was that I was behind a firewall that blocked some ports, but not 8000.
Edit: TL;DR: can't connect to port 9000 remotely, but port 8000 is ok and I don't know why :(
I've got this node.js application that's running on port 8000 and another one (http-proxy) running on port 9000.
Running them on my machine is fine, but I have some problems when I put them up on a server (EC2 instance - I did open the ports in the web console security group[1]). The application works fine, but I can't connect to the proxy from outside. I tried to $ telnet localhost 9000 on the server and it connects, so I guess that's a good sign.
Another thing that I have noticed is that if I try to run the applications separately, I get the same results, i.e.: 8000 - OK, 9000 - NOTOK :<.
However, if I change the port the proxy uses from 9000 to 8000, it works. And if I switch the ports, i.e. application:9000 and proxy:8000, I can connect to the proxy, but not to the application. I have also tried other numbers, but that wouldn't fix it either.
I guess there's something really stupid that has nothing to do with the application itself and that I'm missing, but I can't put my finger on it, so does anyone have any idea why this setup doesn't work?
server.js
var express = require('express.io');
var app = module.exports = express();
require('./proxy');
app.http().io();
app.listen(8000);
// ...
proxy.js
var httpProxy = require('http-proxy');
var url = require('url');
httpProxy.createServer(function(req, res, proxy) {
// ...
proxy.proxyRequest(req, res, {
host: destination.host,
port: 80
});
}).listen(9000);
$ netstat -pln | grep node output
tcp 0 0 0.0.0.0:9000 0.0.0.0:* LISTEN 1487/node
tcp 0 0 0.0.0.0:8000 0.0.0.0:* LISTEN 1487/node
Security group rules
It turned out that the problem was not at all related to the application or the EC2 instance setup.
The network I was in while testing this was blocking some ports. This is why when moving the proxy to port 8000 it was working fine, but on 9000 or any other random ones that I tried it wasn't. D'oh!

Resources