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

5

49

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?

Joniejonina answered 28/10, 2011 at 12:56 Comment(1)
That is a terrible error message.Jacklin
K
72

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

Kennithkennon answered 28/10, 2011 at 13:24 Comment(7)
Could you elaborate as to why not to run a node.js app as root on port 80? Im curious (a novice js dev).Mulch
This doesn't apply to node only. It is not recommended to run any server software as root. If you have to, because you want to use a privileged port, the process drops privileges and "forwards" all incoming traffic on that port to the corresponding process running on a lesser provileged user. This is becasue no program is perfect. Every software has bugs and maybe security issues. If an attacker can utilize such bugs and inject code - this gets executed as the user running this process. So if your process runs as root the attacker could do anything on your machine.Kennithkennon
Running nginx as a reverse-proxy is a bit overkill in this case. I suggest using iptables for port forwarding unless there's additional nginx functionality that you need in front of the Express app.Heterotopia
@ThomasFritz Why do we usually run Apache on port 80 if you are saying we should not run Node there?Alodee
@Alodee Because, like any other process, apache needs root privileges to be able to listen on the privileged port 80. BUT it immediately creates "worker processes" and drops its privileges to a lesser privileged user and group and then forwards all incoming requests on that port to its worker processes. But node is a single process - you can think of it as such a worker process of apache. If you want to run node on 80 the whole process - every possible instruction - would run as root. So it is kind of a similar setup as nginx(80) --> node(3000)Kennithkennon
Ah, that makes more sense. So would having Apache on a port besides 80 be better in any way over having it on 80?Alodee
@Alodee Apache drops its privileges of their "worker processes", etc. automatically itself. So there is no need to try to manually tweak this. Just let it the way it is. It is OK and safe.Kennithkennon
N
94

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
Needlepoint answered 20/12, 2012 at 19:18 Comment(7)
this is great! i was be able to fix the problem!Scutate
nice and clean answer without nginx or other proxy solution!Underexposure
Be careful about using this command. If you're logged in as root in server, this will forward traffic on all your domains to port 3000.Independence
this command brought down my entire digitalocean server... just wanted to put that out there for others to seeAmpersand
you likely had another process running on that port which was clobbered when you redirected 80 to 3000.Needlepoint
It works well, but Im wondering if there is not a cleaner solution? What is the best practice?Pallor
I recommend adding a method for making this persistent. For example. In ubuntu sudo apt install iptables-persistent will take care of this in a clean way.Teleview
K
72

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

Kennithkennon answered 28/10, 2011 at 13:24 Comment(7)
Could you elaborate as to why not to run a node.js app as root on port 80? Im curious (a novice js dev).Mulch
This doesn't apply to node only. It is not recommended to run any server software as root. If you have to, because you want to use a privileged port, the process drops privileges and "forwards" all incoming traffic on that port to the corresponding process running on a lesser provileged user. This is becasue no program is perfect. Every software has bugs and maybe security issues. If an attacker can utilize such bugs and inject code - this gets executed as the user running this process. So if your process runs as root the attacker could do anything on your machine.Kennithkennon
Running nginx as a reverse-proxy is a bit overkill in this case. I suggest using iptables for port forwarding unless there's additional nginx functionality that you need in front of the Express app.Heterotopia
@ThomasFritz Why do we usually run Apache on port 80 if you are saying we should not run Node there?Alodee
@Alodee Because, like any other process, apache needs root privileges to be able to listen on the privileged port 80. BUT it immediately creates "worker processes" and drops its privileges to a lesser privileged user and group and then forwards all incoming requests on that port to its worker processes. But node is a single process - you can think of it as such a worker process of apache. If you want to run node on 80 the whole process - every possible instruction - would run as root. So it is kind of a similar setup as nginx(80) --> node(3000)Kennithkennon
Ah, that makes more sense. So would having Apache on a port besides 80 be better in any way over having it on 80?Alodee
@Alodee Apache drops its privileges of their "worker processes", etc. automatically itself. So there is no need to try to manually tweak this. Just let it the way it is. It is OK and safe.Kennithkennon
C
10

Keep it Stupid Simple:

  • setcap
  • systemd
  • VPS

On a normal VPS (such as Digital Ocean, Linode, Vultr, or Scaleway), where the disk is persistent, use "setcap". 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://webinstall.dev/serviceman | bash
# 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.

Containment answered 15/10, 2019 at 6:43 Comment(0)
S
0

As far as what I have learnt from my basic networking classes, port no 0 to 1023 are reserved ones (known as well known ports), hence can't be used directly. We might require root/admin access.Port no 80 is reserved for HTTP. Correct me if i may be wrong.

Sacculate answered 7/1 at 10:56 Comment(0)
D
-1

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
Doucet answered 28/10, 2011 at 12:59 Comment(1)
I can't think of anything. It's a brand new instance with a copy of node.js installed and mongodb server running. nc returned nothing.Joniejonina

© 2022 - 2024 — McMap. All rights reserved.