VPS

Cómo desplegar una app de Node.js en un VPS con Nginx, PM2 y HTTPS

Publica tu aplicación de Node.js en un VPS con Ubuntu 24.04 para que funcione siempre en tu dominio y con HTTPS. Instalamos Node LTS, mantenemos la app viva con PM2, configuramos Nginx como proxy inverso, activamos Let’s Encrypt y resolvemos los errores más comunes.

Equipo HostSpace

9 min de lectura

Portada del artículo: Cómo desplegar una app de Node.js en un VPS con Nginx, PM2 y HTTPS

Lo esencial

  • Tu app escucha en un puerto local y Nginx recibe las visitas en 80 y 443.
  • PM2 la mantiene viva y la levanta tras un reinicio con pm2 startup y pm2 save.
  • Certbot con el plugin de Nginx activa HTTPS gratis y lo renueva solo.
  • Un 502 Bad Gateway casi siempre significa que la app no está corriendo.
Contenido del artículo

Antes de empezar

En esta guía vas a publicar una aplicación de Node.js en un VPS con Ubuntu 24.04, de forma que siga funcionando aunque cierres la terminal, se reinicie sola si falla y responda en tu dominio con HTTPS. La arquitectura es la más común en producción: tu app escucha en un puerto local, PM2 la mantiene viva y Nginx recibe las visitas y se las pasa.

Necesitas tener listo lo siguiente:

  • Un VPS con Ubuntu 24.04 y acceso por SSH con un usuario con sudo (no root). Si aún entras con contraseña, primero configura tus llaves SSH.
  • Un dominio cuyo registro A apunte a la IP del servidor, por ejemplo 203.0.113.10. Te explicamos cómo en apuntar tu dominio a tu hosting.
  • Tu aplicación en un repositorio Git (GitHub, GitLab u otro).

Paso 1: instalar Node.js LTS

Los repositorios de Ubuntu suelen traer una versión de Node atrasada. Usa siempre una versión LTS (soporte extendido), que es la recomendada para producción. Tienes dos opciones:

  1. NodeSource, que instala Node para todo el sistema con apt y se actualiza junto con el resto de paquetes:
Terminal
curl -fsSL https://deb.nodesource.com/setup_lts.x | sudo -E bash -
sudo apt install -y nodejs git
node -v
npm -v
  1. nvm, si necesitas varias versiones de Node en el mismo servidor. Instala nvm desde su repositorio oficial y luego ejecuta nvm install --lts. Ten en cuenta que con nvm Node queda instalado solo para tu usuario.

Paso 2: clonar e instalar tu aplicación

Crea una carpeta para tus aplicaciones, clona el repositorio e instala las dependencias. Usa npm ci en lugar de npm install: instala exactamente lo que dice tu package-lock.json y falla si algo no coincide.

Terminal
sudo mkdir -p /var/www && sudo chown $USER:$USER /var/www
cd /var/www
git clone https://github.com/tu-usuario/tunegocio.git
cd tunegocio
npm ci
npm run build

Omite npm run build si tu proyecto no tiene paso de compilación. Antes de seguir, comprueba que la app arranca con npm start y que responde en http://127.0.0.1:3000 con curl desde otra terminal.

Variables de entorno

Las contraseñas de base de datos, llaves de API y demás secretos no van en el repositorio. Una forma sencilla es declararlas en un archivo de configuración de PM2 que solo existe en el servidor:

ecosystem.config.cjs
module.exports = {
  apps: [
    {
      name: 'tunegocio',
      script: 'dist/server.js',
      cwd: '/var/www/tunegocio',
      env: {
        NODE_ENV: 'production',
        PORT: 3000,
        DATABASE_URL: 'postgres://usuario:clave@127.0.0.1:5432/tunegocio',
      },
    },
  ],
};

Agrega ecosystem.config.cjs a tu .gitignore y protégelo con chmod 600. Cambia script por el archivo de entrada de tu app.

Paso 3: mantener la app viva con PM2

Si ejecutas node server.js directamente, la app se detiene en cuanto cierras la sesión SSH. PM2 es un gestor de procesos que la ejecuta en segundo plano, la reinicia si falla y la vuelve a levantar cuando el servidor se reinicia.

  1. Instala PM2 de forma global con sudo npm install -g pm2.
  2. Inicia la app con pm2 start ecosystem.config.cjs y revisa que aparezca como online con pm2 status.
  3. Ejecuta pm2 startup. PM2 te mostrará un comando que empieza con sudo env PATH=...: cópialo y ejecútalo tal cual para registrar PM2 como servicio del sistema.
  4. Guarda la lista de procesos con pm2 save. Así PM2 sabe qué apps levantar al arrancar el servidor.

Para ver los registros en vivo usa pm2 logs tunegocio; te servirán para diagnosticar casi cualquier problema.

Paso 4: configurar Nginx como proxy inverso

Nginx atiende los puertos 80 y 443, maneja HTTPS y reenvía cada petición a tu app en el puerto 3000. Instálalo con sudo apt install -y nginx y crea un archivo para tu sitio:

/etc/nginx/sites-available/tunegocio.mx
server {
    listen 80;
    listen [::]:80;
    server_name tunegocio.mx www.tunegocio.mx;

    location / {
        proxy_pass http://127.0.0.1:3000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_cache_bypass $http_upgrade;
    }
}

Las cabeceras Upgrade y Connection permiten que funcionen los WebSockets (por ejemplo, Socket.IO). Las de X-Forwarded le dicen a tu app la IP real del visitante y si llegó por HTTPS. Ahora activa el sitio:

Terminal
sudo ln -s /etc/nginx/sites-available/tunegocio.mx /etc/nginx/sites-enabled/
sudo rm /etc/nginx/sites-enabled/default
sudo nginx -t
sudo systemctl reload nginx

nginx -t valida la sintaxis antes de aplicar cambios. Si marca un error, no recargues hasta corregirlo.

Paso 5: firewall y HTTPS con Let's Encrypt

  1. Permite el tráfico web en el firewall con sudo ufw allow 'Nginx Full', que abre los puertos 80 y 443. Verifica con sudo ufw status que SSH (OpenSSH) siga permitido antes de activar UFW.
  2. Instala Certbot con su plugin para Nginx: sudo apt install -y certbot python3-certbot-nginx.
  3. Solicita el certificado gratuito. Certbot edita tu configuración de Nginx y agrega la redirección de HTTP a HTTPS:
Terminal
sudo certbot --nginx -d tunegocio.mx -d www.tunegocio.mx
sudo certbot renew --dry-run

El segundo comando simula la renovación: los certificados de Let's Encrypt duran poco y Certbot los renueva solo con una tarea programada. Si quieres entender qué protege el certificado, lee qué es un certificado SSL.

Paso 6: publicar actualizaciones

Cada vez que subas cambios a tu repositorio, despliégalos en el servidor así:

Terminal
cd /var/www/tunegocio
git pull
npm ci
npm run build
pm2 reload tunegocio

pm2 reload reinicia la app con el menor tiempo fuera posible. Si cambiaste variables en ecosystem.config.cjs, usa pm2 reload ecosystem.config.cjs --update-env para que se apliquen. Cuando repitas estos pasos seguido, guárdalos en un script deploy.sh.

Errores comunes y cómo resolverlos

502 Bad Gateway

Nginx funciona, pero no puede hablar con tu app. Revisa con pm2 status que esté online, mira pm2 logs por si se cae al arrancar y confirma que el puerto de proxy_pass sea el mismo en el que escucha tu app. Prueba con curl http://127.0.0.1:3000 desde el servidor.

Error: listen EADDRINUSE

Otro proceso ya ocupa ese puerto, casi siempre una copia vieja de tu app que iniciaste a mano o un proceso duplicado en PM2. Encuéntralo con sudo ss -ltnp | grep 3000, detenlo y deja que solo PM2 controle la app.

La app se detiene al cerrar la sesión o tras reiniciar

Se inició con node o npm start en la terminal, o falta registrar PM2 como servicio. Iníciala con PM2 y repite pm2 startup y pm2 save. Si usas nvm, vuelve a ejecutar pm2 startup cada vez que cambies de versión de Node.

Certbot no puede validar el dominio

El registro A todavía no apunta a tu servidor o el puerto 80 está cerrado. Comprueba la IP con dig +short tunegocio.mx, espera a que se propaguen los DNS y revisa UFW.

Preguntas frecuentes

Nginx maneja HTTPS, varios dominios en el mismo servidor, archivos estáticos y conexiones lentas de forma más eficiente, y te permite tener tu app en un puerto local sin exponerla directamente.

Iníciala con un gestor de procesos como PM2 y ejecuta pm2 startup y pm2 save para que también se levante cuando el servidor se reinicie.

Que Nginx no logra conectarse con tu app: está detenida, falla al arrancar o escucha en un puerto distinto al de proxy_pass. Revisa pm2 status y pm2 logs.

Ambos sirven. NodeSource instala Node para todo el sistema y se actualiza con apt; nvm conviene si necesitas varias versiones en el mismo servidor.

Compartir

WhatsAppLinkedInXFacebook

Equipo HostSpace

Ofrecemos hosting, dominios, servidores VPS y correo corporativo con soporte en español. Escribimos sobre lo que más nos preguntan nuestros clientes.