Standard practices say no non-root process gets to talk to the Internet on a port less than 1024. How, then, could I get Node talking on port 80 on EC2? (I wanted it to go as fast as possible and use the smallest possible share of my teeny tiny little micro-instance's resources, so proxying through nginx or Apache seemed suboptimal.)
The temptingly easy but ultimately wrong solution:
Alter the port the script talks to from 8000 to 80:
.. and run it as root:
sudo /usr/local/bin/node foo.js
This is a Bad Idea, for all the standard reasons. (Here's one: if Node has access to the filesystem for any reason, you're hosed.)
One possibly-right way:
Add a port forwarding rule via
Oh dear familiar feeling: you are a total n00b and know not one thing about iptables.
First, I listed the rules currently running on the NAT (Network Address Translation) table:
[ec2-user@ip-XX-XXX-XX-X ~]$ sudo iptables -t nat -L Chain INPUT (policy ACCEPT) target prot opt source destination Chain FORWARD (policy ACCEPT) target prot opt source destination Chain OUTPUT (policy ACCEPT) target prot opt source destination
I saw nothing, so I felt free to add a rule forwarding packets sent to external port 80 to internal port 8000:
[ec2-user@ip-XX-XXX-XX-X ~]$ sudo iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-ports 8000
When I listed again, I saw a new PREROUTING chain:
[ec2-user@ip-XX-XXX-XX-X ~]$ sudo iptables -t nat -L Chain PREROUTING (policy ACCEPT) target prot opt source destination REDIRECT tcp -- anywhere anywhere tcp dpt:http redir ports 8000
I checked my Node script, which was running on port 8000, and (yes!) it was responding on port 80.
During my early attempts I screwed up a bunch of times. I removed busted rules by specifying the right table, the right chain, and the right line number, like so:
[ec2-user@ip-XX-XXX-XX-X ~]$ sudo iptables -t nat -D PREROUTING 1
This removed the first line from the
PREROUTING chain in my nat table.
I did not do this myself but throughout this process I had a very strong feeling I should be very careful not to screw up port 22, which was my only way in.
- @frozentux for http://iptables.rlworkman.net/chunkyhtml, which is a pretty definitive iptables tutorial.
If you're using AWS, a preferred way is to use cloudfront or an elastic load balancer. You can easily create a cloudfront distribution or classic elastic load balancer that will forward traffic to the port of your choice on your ec2 server. You can even create load balancers with only one ec2 instance if you don't want to use cloudfront. This in my opinion should be preferred as you can also quickly add a ssl certificate to your distribution or load balancer using the AWS certificate manager without any server configuration. Then just simply point your A record(s) to the public DNS for your distribution or load balancer. No code, no hacks, easy as pie.