La aplicación Node.js no se puede ejecutar en el puerto 80 aunque no haya ningún otro proceso que bloquee el puerto

94

Estoy ejecutando una instancia de Debian en Amazon EC2 con Node.js instalado. Si ejecuto el siguiente código:

http = require('http');

http.createServer(function (request, response){
  response.writeHead(200, {'Content-Type':'text/plain'});
  response.end('Hello World\n');
}).listen(80);
console.log("Running server at port 80");

Obtengo la salida a continuación que me dice que hay otro proceso escuchando en el puerto 80:

Running server at port 80

events.js:72
        throw er; // Unhandled 'error' event
              ^
Error: listen EACCES
    at errnoException (net.js:901:11)
    at Server._listen2 (net.js:1020:19)
    at listen (net.js:1061:10)
    at Server.listen (net.js:1127:5)
    at Object.<anonymous> (/home/admin/nodetests/nodetest.js:6:4)
    at Module._compile (module.js:456:26)
    at Object.Module._extensions..js (module.js:474:10)
    at Module.load (module.js:356:32)
    at Function.Module._load (module.js:312:12)
    at Function.Module.runMain (module.js:497:10)

Ahora, cuando verifico si hay un proceso (como root en caso de que algo esté oculto) escuchando en el puerto 80 usando:

netstat -tupln

Obtengo la siguiente salida, que me dice que no hay nada escuchando en el puerto 80:

Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      1667/sshd       
tcp6       0      0 :::22                   :::*                    LISTEN      1667/sshd

Debo señalar que Debian tiene el puerto 80 abierto como una regla de entrada si eso hace una diferencia.

Mi pregunta es: ¿Qué estoy haciendo mal? ¿Por qué no puedo identificar el proceso que escucha el puerto 80? ¿Por qué está bloqueado en Debian? ¿Qué pasos debo seguir para que el código se ejecute correctamente?

Brian Yeh
fuente

Respuestas:

197

El código de error EACCESsignifica que no tiene los permisos adecuados para ejecutar aplicaciones en ese puerto. En los sistemas Linux, cualquier puerto por debajo de 1024 requiere acceso de root.

hexacianuro
fuente
5
por lo tanto, el nodo sudo myapp.js lo hará si tiene autorización para usar sudo (simplemente ajústelo para cualquier principiante).
AlexMA
20
@AlexMA, pero ejecutar un servidor como root es un gran no, no
Patrick Evans
1
Entonces, ¿cómo se ejecuta el nodo en el puerto 80? ¿Deberías simplemente ... no y usar un proxy?
AlexMA
9
@PatrickEvans Supongo que la mejor práctica sería ejecutar en un puerto diferente y simplemente configurar una regla de reenvío de puertos como se menciona aquí: stackoverflow.com/questions/16573668/…
AlexMA
73

En lugar de ejecutar en el puerto 80, puede redirigir el puerto 80 al puerto de su aplicación (> 1024) usando

iptables -t nat -I PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 3000

Esto funcionará si su aplicación se ejecuta en el puerto 3000.

Kamrul
fuente
1
hice esto. Descubrí que tienes que ser root para ejecutar iptables en una instalación nueva de Debian, de lo contrario $ PATH no lo señalará.
Brian Yeh
Sí, esta fue probablemente la forma más fácil de hacerlo. Estoy en Google Cloud Compute, lo que me dio problemas al tocar el puerto 80. Fue genial. Gracias.
Andy
Esta debería ser la solución aceptada. Ejecutar el servidor web como sudo es peligroso, ya que puede dar acceso de root al atacante si existe alguna vulnerabilidad en la aplicación; Además, si la aplicación creara archivos, serían inaccesibles para otros usuarios, lo que haría que los usara sudoaún más.
jesusiniesta
No estoy seguro de por qué, pero en Ubuntu 14.04 esto no funcionó para mí. Ahora uso el reenvío de puertos a través de ssh, que es igual de fácil. Publiqué una respuesta a continuación .
panelista
19

Respuesta corta: puede permitir el acceso del nodo a ese puerto usando:

setcap 'cap_net_bind_service=+ep' /path/to/nodejs

respuesta larga

Editar:

Puede que no funcione en nuevas versiones de nodos

Reut Sharabani
fuente
eso hizo el truco. @LinuxMint - sudo setcap 'cap_net_bind_service = + ep' / usr / local / bin / node
Combine
A veces, una actualización cambiará la ruta de ubicación al nodo y esto dejará de funcionar. Por lo tanto, deberá ejecutarlo nuevamente para la nueva ruta al nodo.
vaporizado el
Parece que esto ya no funcionará después de la versión 8 del nodo. Github.com/nodejs/node/issues/22648
timaw
6

Tenga en cuenta que si lo está apacheejecutando, puede crear un proxy inverso en un vhost. Si su nodo se está ejecutando en el puerto 8080:

<VirtualHost 127.0.0.1:80>
        ServerName myLocalServer

        ProxyPass        /  http://localhost:8080/
        ProxyPassReverse /  http://localhost:8080/
</VirtualHost>

Por supuesto, agregue el servidor a /etc/hosts:

127.0.0.1    myLocalServer

Deberá habilitar los módulos de apache relevantes:

sudo a2enmod proxy_html
sudo a2enmod proxy_http
sudo a2enmod proxy_connect
sudo a2enmod proxy_ajp
sudo service apache2 restart

... y ahora puedes conectarte a http://myLocalServer.

Redsandro
fuente
3

Para aquellos que buscan una solución rápida y sencilla para un entorno de desarrollo , el reenvío de puertos a través de ssh puede ser una buena alternativa:

ssh -L 80:localhost:3000 yourusername@localhost -N

Esto reenvía el puerto 80 en localhost al puerto 3000 en localhost.

Debe ejecutarse como root (puerto privilegiado). Para cancelarlo, simplemente presione ctrl-c en la terminal. (Puede agregar el-f bandera para que el comando se ejecute en segundo plano, pero luego debe encontrarlo nuevamente para eliminarlo).

Esta solución requiere que tenga un servidor ssh que se ejecute localmente . Se puede hacer rápidamente , pero tenga en cuenta las implicaciones de seguridad si está en una red compartida. Es posible que desee aplicar al menos algún nivel de seguridad adicional (deshabilite la contraseña y el inicio de sesión de root).

Personalmente, solo uso esto en mi máquina local. No estoy seguro de cómo afecta la velocidad de procesamiento de sus solicitudes si ejecuta esto en producción, tal vez alguien tenga una idea. De todos modos, debe asegurarse de que este comando se siga ejecutando todo el tiempo, lo que presenta más dolores de cabeza. Para entornos de producción , sugiero usar un proxy inverso como nginx .

panelista
fuente
2

la respuesta del hexacianuro es correcta. pero ¿hay alguna solución para que esto funcione?

la respuesta es sí.

¿cómo?

puede usar, reverse proxypor ejemplo, ejecutar un nginx reverse proxypuerto 80y pasar el proxy al destinoip:port que el nodo lo usa.

puede configurar esto usando docker containerque hace la vida aún más fácil. esta es la compilación oficial de nginx en docker hub que puede extraer.

hay incluso más beneficios en el uso reverse proxyque puede buscar en Google.

Ali_Hr
fuente
0

Recibí el mismo error e intenté ejecutar mi aplicación usando sudo y funcionó para mí.

sin sudo

mansi@mansi:~/NodePractice$ node myFirst.js 
events.js:141
      throw er; // Unhandled 'error' event
      ^

Error: listen EACCES 0.0.0.0:80
    at Object.exports._errnoException (util.js:870:11)
    at exports._exceptionWithHostPort (util.js:893:20)
    at Server._listen2 (net.js:1224:19)
    at listen (net.js:1273:10)
    at Server.listen (net.js:1369:5)
    at Object.<anonymous> (/home/mansi/NodePractice/myFirst.js:6:4)
    at Module._compile (module.js:410:26)
    at Object.Module._extensions..js (module.js:417:10)
    at Module.load (module.js:344:32)
    at Function.Module._load (module.js:301:12)

y con sudo

mansi@mansi:~/NodePractice$ sudo node myFirst.js 
^C
Parth Pachchigar
fuente
... que es exactamente lo que no quieres hacer. Crea problemas de seguridad.
bvdb
-1

El uso de PORT 80 requiere algunos permisos especiales. Usar sudoantes de ejecutar la declaración de la aplicación resolvió mi problema. por ejemplo, si usa npm para ejecutar su aplicación, puede escribirsudo npm start

webcrawler
fuente
1
Esta respuesta no agrega nada al contenido de respuesta ya proporcionado por otros. Responda únicamente si está agregando información adicional.
Brian Yeh
-2

El código de error EACCESsignifica que no tiene los permisos adecuados para ejecutar aplicaciones en ese puerto. En los sistemas Linux, cualquier puerto por debajo de 1024 requiere acceso de root.

Ejecute el programa con sudopermiso. Ejecute el sudo sucomando antes de ejecutar el programa.

akshith ranjan
fuente
Vea los comentarios de la publicación en la respuesta de hexacianuros. Gracias.
Brian Yeh