Cómo configurar una aplicación Node.js para producción en CentOS 7

Introducción
Node.js es un entorno de ejecución de código abierto de Javascript para crear fácilmente aplicaciones de red y del lado del servidor. La plataforma se ejecuta en Linux, OS X, FreeBSD y Windows, y sus aplicaciones están escritas en JavaScript. Las aplicaciones de Node.js se pueden ejecutar en la línea de comandos, pero le enseñaremos a ejecutarlas como un servicio, de modo que se reinicien automáticamente al reiniciar o fallar, para que pueda usarlas en un entorno de producción.
En este tutorial, cubriremos la configuración de un entorno Node.js listo para producción que se compone de dos servidores CentOS 7; un servidor ejecutará aplicaciones Node.js administradas por PM2, mientras que el otro proporcionará a los usuarios acceso a la aplicación a través de un proxy inverso Nginx al servidor de aplicaciones.
La versión Ubuntu de este tutorial se puede encontrar aquí.
Prerrequisitos
Esta guía utiliza dos servidores CentOS 7 con redes privadas (en el mismo centro de datos). Las redes privadas se pueden configurar en los servidores nuevos cuando se crean (en la Select additional options
sección). Nos referiremos a ellos con los siguientes nombres:
- aplicación : el servidor donde instalaremos el entorno de ejecución de Node.js, su aplicación Node.js y PM2.
- web : El servidor donde instalaremos el servidor web Nginx, que actuará como un proxy inverso para tu aplicación. Los usuarios accederán a la dirección IP pública de este servidor para acceder a tu aplicación Node.js.
Nota: Consulte la documentación de DigitalOcean: Cómo habilitar redes privadas en Droplets si tiene intención de utilizar un servidor existente que actualmente no tiene configurada una red privada.
Antes de comenzar con esta guía, debe tener un usuario regular, no root, con sudo
privilegios configurados en ambos servidores. Este es el usuario con el que debe iniciar sesión en sus servidores. Puede aprender a configurar una cuenta de usuario regular siguiendo nuestra guía de configuración inicial del servidor para CentOS 7.
Comandos ejecutados en el servidor de aplicaciones :
- an_example_command_on_app
Comandos ejecutados en el servidor web :
- an_example_command_on_web
Es posible utilizar un único servidor para este tutorial, pero deberá realizar algunos cambios a lo largo del camino. Simplemente utilice la dirección IP del host local, es decir 127.0.0.1
, donde se utilice la dirección IP privada del servidor de aplicaciones .
Aquí hay un diagrama de cómo será su configuración después de seguir este tutorial:
Si desea poder acceder a su servidor web a través de un nombre de dominio, en lugar de su dirección IP pública, compre un nombre de dominio y luego siga estos tutoriales:
- Cómo configurar un nombre de host con DigitalOcean
- Cómo apuntar a servidores de nombres de DigitalOcean desde registradores de dominios comunes
Comencemos instalando el entorno de ejecución de Node.js en el servidor de aplicaciones .
Paso 1: Instalación de Node.js
Instalaremos la última versión LTS de Node.js en el servidor de aplicaciones .
Acceda por SSH a su servidor de aplicaciones utilizando el usuario normal, no root, con sudo
privilegios.
En el servidor de aplicaciones , usemos curl
para descargar el archivo de configuración del repositorio RPM de NodeSource:
- curl -L -o nodesource_setup.sh https://rpm.nodesource.com/setup_10.x
CURL
utilizará el protocolo HTTPS para descargar el script de configuración a su servidor, y la salida incluirá información relevante para la descarga:
Output % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed100 11109 100 11109 0 0 70128 0 --:--:-- --:--:-- --:--:-- 70757
A continuación, debe inspeccionar el contenido del script. El siguiente comando abrirá el script de configuración de NodeSource en la consola de su servidor, que luego puede comparar con el script de configuración de NodeSource (del repositorio de Github de distribuciones de NodeSource) para confirmar que el script se descargó correctamente:
- vi nodesource_setup.sh
Una vez satisfecho con el archivo, salga vi
escribiendo :q
to quit
y regrese a la línea de comando.
Ahora ejecutemos el script de configuración para instalar el repositorio RPM de NodeSource. Esto nos permitirá acceder al repositorio de NodeSource desde el yum
administrador de paquetes:
- sudo -E bash nodesource_setup.sh
El script genera información sobre la configuración para nuestra referencia:
Output## Installing the NodeSource Node.js 10.x repo...## Inspecting system...+ rpm -q --whatprovides redhat-release || rpm -q --whatprovides centos-release || rpm -q --whatprovides cloudlinux-release || rpm -q --whatprovides sl-release+ uname -m## Confirming "el7-x86_64" is supported...+ curl -sLf -o /dev/null 'https://rpm.nodesource.com/pub_10.x/el/7/x86_64/nodesource-release-el7-1.noarch.rpm'## Downloading release setup RPM...+ mktemp+ curl -sL -o '/tmp/tmp.2aCcULVx8n' 'https://rpm.nodesource.com/pub_10.x/el/7/x86_64/nodesource-release-el7-1.noarch.rpm'## Installing release setup RPM...+ rpm -i --nosignature --force '/tmp/tmp.2aCcULVx8n'## Cleaning up...+ rm -f '/tmp/tmp.2aCcULVx8n'## Checking for existing installations...+ rpm -qa 'node|npm' | grep -v nodesource## Run `sudo yum install -y nodejs` to install Node.js 10.x and npm.## You may also need development tools to build native addons: sudo yum install gcc-c++ make## To install the Yarn package manager, run: curl -sL https://dl.yarnpkg.com/rpm/yarn.repo | sudo tee /etc/yum.repos.d/yarn.repo sudo yum install yarn
Antes de instalar Node.js es importante limpiar toda la información almacenada en caché de yum
. Borrar la caché garantizará que yum
se use la conexión de red para obtener Node.js de nuestro nuevo repositorio NodeSource (lo que evitará posibles conflictos causados por paquetes obsoletos):
- sudo yum clean all
A continuación, descargaremos y haremos utilizables todos los metadatos de los yum
repositorios habilitados actualmente. Esto garantizará que nuestras yum
consultas se completen lo más rápido posible:
- sudo yum makecache fast
Para compilar e instalar complementos nativos npm
también necesitamos instalar herramientas de compilación:
- sudo yum install -y gcc-c++ make
Ahora podemos instalar la última versión del paquete Node.js:
- sudo yum install -y nodejs
Verifique que Node esté instalado verificando su versión con este comando:
- node -v
Su salida mostrará el número de versión que está ejecutando:
Outputv10.16.3
El entorno de ejecución de Node.js ya está instalado y listo para ejecutar una aplicación. Escribamos una aplicación de Node.js.
Paso 2: Creación de la aplicación Node.js
Ahora crearemos una aplicación Hello World que simplemente responde "Hello World"
a cualquier solicitud HTTP. Esta es una aplicación de muestra que te ayudará a configurar Node.js y que puedes reemplazar con tu propia aplicación. Solo asegúrate de modificar tu aplicación para que escuche en las direcciones IP y puertos adecuados.
Como queremos que nuestra aplicación Node.js responda a las solicitudes que provienen de nuestro servidor proxy inverso ( web ), utilizaremos la interfaz de red privada de nuestro servidor de aplicaciones para la comunicación entre servidores. Busque la dirección de red privada de su servidor de aplicaciones .
Si está utilizando un Droplet de DigitalOcean como servidor, puede buscar la dirección IP privada del servidor a través del servicio de metadatos. En el servidor de aplicaciones , utilice el curl
comando para recuperar la dirección IP ahora:
- curl -sw "n" http://169.254.169.254/metadata/v1/interfaces/private/0/ipv4/address
Querrá copiar la salida (la dirección IP privada), ya que se utilizará para configurar la aplicación Node.js.
A continuación, crea y abre tu aplicación Node.js para editarla. Para este tutorial, usaremos vi
una aplicación de muestra llamada hello.js
:
- vi hello.js
Inserte el siguiente código en el archivo y asegúrese de sustituir la dirección IP privada del servidor de aplicaciones por ambos APP_PRIVATE_IP_ADDRESS
elementos resaltados. Si lo desea, también puede reemplazar el puerto resaltado, 8080
, en ambas ubicaciones (asegúrese de utilizar un puerto que no sea de administrador, ie 1024
o superior):
hola.js
var http = require('http');http.createServer(function (req, res) { res.writeHead(200, {'Content-Type': 'text/plain'}); res.end('Hello Worldn');}).listen(8080, 'APP_PRIVATE_IP_ADDRESS');console.log('Server running at http://APP_PRIVATE_IP_ADDRESS:8080/');
Ahora guarde y salga presionando ESC
para salir --INSERT--
del modo, seguido de :wq
para write
y quit
en un solo comando.
Esta aplicación Node.js simplemente escucha en la dirección IP y el puerto especificados y devuelve "Hello World"
un 200
código HTTP de éxito. Esto significa que solo se puede acceder a la aplicación desde servidores de la misma red privada, como nuestro servidor web .
Si desea probar si su aplicación funciona, ejecute este node
comando en el servidor de aplicaciones :
- node hello.js
Nota: ejecutar una aplicación Node.js de esta manera bloqueará comandos adicionales hasta que se cierre la aplicación presionando CTRL+C
.
Ahorraremos mucho trabajo de depuración de Nginx si primero probamos que nuestro servidor web puede comunicarse con la aplicación Node.js en la aplicación .
Para probar la aplicación, abra otra sesión de terminal y conéctese a su servidor web . Debido a que el servidor web está en la misma red privada, debería poder acceder a la dirección IP privada del servidor de aplicaciones mediante curl
. Asegúrese de sustituir la dirección IP privada del servidor de aplicaciones por APP_PRIVATE_IP_ADDRESS
, y el puerto si lo cambió:
- curl http://APP_PRIVATE_IP_ADDRESS:8080
Si ve el siguiente resultado, la aplicación está funcionando correctamente y escuchando en la dirección IP y el puerto adecuados:
Node Application OutputHello World
Si no ve el resultado adecuado, asegúrese de que su aplicación Node.js esté ejecutándose y configurada para escuchar en la dirección IP y el puerto adecuados.
En el servidor de aplicaciones , asegúrese de cerrar la aplicación presionando CTRL+C
.
Paso 3: Instalación y uso de PM2
Ahora instalaremos PM2, que es un administrador de procesos para aplicaciones Node.js. PM2 proporciona una manera sencilla de administrar y convertir aplicaciones en daemon (ejecutarlas como un servicio).
Usaremos Node Packaged Modules (NPM), que es básicamente un administrador de paquetes para módulos de Node que se instala con Node.js, para instalar PM2 en nuestro servidor de aplicaciones . Use este comando para instalar PM2:
- sudo npm install pm2@latest -g
Cubriremos algunos usos básicos de PM2.
Lo primero que querrás hacer es usar el pm2 start
comando para ejecutar tu aplicación, hello.js
, en segundo plano:
- pm2 start hello.js
Esto también agrega su aplicación a la lista de procesos de PM2, que se genera cada vez que inicia una aplicación:
Output┌──────────┬────┬──────┬───────┬────────┬─────────┬────────┬─────────────┬──────────┐│ App name │ id │ mode │ pid │ status │ restart │ uptime │ memory │ watching │├──────────┼────┼──────┼───────┼────────┼─────────┼────────┼─────────────┼──────────┤│ hello │ 0 │ fork │ 30099 │ online │ 0 │ 0s │ 14.227 MB │ disabled │└──────────┴────┴──────┴───────┴────────┴─────────┴────────┴─────────────┴──────────┘
Como puede ver, PM2 asigna automáticamente un nombre de aplicación (basado en el nombre del archivo, sin la .js
extensión) y un ID de PM2. PM2 también mantiene otra información, como el PID del proceso, su estado actual y el uso de memoria.
Las aplicaciones que se ejecutan en PM2 se reiniciarán automáticamente si fallan o se cierran, pero es necesario realizar un paso adicional para que la aplicación se inicie al iniciar el sistema (arranque o reinicio). Afortunadamente, PM2 ofrece una forma sencilla de hacerlo: el startup
subcomando.
El startup
subcomando genera y configura un script de inicio para iniciar PM2 y sus procesos administrados en el arranque del servidor. También debe especificar el sistema de inicio en el que se está ejecutando, que es systemd
, en nuestro caso:
- sudo pm2 startup systemd
Verá un resultado como el siguiente, que indica que se ha instalado el servicio PM2:
Output[PM2] Generating system init script in /etc/systemd/system/pm2.service[PM2] Making script booting at startup...[PM2] -systemd- Using the command: su root -c "pm2 dump pm2 kill" su root -c "systemctl daemon-reload systemctl enable pm2 systemctl start pm2"[PM2] Dumping processes[PM2] Stopping PM2...[PM2] All processes have been stopped and deleted[PM2] PM2 stopped[PM2] Done.
Para garantizar que PM2 sepa qué aplicaciones debe iniciar al arrancar, debemos guardar la lista de procesos actual. Para guardar la lista:
- pm2 save
Verá un resultado como el siguiente, que indica que se ha guardado la lista de procesos PM2:
Output[PM2] Saving current process list...[PM2] Successfully saved in /home/deployer/.pm2/dump.pm2
Ahora sus aplicaciones administradas por PM2 deberían iniciarse automáticamente durante el arranque.
PM2 ofrece muchos subcomandos que le permiten administrar o buscar información sobre sus aplicaciones. Tenga en cuenta que si se ejecuta pm2
sin argumentos, se mostrará una página de ayuda, que incluye ejemplos de uso, que cubren el uso de PM2 con más detalle que esta sección del tutorial.
Detenga una aplicación con este comando (especifique PM2 App name
o id
):
- pm2 stop example
Reinicie una aplicación con este comando (especifique PM2 App name
o id
):
- pm2 restart example
La lista de aplicaciones administradas actualmente por PM2 también se puede consultar con el list
subcomando:
- pm2 list
Se puede encontrar más información sobre una aplicación específica utilizando el info
subcomando (especifique el nombre o el ID de la aplicación PM2):
- pm2 info example
El monitor de procesos PM2 se puede abrir con el monit
subcomando. Esto muestra el estado de la aplicación, la CPU y el uso de la memoria:
- pm2 monit
Nota: ejecutar el comando PM2 monit
bloqueará comandos adicionales hasta que se cierre la aplicación presionando CTRL+C
.
Ahora que su aplicación Node.js está ejecutándose y administrada por PM2, configuremos el proxy inverso.
Paso 4: Configuración de un servidor proxy inverso Nginx
Ahora que su aplicación está ejecutándose y escuchando en una dirección IP privada, necesita configurar una forma para que sus usuarios accedan a ella. Configuraremos un servidor web Nginx como proxy inverso para este propósito. Este tutorial configurará un servidor Nginx desde cero. Si ya tiene un servidor Nginx configurado, puede simplemente copiar el location
bloque en el bloque de servidor que elija (asegúrese de que la ubicación no entre en conflicto con ningún contenido existente de su servidor web).
En el servidor web , instalemos el epel-release
paquete usando yum:
- sudo yum install epel-release
Luego instala Nginx:
- sudo yum install nginx
Ahora abra el archivo de configuración de Nginx para editarlo:
- sudo vi /etc/nginx/nginx.conf
En primer lugar, busque la línea donde server_name
se define, dentro del bloque de servidor predeterminado. Debería verse así:
Extracto de nginx.conf — server_name (antes)
server_name _;
Actualice el nombre del servidor para sustituir el guión bajo ( _
) con su propio nombre de dominio para la server_name
directiva (o dirección IP si no tiene un dominio configurado).
Extracto de nginx.conf — server_name (después)
server_name your-domain;
Luego, busque la línea donde location /
se define (normalmente unas líneas debajo de server_name), dentro del mismo bloque de servidor predeterminado. Debería verse algo así:
Extracto de nginx.conf — ubicación / (antes)
location / { }
Reemplácelo con el siguiente bloque de código y asegúrese de sustituir la dirección IP privada del servidor de aplicaciones por APP_PRIVATE_IP_ADDRESS
. Además, cambie el puerto ( 8080
) si su aplicación está configurada para escuchar en un puerto diferente:
Extracto de /etc/nginx/nginx.conf — ubicación / (después)
location / { proxy_pass http://APP_PRIVATE_IP_ADDRESS:8080; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection 'upgrade'; proxy_set_header Host $host; proxy_cache_bypass $http_upgrade; }
Esto configura el servidor webyour-domain
para que responda a las solicitudes en su raíz. Suponiendo que nuestro servidor está disponible en , el acceso http://your-domain/
a través de un navegador web enviaría la solicitud a la dirección IP privada del servidor de aplicaciones en el puerto 8080
, que sería recibida y respondida por la aplicación Node.js.
Puedes agregar location
bloques adicionales al mismo bloque de servidor para brindar acceso a otras aplicaciones en el mismo servidor web . Por ejemplo, si también estuvieras ejecutando otra aplicación Node.js en el servidor de aplicaciones en el puerto 8081
, podrías agregar este bloque de ubicación para permitir el acceso a ella mediante http://your-domain/app2
:
Configuración de Nginx: ubicaciones adicionales
location /app2 { proxy_pass http://APP_PRIVATE_IP_ADDRESS:8081; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection 'upgrade'; proxy_set_header Host $host; proxy_cache_bypass $http_upgrade; }
Una vez que haya terminado de editar los bloques de ubicación para sus aplicaciones, guarde y salga presionando ESC
para salir --INSERT--
del modo, seguido de :wq
para write
y quit
en un solo comando.
En el servidor web , reinicie Nginx:
- sudo systemctl start nginx
A continuación queremos asegurarnos de que Nginx se ejecute cada vez que se reinicie el servidor:
- sudo systemctl enable nginx
El enable
comando debe proporcionar la siguiente salida
OutputCreated symlink from /etc/systemd/system/multi-user.target.wants/nginx.service to /usr/lib/systemd/system/nginx.service.
También puede confirmar que Nginx se está ejecutando y está habilitado solicitando su estado a systemctl
:
- sudo systemctl status nginx
El comando de estado generará información de configuración para el servicio Nginx:
Output● nginx.service - The nginx HTTP and reverse proxy server Loaded: loaded (/usr/lib/systemd/system/nginx.service; enabled; vendor preset: disabled) Active: active (running) since Mon 2019-10-14 09:37:23 UTC; 3min 29s ago Main PID: 12818 (nginx) CGroup: /system.slice/nginx.service ├─12818 nginx: master process /usr/sbin/nginx └─12819 nginx: worker processOct 14 09:37:23 centos-s-1vcpu-1gb-sgp1-01 systemd[1]: Starting The nginx HTTP and reverse proxy server...Oct 14 09:37:23 centos-s-1vcpu-1gb-sgp1-01 nginx[12814]: nginx: the configuration file /etc/nginx/nginx.conf syntax is okOct 14 09:37:23 centos-s-1vcpu-1gb-sgp1-01 nginx[12814]: nginx: configuration file /etc/nginx/nginx.conf test is successfulOct 14 09:37:23 centos-s-1vcpu-1gb-sgp1-01 systemd[1]: Failed to read PID from file /run/nginx.pid: Invalid argumentOct 14 09:37:23 centos-s-1vcpu-1gb-sgp1-01 systemd[1]: Started The nginx HTTP and reverse proxy server.
Por último, se proporciona a Nginx la capacidad de retransmitir tráfico a través de Security-Enhanced Linux (SELinux). SELinux proporciona una capa de seguridad que implementa el Control de acceso obligatorio (MAC) en el núcleo de Linux. Cada objeto del sistema operativo (proceso, descriptor de archivo, archivo, etc.) se etiqueta con un contexto SELinux que define los permisos y las operaciones que puede realizar el objeto.
Nginx está etiquetado con el httpd_t
contexto y, como resultado, SELinux bloquea una serie de configuraciones a menos que se permita explícitamente. Para demostrarlo, ejecute el siguiente comando para confirmar que el servicio Nginx está etiquetado httpd_t
:
- ps -eZ
Este comando proporciona información sobre el estado del proceso. Busque la información del proceso específico de Nginx para ver la etiqueta. Verá el httpd_t
, de manera similar a la siguiente:
Output...system_u:system_r:httpd_t:s0 10208 ? 00:00:00 nginxsystem_u:system_r:httpd_t:s0 10209 ? 00:00:00 nginx...
Ahora, verifiquemos el estado de los valores booleanos predeterminados relacionados con la httpd_t
etiqueta SELinux. Podemos mostrar esta información ejecutando el siguiente comando:
- getsebool -a
httpd
Para este tutorial solo nos interesan los valores booleanos relacionados:
Output...httpd_anon_write -- offhttpd_builtin_scripting -- onhttpd_can_check_spam -- offhttpd_can_connect_ftp -- offhttpd_can_connect_ldap -- offhttpd_can_connect_mythtv -- offhttpd_can_connect_zabbix -- offhttpd_can_network_connect -- offhttpd_can_network_connect_cobbler -- offhttpd_can_network_connect_db -- offhttpd_can_network_memcache -- offhttpd_can_network_relay -- offhttpd_can_sendmail -- offhttpd_dbus_avahi -- offhttpd_dbus_sssd -- offhttpd_dontaudit_search_dirs -- offhttpd_enable_cgi -- onhttpd_enable_ftp_server -- offhttpd_enable_homedirs -- offhttpd_execmem -- offhttpd_graceful_shutdown -- onhttpd_manage_ipa -- offhttpd_mod_auth_ntlm_winbind -- offhttpd_mod_auth_pam -- offhttpd_read_user_content -- offhttpd_run_ipa -- offhttpd_run_preupgrade -- offhttpd_run_stickshift -- offhttpd_serve_cobbler_files -- offhttpd_setrlimit -- offhttpd_ssi_exec -- offhttpd_sys_script_anon_write -- offhttpd_tmp_exec -- offhttpd_tty_comm -- offhttpd_unified -- offhttpd_use_cifs -- offhttpd_use_fusefs -- offhttpd_use_gpg -- offhttpd_use_nfs -- offhttpd_use_openstack -- offhttpd_use_sasl -- offhttpd_verify_dns -- off...
Los dos booleanos que se deben tener en cuenta son httpd_can_network_connect
y httpd_can_network_relay
. La documentación de Redhat proporciona detalles sobre cada uno de los httpd
booleanos y su función asociada (si desea obtener más información sobre cada booleano), aunque a continuación se incluyen las explicaciones de los dos booleanos relacionados con este tutorial:
...httpd_can_network_connect: When disabled, this Boolean prevents HTTP scripts and modules from initiating a connection to a network or remote port. Enable this Boolean to allow this access.httpd_can_network_relay: Enable this Boolean when httpd is being used as a forward or reverse proxy....
Dado que nuestra configuración solo retransmite tráfico, solo tenemos que indicarle a SELinux que el httpd
servidor, en nuestro caso Nginx, puede usar la red para retransmitir tráfico en la configuración de proxy inverso que hemos configurado. Usaremos el -P
indicador para asegurarnos de que los cambios sean permanentes (omitir este indicador hará que httpd_can_network_relay
vuelva a su estado predeterminado, apagado, al reiniciar el servidor):
- sudo setsebool -P httpd_can_network_relay on
Suponiendo que su aplicación Node.js se esté ejecutando y que las configuraciones de su aplicación y Nginx sean correctas, debería poder acceder a su aplicación a través del proxy inverso del servidor web . Pruébelo accediendo a la URL de su servidor web (su dirección IP pública o nombre de dominio).
Nota: Si también planeaba usar su servidor web para alojar otros sitios (como hosts virtuales convencionales), entonces también necesitará activarlo httpd_can_network_connect
.
Conclusión
Ahora tienes tu aplicación Node.js ejecutándose detrás de un proxy inverso Nginx. Esta configuración de proxy inverso es lo suficientemente flexible como para brindar a tus usuarios acceso a otras aplicaciones o contenido web estático que quieras compartir.
Además, si buscas cifrar las transmisiones entre tu servidor web y tus usuarios, aquí tienes un tutorial que te ayudará a configurar el soporte HTTPS (TLS/SSL).
Deja una respuesta