1

Is there an Amazon Web Services service which will translate ports, such as port 8001 to port 80?

I like to host multiple websites behind a single static IP address, and I use port forwarding to route the different ports to various web servers behind my firewall which does the port forwarding.

It would be nice if I could implement a table like this somewhere inside an AWS service:

Client requests mydomain.com:80 -> AWS Route 53 translates to 123.123.123.123:8001 -> My firewall port forwards 8001 to the web server inside the LAN.

If AWS does not offer this service, then is there another out of the box solution? I could write my own app to do this and run it on an EC2 instance, but I prefer to use an existing tool if one is available.

  • If the ALB didn't exist this is trivially simple to do in Nginx. Run it on a t2.nano (subject to bandwidth, it may need to be larger) and it's $5/month, less on a reserved instance. ALB costs around $16/month plus the cost of LCUs. The service you need is called a "reverse proxy". – Tim Apr 30 '17 at 20:03
  • Is there any particular reason to do such strange thing? – Putnik May 1 '17 at 7:31
3

Sure, the AWS ALB can do this. Additionally, it now supports host-based routing, so you can point multiple names to the ALB and configure it to route each one separately.

Note: the ALB is only able to load balance requests to backend servers that are within AWS. It's not a general-purpose load balancing service that can be used anywhere. Typically you will deploy backend servers in private subnet of a VPC and then deploy an ALB in front of them to accept client requests.

Client requests mydomain.com:80 -> AWS Route 53 translates to 123.123.123.123:8001 -> My firewall port forwards 8001 to the web server inside the LAN.

I think you're confused about the role of DNS. The DNS knows nothing about ports. For the purposes of publishing a web site, DNS only maps a name to one or more IP addresses. Period. There is no way to have DNS "redirect" to a port or anything like that.

  • Where is the restriction saying AWS ALB will only route to hosts within AWS? Is AWS really preventing the load blancer from routing traffic outside of an AWS wan IP? – steampowered Apr 30 '17 at 19:54
  • 2
    The only way to add backends to AWS load balancers is by specifying an instance ID. – EEAA Apr 30 '17 at 19:55
  • 1
    ELBs are strictly designed to be used in conjunction with other AWS services (which is one of the reasons they're so inexpensive to use). – EEAA Apr 30 '17 at 19:58
  • So there is no way to use an AWS load balancer to redirect traffic away from AWS. I wrote my own and now I run it on AWS. The code is in my separate answer - works great. – steampowered May 1 '17 at 0:23
1

I wrote my own port translator in NodeJS, and I am submitting the code here in case anyone else wants to use it. It does encrypted connections with https certificates as well as plain text port 80. I run it on an EC2 t2.micro instance for $10 per month and it runs great.

The only catch it it requires the browser to support SNICallback so the proxy server can dynamically use the correct certificate for the domain requested.

This tiny app below leverages the http-proxy library for NodeJS.

var proxyTable = {
    'mydomain.com': 'http://localhost:8001',
    'demo1.mydomain.com': 'https://localhost:8002', // https after proxy
    'demo2.mydomain.com': 'https://localhost:8005', // https after proxy
    'demo3.mydomain.com': 'https://localhost:8006', // https after proxy
    'demo4.mydomain.com': 'https://localhost:8007', // https after proxy
    'demo5.mydomain.com': 'https://localhost:8008', // https after proxy
}

http.createServer(function(req, res) {
    var hostname = req.headers.host.replace(/^www\./, ''); // remove www. subdomain prefix
    if (proxyTable[hostname]) {
        if (-1 != httpsDomains.indexOf(hostname)) { // redirect to https for httpsDomains
            redirectToHttps(req, res); // res.redirect() not available here
        } else {
            proxy.web(req, res, {target: proxyTable[hostname]});
        }
    } else {
        displayError(res, hostname)
    }
}).listen(80);

// Use SNICallback to dynamically use various SSL certificates depending upon hostname.
// To add a new SSL domain, add to secureContext AND proxyTable
const efboKey = fs.readFileSync(global.appRootPath + '/../mydomain.com.key', 'utf8');
const efboCert = fs.readFileSync(global.appRootPath + '/../mydomain.com.crt', 'utf8');
const efboCaBundleArray = makeCertificateAuthorityArray(global.appRootPath + '/../mydomain.com.ca-bundle', 'utf8');
const efboHttpsComponents = {
        key: efboKey,
        cert: efboCert,
        ca: efboCaBundleArray,
    };
var secureContext = {
    'mydomain.com': tls.createSecureContext(efboHttpsComponents),
    'demo1.mydomain.com': tls.createSecureContext(efboHttpsComponents),
    'demo2.mydomain.com': tls.createSecureContext(efboHttpsComponents),
    'demo3.mydomain.com': tls.createSecureContext(efboHttpsComponents),
    'demo4.mydomain.com': tls.createSecureContext(efboHttpsComponents),
    'demo5.mydomain.com': tls.createSecureContext(efboHttpsComponents),
}
try {
    var options = {
        SNICallback: function (hostname, cb) {
            if (secureContext[hostname]) {
                if (cb) {
                    cb(null, secureContext[hostname]);
                } else {
                    return secureContext[hostname]; // compatibility for older versions of node
                }
            } else {
                throw new Error('No keys/certificates for hostname requested');
            }
        },
        // must list a key and cert because required by tls.createServer()
        key: efboKey,
        cert: efboCert,
        ca: efboCaBundleArray,
    }
    https.createServer(options, function (req, res) {
        var hostname = req.headers.host.replace(/^www\./, ''); // remove www. subdomain prefix
        proxy.web(req, res, {target: proxyTable[hostname], secure: false}); // proxy https to http
    }).listen(443);
} catch (err){
    console.error(err.message);
    console.error(err.stack);
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.