3
votes

My Goal: To run 2 servers, HTTP server for my web application and TCP server to handle my TCP clients and use SSL for both. I want ELB to handle SSL for HTTP and my application to handle the SSL connection for TCP server (I use self-signed certs only for TCP server),

Here's what I have so far

  • My HTTP server is a Node.js HTTP server with Express. I wanted to encrypt all connections and found out I could get a free SSL certificate through Certificate Manager on Amazon. However, I found out I need Elastic Load Balancer. So I set one up and it has been more painful than I anticipated. I'm having trouble getting https working for my web application.
  • The idea is that the load balancer terminates all the SSL connections from client and sends the un-encrypted data to the Back-end EC2 machine over 80. The node.js HTTP server is listening on 80.

This is my HTTP server file app.js

var express = require('express');
var http = require('http');
var servestatic = require('serve-static');
var app = express();
var bodyParser = require('body-parser');

var flash = require('connect-flash');
var morgan = require('morgan');
var cookieParser = require('cookie-parser');
var session = require('express-session');
var cacheResponseDirective = require('express-cache-response-directive');

app.use(morgan('dev')); // log every request to the console
app.use(bodyParser.json()); // support json encoded bodies
app.use(bodyParser.urlencoded({extended: true })); // support encoded bodies
app.use(passport.initialize());
app.use(passport.session()); // persistent login sessions
app.use(flash()); // use connect-flash for flash messages stored in session
app.use(cacheResponseDirective());



app.use(express.static('public')); // enable if needed for server to serve static content

require('routes.js')(app); // Load routes and pass in our app and fully configured passport


var allowCrossDomain = function(req, res, next) {

    res.header('Access-Control-Allow-Origin', '*');
    res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE');
    res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization');

    if ('OPTIONS' == req.method) {
    res.send(200);
    }
    else {
    next();
    }
};



var server = app.listen(80, function() {



    console.log('The server is running at http://%s,%s', HOST,PORT);

});

I handle all my routes through routes.js

module.exports = function (app) {

path = require('path');

// for home or index page
app.get('/', function (req, res) {
    res.sendFile(path.join(__dirname, './models', 'index.html'));
});// end of index file

// for contact page
app.get('/contact', function (req, res) {
    res.sendFile(path.join(__dirname, './models', 'contact.html'));
});

// route for signup
app.get('/signup', function (req, res) {
    console.log("\n I'm in index");
    res.sendFile(path.join(__dirname, './models', 'signup.html'));
});

app.get('/loginBtn', function (req, res) {
    console.log("\n I'm in initial login page");
    res.sendFile(path.join(__dirname, './models', 'login.html')); // Go to the login page
});

};
  • I did my research and found these posts related to this issue. 1, 2, 3. The first post suggests this snippet of code. Including this in app.js results in a 302 error. How can I de-bug this issue? where should I include it?

    app.use(function(req, res, next) {
     if((!req.secure) && (req.get('X-Forwarded-Proto') !== 'https')) {
      res.redirect('https://' + req.get('Host') + req.url);
     }
    else
     next();
    }); 
    
  • One of the posts recommends using reverse proxy. Is this necessary?

  • The other complexity is that the ELB health check pings on port 80 and is handled by the same HTTP server. With this code snippet, the ELB starts seeing 5xx error and the ELB takes the instance out of service.

  • For my TCP server, I plan to handle the SSL connections myself(self-generated certs). I run TCP on some random port. When ELB sees SSL conenction on this port, will it terminate it?

ELB listener config

(Load balancer) http 80 --> (Node instance) http 80

(Load balancer) https 443 --> (Node instance) http 80

(Load balancer) TCP random_port -->(Node instance) TCP random_port

1
Change your ELB listener 443 to 443 and see if you get the same issue?error2007s
@error2007s Your suggestion makes me think you don't understand how SSL termination at the ELB works.Mark B
@MarkB Comment section is to comment on the question and not on other peoples comment and if you know the answer then answer the question or give your suggestion by commenting to user what he should do. What I understand and don't understand is none of your business :)error2007s
@error2007s I did answer. And when people are spreading incorrect information on this site I think it is everyone's business.Mark B
@MarkB My comment was to try stuff I did not say in the comment it will fix your issue. If I would have answered incorrectly then that is wrong information.error2007s

1 Answers

1
votes

Including this in app.js results in a 302 error.

app.use(function(req, res, next) {
 if((!req.secure) && (req.get('X-Forwarded-Proto') !== 'https')) {
  res.redirect('https://' + req.get('Host') + req.url);
 }
else
 next();
});

302 isn't an error, it's a redirect. You added code to redirect all HTTP requests to HTTPS. The code looks correct to me and should be redirecting if the original request to the ELB is not over HTTPS.

One of the posts recommends using reverse proxy. Is this necessary?

No it isn't. It may provide a performance improvement, but it isn't necessary and would add extra moving parts at this point which could confuse things.

The other complexity is that the ELB health check pings on port 80 and is handled by the same HTTP server. With this code snippet, the ELB starts seeing 5xx error and the ELB takes the instance out of service.

Are you sure the ELB is seeing 5xx errors instead of 302 responses? Regardless, you need to add a condition to the if statement in that snippet to allow HTTP requests to the health check URL go through.

For my TCP server, I plan to handle the SSL connections myself(self-generated certs). I run TCP on some random port. When ELB sees SSL connection on this port, will it terminate it?

Edit: I just realized you want to use self-signed certs over the TCP connections, so you should just specify a TCP listener on the ELB and forward that to TCP on the server, and the ELB will not try to terminate the SSL.