Guía de despliegue

Desplegar una aplicación Nuxt en un VPS

Desplegar en un VPS Cloud →

Tutorial

Desarrollo

Desplegar una aplicación Nuxt en un VPS

Nuxt y su motor Nitro producen un artefacto Node.js autónomo, perfectamente adaptado al autoalojamiento en un VPS. Este enfoque le libera de las cuotas de funciones cloud y le da control total sobre la caché, las cabeceras HTTP y las estrategias de renderizado página a página. Esta guía cubre la instalación completa: elección del modo de renderizado, configuración del proyecto, build, variables de entorno, supervisión con PM2, proxy inverso Nginx y HTTPS, registros, hasta la resolución de los errores que bloquean la producción.

12 min de lectura7 pasos
Contenido· ¿Por qué autoalojar Nuxt en un VPS?1/13
  1. 01¿Por qué autoalojar Nuxt en un VPS?
  2. 02Beneficios concretos de un Nuxt autoalojado
  3. 03SSR, SSG, SPA o híbrido: ¿qué modo de renderizado elegir?
  4. 04Requisitos de hardware y software
  5. 05Partir de la plantilla Nuxt Stack
  6. 06Desplegar Nuxt paso a paso
  7. 07Variables de entorno: públicas, privadas y recarga
  8. 08Optimizar el renderizado con routeRules
  9. 09Nitro server vs Docker vs Vercel/Netlify para alojar Nuxt
  10. 10Registros: leerlos, rotarlos y cruzarlos con Nginx
  11. 11Resolución de problemas: errores comunes en producción
  12. 12Supervisión y métricas con PM2
  13. 13La documentación oficial

¿Por qué autoalojar Nuxt en un VPS?

Con Nitro, Nuxt genera un build portable (preset: node-server) que arranca como un simple servidor Node a la escucha en un puerto. Esta portabilidad es ideal para un VPS: dispone del renderizado del lado del servidor, de las rutas server/api y de la caché de rutas sin depender de un runtime edge propietario.

El autoalojamiento elimina las cuotas de funciones y le permite ajustar el almacenamiento en caché, la compresión y el número de instancias Node. Para una aplicación Vue 3 en producción con autenticación, llamadas a API de servidor y un SEO cuidado, el VPS ofrece la estabilidad de un servidor persistente y un costo fijo, sin sorpresas de facturación por invocación.

Aun así, hace falta un servidor que acepte un proceso Node.js permanente: la mayoría de los alojamientos compartidos no lo permiten, lo que descarta desde el principio el SSR y las rutas de servidor. En un VPS también elige la versión de Node.js, el proxy inverso (Nginx o Caddy) y la gestión de los certificados TLS, sin un tope artificial de CPU o memoria.

Beneficios concretos de un Nuxt autoalojado

  • Rutas de servidor server/api ilimitadas, sin facturación por llamada.
  • SSR e hidratación Vue 3 servidos desde un servidor Node persistente y estable.
  • Build Nitro portable (node-server), fácil de contenerizar y de reproducir.
  • Caché de rutas y reglas routeRules (SSR, SSG, ISR, SWR) controladas desde el servidor.
  • Varias apps Nuxt en un mismo VPS detrás de Nginx, cada una en su puerto interno (3000, 3001…).
  • Variables de entorno en runtime (runtimeConfig) gestionadas directamente en su servidor.
  • Control total sobre las cabeceras HTTP (CSP, HSTS, cache-control) vía middleware Nitro.
  • Un sitio pregenerado con nuxt generate, servido solo por Nginx, sin proceso Node.js permanente.

SSR, SSG, SPA o híbrido: ¿qué modo de renderizado elegir?

Desplace la tabla

ModoRenderizadoProceso Node.jsIdeal para
SSR (por defecto)En cada petición, en el servidorSí, supervisado por PM2Aplicación dinámica, SEO, contenido personalizado
SSG (`nuxt generate`)En el build, como HTML estáticoNo, Nginx sirve `.output/public`Blog, web corporativa, contenido que cambia poco
SPA (`ssr: false` + `nuxt generate`)En el navegadorNo, basta con NginxPanel interno, aplicación tras autenticación
Híbrido (`routeRules`)Por ruta: SSR, prerenderizado, SWR, ISRSí, servidor NitroAplicación que mezcla páginas estáticas y rutas API

Requisitos de hardware y software

Como con cualquier framework moderno, el build de Nuxt consume memoria: apunte a 2 GB de RAM como mínimo (el build puede hacerse en CI si su VPS es más modesto). En runtime, 1 vCPU y 1 GB bastan para el servidor Nitro con carga ligera; suba a 2 vCPU / 2 GB para aplicaciones con muchas rutas server/api simultáneas, y a 2 vCPU / 4 GB si varias aplicaciones Nuxt comparten el VPS.

En cuanto a versiones, parta de Nuxt 4: Nuxt 3 llegó al final de su vida útil el 31 de julio de 2026 y ya no recibe correcciones ni parches de seguridad. El despliegue descrito aquí es el mismo para ambas versiones, ya que es Nitro quien produce el servidor. Instale una línea LTS de Node.js que siga mantenida, Node.js 24 o 26 (Node.js 20 está fuera de soporte desde el 30 de abril de 2026), mediante nvm o una imagen node:24-alpine, junto con PM2 para la supervisión de procesos. node-server es el preset que Nitro aplica por defecto a un build de producción: declararlo en nuxt.config.ts solo lo hace explícito. Se requiere un dominio que apunte a su VPS para el certificado TLS. Ubuntu 22.04 o 24.04 LTS sigue siendo la base recomendada.

Partir de la plantilla Nuxt Stack

La plantilla Nuxt Stack del Marketplace de ServOrbit prepara un VPS Ubuntu 24.04 con Node.js en la línea LTS actual del repositorio de NodeSource, PM2 instalado de forma global, Nginx y PostgreSQL. Le ahorra la instalación del runtime: los pasos siguientes empiezan entonces en la configuración del proyecto.

Es un entorno de ejecución, no una aplicación con pantalla de inicio de sesión: se accede por SSH (ssh root@<ip-del-vps>) para subir el código. En el primer acceso, Nginx sirve su página por defecto en el puerto 80; quedan por preparar el virtual host de su aplicación, el certificado de Let's Encrypt (Certbot no viene preinstalado) y su código. PostgreSQL solo escucha en local, con autenticación peer para el usuario del sistema postgres (sudo -u postgres psql): suficiente para conectar una DATABASE_URL en 127.0.0.1 sin exponer la base de datos.

Desplegar Nuxt paso a paso

  1. Configurar el proyecto para Node

    Defina el preset Nitro en nuxt.config.ts:

    export default defineNuxtConfig({
      nitro: { preset: 'node-server' }
    })

    Declare sus secretos en runtimeConfig únicamente en el lado del servidor — nunca en runtimeConfig.public. En el VPS, instale Node.js 24 LTS con nvm install 24 && nvm use 24 && nvm alias default 24, luego PM2 de forma global: npm install -g pm2. En la plantilla Nuxt Stack, Node.js y PM2 ya están instalados.

  2. Compilar la aplicación

    Clone el repositorio e instale las dependencias:

    git clone https://git.sudominio.com/su-org/su-app.git /srv/nuxt-app
    cd /srv/nuxt-app
    npm ci
    npm run build

    Nitro produce una carpeta .output autónoma que contiene server/index.mjs y los assets estáticos en .output/public. Esa carpeta es todo lo que el VPS necesita para servir la aplicación en producción — también puede ensamblarla en CI y transferirla por rsync para evitar el build en el servidor.

  3. Crear el archivo de entorno

    Cree /srv/nuxt-app/.env con sus variables de runtime. Todas las variables con prefijo NUXT_ sobreescriben las claves correspondientes de runtimeConfig al arrancar:

    NUXT_MY_SECRET_KEY=valor-produccion
    NITRO_HOST=127.0.0.1
    NITRO_PORT=3000

    Nunca incluya este archivo en el repositorio. Asegúrese de que pertenece al usuario que ejecuta PM2 y solo es legible por ese usuario (chmod 600).

    Con NITRO_HOST=127.0.0.1, Nitro solo escucha en la interfaz local: únicamente Nginx puede alcanzarlo y el puerto 3000 no queda expuesto a Internet.

  4. Arrancar el servidor Nitro con PM2

    Inicie la aplicación en modo cluster pidiendo a Node que cargue el archivo de entorno: Nuxt no lee .env en producción y la línea de comandos de PM2 no tiene una opción dedicada.

    pm2 start /srv/nuxt-app/.output/server/index.mjs \
      --name nuxt-app -i max \
      --node-args="--env-file=/srv/nuxt-app/.env"
    pm2 save
    pm2 startup

    -i max lanza una instancia por vCPU; este modo cluster es lo que permite las recargas sin corte del último paso. El comando pm2 startup muestra una línea para copiar y pegar que crea el servicio systemd. Ejecútela con permisos de administrador. Verifique que la aplicación está en línea: pm2 status debe mostrar el estado online.

  5. Configurar Nginx como reverse proxy

    Cree /etc/nginx/sites-available/nuxt-app:

    server {
        listen 80;
        server_name sudominio.com www.sudominio.com;
    
        location /_nuxt/ {
            root /srv/nuxt-app/.output/public;
            expires 1y;
            add_header Cache-Control "public, immutable";
        }
    
        location /favicon.ico {
            root /srv/nuxt-app/.output/public;
        }
    
        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;
        }
    }

    Active el sitio y pruebe la configuración: ln -s /etc/nginx/sites-available/nuxt-app /etc/nginx/sites-enabled/ && nginx -t && systemctl reload nginx.

  6. Activar HTTPS con Let's Encrypt

    Instale Certbot y el plugin de Nginx, luego genere el certificado:

    apt install certbot python3-certbot-nginx
    certbot --nginx -d sudominio.com -d www.sudominio.com

    Certbot modifica automáticamente el bloque Nginx para escuchar en el puerto 443 y forzar la redirección HTTP → HTTPS. Verifique que X-Forwarded-Proto se transmite correctamente a Nitro — sin ello, useRequestHeaders() en el lado del servidor y las redirecciones basadas en el protocolo pueden comportarse incorrectamente. La renovación automática la gestiona el timer systemd de Certbot, comprobable con systemctl status certbot.timer.

  7. Actualizar sin interrupción del servicio

    Para una actualización, el reload de PM2 (no el restart) garantiza la continuidad. Agrupe los comandos en un script /srv/nuxt-app/deploy.sh, que set -e detiene en el primer error, antes de cualquier recarga:

    #!/bin/bash
    set -e
    cd /srv/nuxt-app
    git pull origin main
    npm ci
    npm run build
    pm2 reload nuxt-app

    Hágalo ejecutable (chmod +x deploy.sh) y llámelo desde su pipeline de CI/CD por SSH. En modo cluster, PM2 sustituye las instancias una a una: la nueva versión toma el relevo antes de que se detenga la antigua. Para un rollback, vuelva al commit anterior, reconstruya y recargue. Si el build se hace en CI, transfiera únicamente la carpeta .output por rsync y recargue sin reconstruir en el servidor.

Variables de entorno: públicas, privadas y recarga

Nuxt organiza su configuración de ejecución en dos niveles. Las claves situadas bajo runtimeConfig.public se envían al navegador y siguen siendo legibles en el servidor: URL pública de la API, identificador de analítica. Las demás claves de runtimeConfig nunca salen del servidor: claves secretas, acceso a la base de datos.

Al arrancar, una variable de entorno sustituye a la clave correspondiente si sigue la convención NUXT_<NOMBRE>, o NUXT_PUBLIC_<NOMBRE> para una clave pública: NUXT_PUBLIC_API_BASE reemplaza runtimeConfig.public.apiBase. Un valor leído de otra forma, por ejemplo process.env.OTRA_VARIABLE escrito en nuxt.config.ts, solo se toma durante el build y queda congelado en el artefacto.

En la práctica, cambiar una URL de API o una clave no exige reconstruir: se modifica el .env en el servidor y se recarga PM2 (pm2 reload nuxt-app). La misma carpeta .output puede así servir preproducción y producción con dos archivos de entorno distintos. La única condición es que el proceso cargue ese archivo, ya que Nuxt deja de leer .env una vez construida la aplicación: de ahí la opción --env-file que se pasa a Node al arrancar con PM2.

Optimizar el renderizado con routeRules

Una de las fortalezas de Nuxt en un VPS es la granularidad de las estrategias de renderizado página a página, sin cambiar de infraestructura. En nuxt.config.ts, las routeRules permiten mezclar SSR, SSG, ISR y SWR en un único despliegue Nitro.

Las páginas estáticas (blog, avisos legales, landing pages) pueden pregenerarse en el build con prerender: true: Nitro las sirve desde disco, sin Node. Las páginas semi-dinámicas (listas de productos, dashboards públicos) se benefician de swr: 60 para una caché de un minuto invalidada en segundo plano. El SSR completo queda reservado para las páginas personalizadas que dependen de la sesión o del perfil del usuario.

Este enfoque reduce la carga sobre Node sin necesitar un CDN de pago o una capa de caché externa — su Nginx almacena lo que Nitro pregenera.

Nitro server vs Docker vs Vercel/Netlify para alojar Nuxt

Desplace la tabla

EnfoqueVentajasLimitaciones
Nitro `node-server` + PM2Simple, ligero, recarga sin downtime, costo fijo VPSSupervisión a gestionar, servidor único sin alta disponibilidad nativa
Docker en VPSAislamiento, reproducibilidad, rollback por imagen, compose multi-appImagen a construir y almacenar, memoria adicional por contenedor
Vercel / NetlifyConfiguración cero, CDN edge global, previews por PRCuotas de funciones, costo variable, sin control sobre la infraestructura
Kamal (despliegue zero-downtime)Orquesta Docker y kamal-proxy, despliegue con un solo comando (`kamal deploy`)Herramienta Ruby (gem o imagen Docker), configuración inicial más larga, pensado para equipos

Registros: leerlos, rotarlos y cruzarlos con Nginx

PM2 centraliza la salida de la aplicación: pm2 logs nuxt-app sigue el flujo en directo (salida estándar y errores) y pm2 logs nuxt-app --lines 100 muestra las últimas líneas. Los archivos se escriben en ~/.pm2/logs/, un -out.log y un -error.log por aplicación, con el número de instancia como sufijo en modo cluster.

Estos archivos no rotan por sí solos. El módulo pm2-logrotate los rota al superar los 10 MB y conserva 30 por defecto; ajuste estos umbrales al tamaño de su disco:

pm2 install pm2-logrotate
pm2 set pm2-logrotate:max_size 50M
pm2 set pm2-logrotate:retain 7

Cuando el navegador recibe un 502 o un 504, mire primero del lado de Nginx: /var/log/nginx/error.log indica si no pudo alcanzar 127.0.0.1:3000 (proceso detenido, puerto erróneo) o si Nitro tardó demasiado en responder.

Resolución de problemas: errores comunes en producción

Error: listen EADDRINUSE: address already in use :::3000
Un proceso ya ocupa el puerto 3000. Identifíquelo con ss -tlnp | grep 3000 y detenga la instancia PM2 huérfana: pm2 delete nuxt-app seguido de un reinicio limpio. Evite lanzar múltiples instancias sin un load balancer — configure el cluster_mode de PM2.

502 Bad Gateway en Nginx
Nitro no está arrancado o escucha en el puerto incorrecto. Compruebe pm2 status y revise los logs: pm2 logs nuxt-app --lines 50. Verifique también que la directiva proxy_pass en Nginx apunta a http://127.0.0.1:3000 (no a localhost que puede resolver a IPv6 si el proceso solo escucha en IPv4).

useRuntimeConfig() devuelve undefined
Las variables NUXT_* solo se leen cuando arranca el proceso Nitro: tras modificar .env, recargue con pm2 reload nuxt-app. Compruebe que el archivo se carga realmente mediante --node-args="--env-file=…" y no exportado en el shell actual, que desaparece con la sesión SSH. Si el valor falta solo en el navegador, la clave debe declararse bajo runtimeConfig.public y la variable llevar el prefijo NUXT_PUBLIC_.

Las rutas server/api devuelven 404 en producción
Compruebe que su build incluye la carpeta server/ en .output. Un nitro.preset mal configurado (por ejemplo static en vez de node-server) genera un sitio estático sin servidor. Reconstruya con npm run build tras verificar nuxt.config.ts.

X-Forwarded-Proto ignorado, bucle de redirección
Si Nuxt redirige HTTP → HTTPS en bucle, significa que el middleware de redirección ve http pese al HTTPS del cliente. Asegúrese de que Nginx transmite proxy_set_header X-Forwarded-Proto $scheme y que su nuxt.config.ts no fuerza la redirección HTTPS dos veces junto a Certbot.

Supervisión y métricas con PM2

Más allá del simple pm2 status, PM2 expone un panel en tiempo real con pm2 monit: CPU, memoria, reinicios y logs de procesos. Para una aplicación Nuxt bajo carga, active el modo cluster para usar todos los vCPU disponibles:

pm2 start .output/server/index.mjs --name nuxt-app -i max

PM2 distribuye automáticamente las peticiones entre los workers. Exporte estas métricas a Prometheus y Grafana para recibir alertas sobre reinicios inesperados — señal de un bug o fuga de memoria a corregir antes de que afecte a los usuarios.

La documentación oficial

Para la configuración avanzada y los cambios de versión, consulte la documentación oficial de Nuxt (routeRules, runtimeConfig, módulos), la página de Node.js de Nitro para las variables NITRO_PORT y NITRO_HOST, y la documentación del modo cluster de PM2. Esta guía cubre la puesta en línea en un VPS; la documentación del editor sigue siendo la referencia para los ajustes finos.

Despliegue su Nuxt con total autonomía

El VPS Cloud de ServOrbit incluye una plantilla con Node.js, PM2, Nginx y SSL automático, ideal para alojar sus aplicaciones Nuxt 3 con SSR y rutas de servidor.