7

I've written a web-server using Node.js. When I tried to test my server with the tester I've written for it, I succeed only if the port I'm using for the server is not 80. I've checked on netstat, and no other application is using port 80. The error I'm getting on the console is:

Error: connect ECONNREFUSED
  at errnoException (net.js:640:11)
  at Object.afterConnect [as oncomplete] (net.js:631:18)

What can be done in this case?

franzlorenzon
  • 5,333
  • 6
  • 31
  • 55
limlim
  • 2,835
  • 2
  • 31
  • 46

5 Answers5

18

You should not make a habit of running node as a privileged user. Here is a method I'm using on 6 different machines:

Use iptables to forward incoming traffic on port 80 to 8080 like so:

sudo iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 8080

Then be sure to save that

sudo iptables-save

Youd also want to add that to rc.local so those are set at reboot or instance launch (in the case of EC2 or other cloud)

Then you can safely start node listening on 8080 as any user.

talentedmrjones
  • 5,533
  • 1
  • 24
  • 25
  • Do you not also need to make outbound traffic to port 8080 forward to port 80? – Tom Mar 05 '12 at 18:11
  • @Tom You do not. That is automatic. – talentedmrjones Mar 06 '12 at 21:25
  • Huge +1 on this solution. I had considered using an apache virtualhost to do the same thing, but this did the trick! – benipsen May 15 '13 at 05:38
  • @talentedmrjones it is not working for me without making outbound traffic. Ubuntu 12.10. It only works after i give this command also. `iptables -t nat -A OUTPUT -d localhost -p tcp --dport 80 -j REDIRECT --to-ports 8080` – vumaasha Aug 18 '13 at 01:06
10

This is basically an addition to the answer from maerics, but since I want to add a code example I write another answer with additional information how to prevent security problems.

Usually web servers are started as root, because this is needed to bind on ports below 1024, but then they change the user they run under to an not privileged user.

You can do this with node.js using process.setuid("username").

The following example starts the server and then drop the root permissions to the user "www-data" after it bound itself to port 80 when started as root:

function StartServer() {
  console.log("Starting server...");
  // Initalizations such as reading the config file, etc.
  server = http.createServer(function (req, res) {
    res.writeHead(200, {'Content-Type': 'text/plain'});
    res.end('Hello World\n');
  });
  try {
    server.listen(80, "0.0.0.0", function(){
      process.setuid("www-data");
    });
  }
  catch(err) {
    console.error("Error: [%s] Call: [%s]", err.message, err.syscall);
    process.exit(1);
  }
}
Torsten Robitzki
  • 2,939
  • 18
  • 34
Bastian
  • 10,129
  • 1
  • 29
  • 39
  • 1
    +1 also, just FYI you can add [language syntax highlighting hints](http://meta.stackexchange.com/questions/981/syntax-highlighting-language-hints) ([link](http://meta.stackexchange.com/questions/981/syntax-highlighting-language-hints)) to your code snippets to make them prettier! – maerics Jan 11 '12 at 14:36
  • thanks, guess it did not work by itself without the javascript tag in the question :) – Bastian Jan 11 '12 at 15:17
  • yeah, the auto-detect seems to have the most trouble with ECMAScript derivatives for some reason. – maerics Jan 11 '12 at 15:24
  • The .setuid is exactly what is needed, especially when trying to start this from Upstart or similar where everyone else is saying "do -u www-data". – Jon J Jan 18 '13 at 02:06
3

You might not have permission to bind to ports below 1024 (including 80) as a normal user (e.g. non-root), try a higher numbered port (above 1024, e.g. 8080).

[Edit]

Depending on your target system, and assuming you are its administrator, then you can probably work around the problem like so:

  1. Execute your program using "sudo", such as: sudo node ./myprogram.js.

  2. Or, login as the "root" user on your system and run the program as normal.

However, don't get in the habit of doing either of these on a regular basis (until you understand why), they can potentially introduce security holes which may be exploitable by malicious, motivated individuals.

maerics
  • 133,300
  • 39
  • 246
  • 273
  • I have to set the port to 80 (it's an assignment I have to submit, so It has to work also on port 80). How can I get this permission? – limlim Jan 09 '12 at 18:00
  • Permission may be granted by a system administrator. Note that your program will work the same on any port number, as long as the user running the program has permission to bind to that port. – maerics Jan 09 '12 at 18:04
  • It is my own computer. How can I do that? – limlim Jan 09 '12 at 18:07
  • @limlim: it depends on your system, but try `sudo node ./myprogram.js` and enter your password when prompted. Alternatively, log in as the root user and run your program (but don't get in the habit of doing that, it's very bad!). – maerics Jan 09 '12 at 18:09
  • I added an answer with a code example how to drop the root privileges after the server has been startet to prevent a security hole by answering web requests as root – Bastian Jan 11 '12 at 14:31
  • You can also listen on 8080 and have iptables forward incoming 80 to 8080 like so: sudo iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 8080 && sudo iptables-save – talentedmrjones Feb 09 '12 at 19:07
0

An alternate option that I haven't seen in the above list is also to permit your process to bind to a privileged port (<1024) by executing the following command on the node executable. (Adapt the path)

setcap 'cap_net_bind_service=+ep' /opt/meteor/.meteor/tools/latest/bin/node

The annoyance is that you must reissue this command every time you update or change the node executable.

Regards,

Pivert
  • 701
  • 5
  • 15
0

I use Nginx server (port 80) in front of Node.js (any port >1024). It works great.

Roman Podlinov
  • 19,179
  • 7
  • 37
  • 56