Node.js + Express: app won't start listening on port 80

I create and launch an app like this:

express -s -t ejs
npm install express
npm install ejs
node app.js

and it works (on port 3000). But when I go and change the port to 80, then running node app.js outputs this:

node.js:198
throw e; // process.nextTick error, or 'error' event on first tick
          ^
TypeError: Cannot call method 'getsockname' of null
at HTTPServer.address (net.js:746:23)
at Object.<anonymous> (/var/www/thorous/app.js:35:67)
at Module._compile (module.js:432:26)
at Object..js (module.js:450:10)
at Module.load (module.js:351:31)
at Function._load (module.js:310:12)
at Array.<anonymous> (module.js:470:10)
at EventEmitter._tickCallback (node.js:190:26)

This works too on my laptop, but not on my Amazon EC2 instance, where port 80 is open. Can figure out what's wrong. Any tips?

Answers


Are you starting your app as root? Because lower port numbers require root privileges. Maybe a sudo node app.js works?

BUT, you should NOT run any node.js app on port 80 with root privileges!!! NEVER!

My suggestions is to run nginx in front as a reverse proxy to your node.js app running on port e.g. 3000


If you really want to do this you can forward traffic on port 80 to 3000.

sudo iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-ports 3000

Perhaps there is something else running on port 80 previously?

Perhaps do a port scan and confirm that it is not being used already?

nc -z <<your IP>> 80

Keep it Stupid Simple:

  • netcap
  • systemd
  • VPS

On a normal VPS (such as Digital Ocean, Linode, Vultr, or Scaleway), where the disk is persistent, use "netcap". This will allow a non-root user to bind to privileged ports.

sudo setcap 'cap_net_bind_service=+ep' $(which node)

TADA! Now you can run node ./server.js --port 80 as a normal user!

Aside:

You can also use systemd to stop and start your service. Since systemd is sometimes a p.i.t.a., I wrote a wrapper script in Go that makes it really easy to deploy node projects:

# Install
curl https://rootprojects.org/serviceman/dist/linux/amd64/serviceman -o serviceman
chmod +x ./serviceman
sudo serviceman /usr/local/bin
# Use
cd ./my/node/project
sudo serviceman --username $(whoami) add npm start

or, if your server isn't called 'server.js' (de facto standard), or extra options:

cd ./my/node/project
sudo serviceman --username $(whoami) add node ./my-server-thing.js -- --my-options

All that does is create your systemd file for you with sane defaults. I'd recommend you check out the systemd documentation as well, but it is a bit hard to grok and there are probably more confusing and otherwise bad tutorials than there are simple and otherwise good tutorials.

Ephemeral Instances (i.e. EC2) are not for long-running servers

Generally, when people use EC2, it's because they don't care about individual instance uptime reliability - they want a "scalable" architecture, not a persistent architecture.

In most of these cases it isn't actually intended that the virtualized server persist in any sort of way. In these types of "ephemeral" (temporary) environments a "reboot" is intended to be about the same as reinstalling from scratch.

You don't "setup a server" but rather "deploy an image". The only reason you'd log into such a server is to prototype or debug the image you're creating.

The "disks" are volatile, the IP addresses are floating, the images behave the same on each and every boot. You're also not typically utilizing a concept of user accounts in the traditional sense.

Therefore: although it is true that, in general, you shouldn't run a service as root, the types of situations in which you typically use volatile virtualization... it doesn't matter that much. You have a single service, a single user account, and as soon as the instance fails or is otherwise "rebooted" (or you spin up a new instance of your image), you have a fresh system all over again (which does mean that any vulnerabilities persist).

Firewalls: Ephemeral vs VPS

Stuff like EC2 is generally intended to be private-only, not public-facing. These are "cloud service" systems. You're expected to use a dozen different services and auto-scale. As such, you'd use the load balancer service to forward ports to your EC2 group. Typically the default firewall for an instance will deny all public-network traffic. You have to go into the firewall management and make sure the ports you intend to use are actually open.

Sometimes VPS providers have "enterprise" firewall configurators, but more typically you just get raw access to the virtual machine and since only the ports that you actually listen on get access to the outside world in the first place (by default they typically don't have random services running), you may not get any additional benefit from a firewall. Certainly a good idea, but not a requirement to do what you need to do.

Don't use EC2 as a VPS

The use case you have above may be a much better candidate for a traditional VPS service (as mentioned above: Digital Ocean, Linode, Vultr, Scaleway, etc) which are far easier to use and have much less management hassle to get started. All you need is a little bash CLI know-how.

And, as an extra bonus, you don't have to guess at what the cost will be. They tell you in simple $/month rather than ยข/cpu/hour/gb/internal-network/external-network/etc - so when something goes wrong you get a warning via email or in your admin console rather than an unexpected bill for $6,527.

Bottom line: If you choose to use EC2 and you're not a "DevOps" expert with an accountant on staff... you're gonna have a hard time.


Need Your Help

Python subprocess.call a bash alias

python bash subprocess

At work there's a script that lists completed tasks. This was written by someone else and is hosted over the network. I have an alias in my .bashrc that calls this script, with its many flags and s...

module.exports client side

javascript node.js browser module requirejs

I've created a node module that is essentially just some useful JS that can also be used client side. I know that require.js can load common.js components, but I don't necessarily want to make a ma...