Publicaciones
Configuración de Integración Continua en Ubuntu con Nodejs
15 de agosto de 2015 • 11 min de lectura
Pasé por sangre, sudor y lágrimas para traerte esto. Sufrí el calor abrasador del Valle de la Muerte y escalé los picos del Monte McKinley. He sacrificado mucho.
Gran parte del contenido compartido en este artículo no es trabajo original mío. Cuando puedo, enlazo al trabajo original.
Este artículo asume que puedes moverte por Linux.
No pude encontrar una guía completa sobre cómo alojar y gestionar aplicaciones Nodejs en Ubuntu en capacidad de producción. He reunido múltiples artículos sobre el tema. Al final de este artículo, espero que puedas configurar tu propio servidor Ubuntu y tener Nodejs desplegándose a través de un servidor de integración continua.
Entorno
Estoy usando TeamCity en Windows que luego despliega código desde GitHub a Ubuntu alojado en AWS.
Tecnologías
Para este artículo utilicé las siguientes tecnologías:
- Ubuntu 14.04 en AWS
- Plink 0.64
- TeamCity 9.1
- GitHub
- Nginx 1.9.3
Configuración de Ubuntu
No voy a entrar en detalles aquí. Amazon Web Services (AWS) hace que esto sea bastante fácil. No importa dónde esté o si está en tu propio servidor.
Encontré algunos problemas. Primero, asegúrate de que el puerto 80 esté abierto. Cometí el error tonto de intentar conectarme con el puerto 80 cerrado. Una vez que descubrí mi error, me sentí como el trasero de un rinoceronte.
Instalación de Nodejs desde la fuente
Nodejs es una tecnología de servidor que utiliza el motor de javascript V8 de Google. Desde su lanzamiento en 2010, se ha vuelto ampliamente popular.
Las siguientes instrucciones provienen originalmente de un post de Digital Ocean (post).
Siempre tienes la opción de instalar Nodejs desde apt-get, pero estará algunas versiones atrás. Para obtener las últimas versiones, instala Nodejs desde la fuente.
Al final de esta sección habremos descargado la última versión estable de node (según este artículo), habremos compilado la fuente e instalado Nodejs.
Inicia sesión en tu servidor. Comenzaremos actualizando las listas de paquetes.
sudo apt-get update
También te sugiero que actualices todos los paquetes. Esto no es necesario para Nodejs, pero es una buena práctica mantener tu servidor actualizado.
sudo apt-get upgrade
Tu servidor está completamente actualizado. Es hora de descargar la fuente.
cd ~
En el momento de escribir esto, 12.7 es la última versión estable de Nodejs. Consulta nodejs.org para la última versión.
wget https://nodejs.org/dist/v0.12.7/node-v0.12.7.tar.gz
Extrae el archivo que has descargado.
tar xvf node-v*
Muévete al directorio recién creado
cd node-v*
Configura y compila Nodejs.
./configure
make
Instala Nodejs
sudo make install
Para eliminar los archivos descargados y extraídos. Por supuesto, esto es opcional.
cd ~
rm -rf node-v*
¡Felicidades! ¡Nodejs está instalado! Y no fue muy difícil.
Configuración de Nginx
Nodejs puede actuar como servidor web, pero no es lo que querría exponer al mundo. Un servidor web industrial, endurecido y rico en características es más adecuado para esto. He recurrido a Nginx para esta tarea.
Es un servidor web maduro con las características que necesitamos. Para ejecutar más de una instancia de Nodejs, necesitaremos reenvío de puertos.
Podrías estar pensando, ¿por qué necesitamos más de una instancia de Nodejs ejecutándose al mismo tiempo? Es una pregunta justa… En mi escenario, tengo un servidor y necesito ejecutar DEV, QA y PROD en la misma máquina. Sí, lo sé, no es ideal, pero no quiero configurar 3 servidores para cada entorno.
Para comenzar, instalemos Nginx
sudo -s
add-apt-repository ppa:nginx/stable
apt-get update
apt-get install nginx
Una vez que Nginx se ha instalado correctamente, necesitamos configurar los dominios. Voy a asumir que querrás tener cada uno de tus sitios en su propio dominio/subdominio. Si no es así y quieres usar diferentes subcarpetas, eso es posible y muy fácil de hacer. No voy a cubrir ese escenario aquí. Hay toneladas de documentación sobre cómo hacerlo. Hay muy poca documentación sobre la configuración de diferentes dominios y reenvío de puertos a las instancias correspondientes de Nodejs. Esto es lo que voy a cubrir.
Ahora que Nginx está instalado, crea un archivo para yourdomain.com en /etc/nginx/sites-available/
sudo nano /etc/nginx/sites-available/yourdomain.com
Añade la siguiente configuración a tu archivo recién creado
# the IP(s) on which your node server is running. I chose port 9001.
upstream app_myapp1 {
server 127.0.0.1:9001;
keepalive 8;
}
# the nginx server instance
server {
listen 80;
server_name yourdomain.com;
access_log /var/log/nginx/yourdomain.log;
# pass the request to the node.js server with the correct headers
# and much more can be added, see nginx config options
location / {
proxy_http_version 1.1;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_set_header X-NginX-Proxy true;
proxy_pass http://app_myapp1;
}
}
Asegúrate de reemplazar “yourdomain.com” con tu dominio real. Guarda y sal de tu editor.
Crea un enlace simbólico a este archivo en el directorio sites-enabled.
cd /etc/nginx/sites-enabled/
ln -s /etc/nginx/sites-available/yourdomain.com yourdomain.com
Para probar que todo funciona correctamente, crea una aplicación node simple y guárdala en /var/www/yourdomain.com/app.js y ejecútala.
Aquí hay una aplicación nodejs simple si no tienes una a mano.
var http = require('http');
http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end('Hello World\n');}).listen(9001, "127.0.0.1");
console.log('Server running at http://127.0.0.1:9001/');
Reiniciemos Nginx.
sudo /etc/init.d/nginx restart
No olvides iniciar tu instancia de Nodejs, si aún no lo has hecho.
cd /var/www/yourdomain/ && node app.js
Si todo funciona correctamente, cuando navegues a yourdomain.com verás “Hello World.”
Para añadir otro dominio para una instancia diferente de Nodejs, necesitas repetir los pasos anteriores. Específicamente, necesitarás cambiar el nombre upstream, el puerto y el dominio en tu nuevo archivo de configuración de Nginx. La dirección proxy_pass debe coincidir con el nombre upstream en el archivo de configuración de nginx. Mira el nombre upstream y el valor proxy_pass y verás a qué me refiero.
Para resumir, hemos instalado NodeJS desde la fuente y acabamos de terminar de instalar Nginx. Hemos configurado y probado el reenvío de puertos con Nginx y Nodejs
Instalación de PM2
Podrías estar preguntando “¿Qué es PM2?” como lo hice cuando lo escuché por primera vez. PM2 es un gestor de procesos para aplicaciones Nodejs. Nodejs no viene con mucho. Eso es parte de su atractivo. La desventaja de esto es que, bueno, tienes que proporcionar las capas frente a él. PM2 es una de esas capas.
PM2 gestiona la vida del proceso de Nodejs. Cuando se termina, PM2 lo reinicia. Cuando el servidor se reinicia, PM2 reinicia todos los procesos de Nodejs para ti. También tiene un extenso proceso del ciclo de vida del desarrollo. No vamos a cubrir este aspecto de PM2. Te animo a que leas la documentación bien escrita.
Asumiendo que has iniciado sesión en la terminal, comenzaremos instalando PM2 a través de NPM. Npm es el gestor de paquetes de Nodejs (npm). Se instaló cuando instalaste Nodejs.
sudo npm install pm2 -g
Eso es todo. PM2 está instalado.
Uso de PM2
PM2 es fácil de usar.
El hola mundo para PM2 es simple.
pm2 start hello.js
Esto añade tu aplicación a la lista de procesos de PM2. Esta lista se genera cada vez que se inicia una aplicación.

En este ejemplo hay dos aplicaciones Nodejs ejecutándose. Una llamada api.dev y api.pre.
PM2 asigna automáticamente el nombre de la aplicación al “App name” en la lista.
De serie, PM2 no se configura para iniciarse cuando el servidor se reinicia. El comando es diferente para los diferentes sabores de Linux. Estoy ejecutando en Ubuntu, así que ejecutaré el comando de Ubuntu.
pm2 start ubuntu
Aún no hemos terminado. Tenemos que añadir una ruta al binario de PM2. Afortunadamente, la salida del comando anterior nos dice cómo hacerlo.
Salida:
[PM2] You have to run this command as root
[PM2] Execute the following command :
[PM2] sudo env PATH=$PATH:/usr/local/bin pm2 startup ubuntu -u sammy
Ejecuta el comando que se generó (similar a la salida resaltada anterior) para configurar PM2 para que se inicie al arrancar (usa el comando de tu propia salida):
sudo env PATH=$PATH:/usr/local/bin pm2 startup ubuntu -u sammy
Ejemplos de otros usos de PM2 (opcional)
Detener una aplicación por nombre de aplicación
pm2 stop example
Reiniciar por nombre de aplicación
pm2 restart example
Lista de aplicaciones actuales gestionadas por PM2
pm2 list
Especificar un nombre al iniciar un proceso. Si llamas, PM2 usa el archivo javascript como nombre. Esto podría no funcionar para ti. Aquí te mostramos cómo especificar el nombre.
pm2 start www.js --name api.pre
Eso debería ser suficiente para que comiences con PM2. Para obtener más información sobre las capacidades de PM2, visita el Repositorio de GitHub.
Configuración y uso de Plink
Probablemente estés pensando, “¿Qué en nombre de la vaca de Betsey es Plink?” Al menos eso pensé. Todavía no estoy seguro qué pensar al respecto. Nunca he visto nada parecido.
¿Alguna vez has visto la película Wall-e? Wall-e saca una cuchara. Primero intenta ponerla con los tenedores, pero no encaja y luego intenta ponerla con las cucharas, pero tampoco encaja. Bueno, eso es Plink. Es un cruce entre Putty (SSH) y la línea de comandos de Windows.
Plink básicamente te permite ejecutar comandos bash a través de la línea de comandos de Windows mientras estás conectado a un shell de Linux (y probablemente Unix).
Comienza descargando Plink. Es solo un ejecutable. Te recomiendo que lo pongas en C:/Program Files (x86)/Plink. Lo necesitaremos más adelante.
Si estás ejecutando una instancia de Ubuntu en AWS. Ya tendrás un certificado configurado para Putty (asumo que estás usando Putty).
Si no es así, necesitarás asegurarte de que tienes un certificado ssh compatible para Ubuntu en AWS.
Si no estás usando AWS, puedes especificar el nombre de usuario y la contraseña en la línea de comandos y no tendrás que preocuparte por los certificados ssh.
Aquí hay un ejemplo de línea de comandos que se conecta a Ubuntu con Plink.
"C:\Program Files (x86)\Plink\plink.exe" -ssh ubuntu@xx.xx.xx.xx -i "C:\Program Files (x86)\Plink\ssh certs\aws-ubuntu.ppk"

Esto podría estar adelantándose, pero para ejecutar un script ssh en el servidor Ubuntu añadimos la ruta completa al final del comando Plink.
"C:\Program Files (x86)\Plink\plink.exe" -ssh ubuntu@xx.xx.xx.xx -i "C:\Program Files (x86)\Plink\ssh certs\aws-ubuntu.ppk" /var/www/deploy-dev-ui.sh
Y eso, querido lector, es Plink.
Entendiendo NODE_ENV
NODE_ENV es una variable de entorno popularizada por expressjs. Antes de iniciar la instancia de node, establece NODE_ENV al entorno. En el código puedes cargar archivos específicos basados en el entorno.
Configuración de NODE_ENV
Linux & Mac: export NODE_ENV=PROD
Windows: set NODE_ENV=PROD
La variable de entorno se recupera dentro de una instancia de Nodejs usando process.env.NODE_ENV.
ejemplo
var environment = process.env.NODE_ENV
o con expressjs
app.get('env')
*Nota: app.get('env') por defecto es “development”.
Juntándolo todo
Nodejs, PM2, Nginx y Plink están instalados y esperemos que funcionando. Ahora necesitamos reunir todas estas piezas en una solución de integración continua.
Clona tu repositorio de GitHub en /var/www/yourdomain.com. Aunque SSH es más seguro que HTTPS, te recomiendo que uses HTTPS. Sé que esto no es ideal, pero no pude hacer que Plink funcionara con GitHub en Ubuntu. Sin entrar en demasiados detalles, Plink y los formatos de certificados SSH de GitHub son diferentes y llamar a GitHub a través de Plink mediante SSH no funcionó. ¡Si puedes resolver el problema, házmelo saber!
Para hacer que el pull de GitHub sea sin intervención, el nombre de usuario y la contraseña necesitarán ser parte de la URL de origen.
Aquí te mostramos cómo establecer tu URL de origen. Por supuesto, necesitarás sustituir tu información donde sea apropiado.
git remote set-url origin https://username:password@github.com/username/yourdomain.git
Clona tu repositorio.
cd /var/www/yourdomain.com
git clone https://username:password@github.com/username/yourdomain.git .
Ten en cuenta que si este directorio no está completamente vacío, incluidos los archivos ocultos, Git no clonará el repositorio en este directorio.
Para encontrar archivos ocultos en el directorio, ejecuta este comando
ls -a
Para el pegamento, estamos usando un script de shell. Aquí hay una copia de mi script.
#!/bin/bash
echo "> Current PM2 Apps"
pm2 list
echo "> Stopping running API"
pm2 stop api.dev
echo "> Set Environment variable."
export NODE_ENV=DEV
echo "> Changing directory to dev.momentz.com."
cd /var/www/yourdomain.com
echo "> Listing the contents of the directory."
ls -a
echo "> Remove untracked directories in addition to untracked files."
git clean -f -d
echo "> Pull updates from Github."
git pull
echo "> Install npm updates."
sudo npm install
echo "> Transpile the ECMAScript 2015 code"
gulp babel
echo "> Restart the API"
pm2 start transpiled/www.js --name api.dev
echo "> List folder directories"
ls -a
echo "> All done."
Lanzo este script de shell con TeamCity, pero puedes lanzarlo con cualquier cosa.
Aquí está el comando sin procesar.
"C:\Program Files (x86)\Plink\plink.exe" -ssh ubuntu@xx.xx.xx.xx -i "C:\Program Files (x86)\Plink\ssh certs\aws-ubuntu.ppk" /var/www/deploy-yourdomain.sh
exit
>&2
Eso es todo.
En conclusión
Este proceso tiene algunos bordes ásperos… Espero pulir esos bordes con el tiempo. Si tienes sugerencias, déjalas en los comentarios.
Este documento está en mi Repositorio de GitHub. Las tecnologías cambian, así que si encuentras un error, actualízalo. Luego actualizaré este artículo.
Autor: Chuck Conway es un Ingeniero de IA con casi 30 años de experiencia en ingeniería de software. Construye sistemas de IA prácticos—canalizaciones de contenido, agentes de infraestructura y herramientas que resuelven problemas reales—y comparte lo que está aprendiendo en el camino. Conéctate con él en redes sociales: X (@chuckconway) o visítalo en YouTube y en SubStack.