--- title: "Cómo desplegar Next.js en Ubuntu 24.04 con systemd y Nginx" description: "Despliega Next.js en Ubuntu 24.04 con Node.js 24, ejecútalo como servicio de systemd y sírvelo tras Nginx con caché de estáticos y HTTPS de Let's Encrypt." category: "E-commerce y CMS" language: es source: https://cubepath.com/es/docs/e-commerce-y-cms/implementacion-y-optimizacion-de-aplicacion-nextjs updated: 2026-09-25 --- # Cómo desplegar Next.js en Ubuntu 24.04 con systemd y Nginx Next.js genera páginas en el servidor, así que en producción necesita un proceso de Node.js en marcha además de los archivos estáticos. En este tutorial desplegarás una aplicación Next.js en Ubuntu 24.04: instalarás Node.js 24 desde el repositorio oficial de NodeSource, compilarás la aplicación, la ejecutarás con `next start` como servicio de systemd y pondrás Nginx delante para servir los estáticos con caché larga y gestionar HTTPS. ## Requisitos previos Para seguir esta guía necesitas: - Un servidor con Ubuntu 24.04 LTS, por ejemplo un VPS de CubePath, con al menos 2 GB de RAM. La compilación con `next build` es la parte que más memoria consume. - Un usuario no root con privilegios `sudo`. En los ejemplos se llama `your_user` y es también el usuario que ejecutará la aplicación. - Un dominio con un registro DNS `A` apuntando a la IP del servidor. En los ejemplos se usa `your_domain`. - Una aplicación Next.js en un repositorio Git, o las ganas de probar con un proyecto nuevo. La aplicación de ejemplo se llama `myapp` y vive en `/var/www/myapp`. ## Paso 1: Instalar Node.js 24 La versión de Node.js de los repositorios de Ubuntu 24.04 es demasiado antigua para las versiones actuales de Next.js. Instala Node.js 24 LTS desde el repositorio de NodeSource. Primero, descarga su clave de firma: ```bash sudo apt update sudo apt install ca-certificates curl gnupg sudo install -m 0755 -d /etc/apt/keyrings curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | sudo gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg ``` Añade el repositorio e instala Node.js, que incluye `npm`: ```bash echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_24.x nodistro main" | sudo tee /etc/apt/sources.list.d/nodesource.list sudo apt update sudo apt install nodejs ``` Comprueba las versiones: ```bash node -v npm -v ``` ```output v24.x.x 11.x.x ``` Instala también Nginx y Git, y abre en el cortafuegos SSH, HTTP y HTTPS: ```bash sudo apt install nginx git sudo ufw allow OpenSSH sudo ufw allow 'Nginx Full' sudo ufw enable ``` ## Paso 2: Descargar y compilar la aplicación Crea el directorio de la aplicación con tu usuario como propietario: ```bash sudo mkdir -p /var/www/myapp sudo chown your_user:your_user /var/www/myapp ``` Si tienes la aplicación en un repositorio, clónala: ```bash git clone https://github.com/your_account/myapp.git /var/www/myapp ``` Si solo quieres probar el despliegue, crea un proyecto nuevo en ese directorio y acepta las opciones por defecto del asistente: ```bash npx create-next-app@latest /var/www/myapp ``` Si la aplicación usa variables de entorno en el servidor (claves de API, URL de la base de datos), guárdalas en `.env.production.local`, que Next.js carga en producción y que no se sube al repositorio: ```bash nano /var/www/myapp/.env.production.local ``` ```ini DATABASE_URL=postgres://user:your_strong_password@localhost:5432/myapp ``` > Importante: las variables con prefijo `NEXT_PUBLIC_` se incrustan en el JavaScript del navegador durante `next build`. Si cambias alguna, tienes que volver a compilar; y nunca guardes secretos en ellas. Instala las dependencias exactamente como están en `package-lock.json` y compila. `npm ci` instala también las dependencias de desarrollo, que hacen falta para compilar (TypeScript, por ejemplo): ```bash cd /var/www/myapp npm ci npm run build ``` ```output Next.js 16.x.x Creating an optimized production build ... Compiled successfully ... ``` La compilación genera el directorio `.next`, que contiene el servidor compilado y los estáticos en `.next/static`. ## Paso 3: Ejecutar Next.js con systemd Crea un servicio de systemd que ejecute `next start` y lo reinicie si falla. Las opciones `-H 127.0.0.1 -p 3000` hacen que solo escuche en local, de modo que únicamente Nginx puede llegar a él: ```bash sudo nano /etc/systemd/system/myapp.service ``` ```ini [Unit] Description=myapp Next.js server After=network.target [Service] Type=simple User=your_user WorkingDirectory=/var/www/myapp Environment=NODE_ENV=production ExecStart=/usr/bin/npm run start -- -H 127.0.0.1 -p 3000 Restart=always RestartSec=5 [Install] WantedBy=multi-user.target ``` El script `start` del `package.json` de un proyecto Next.js es `next start`, y `--` le pasa el resto de argumentos. Activa e inicia el servicio: ```bash sudo systemctl daemon-reload sudo systemctl enable --now myapp systemctl status myapp --no-pager ``` ```output ● myapp.service - myapp Next.js server Active: active (running) since ... ``` Comprueba que responde: ```bash curl -I http://127.0.0.1:3000 ``` ```output HTTP/1.1 200 OK X-Powered-By: Next.js Content-Type: text/html; charset=utf-8 ... ``` Los logs de la aplicación, incluidos los `console.log` del servidor, están en `journalctl -u myapp`. ## Paso 4: Configurar Nginx con caché para los estáticos Los archivos de `/_next/static/` llevan un hash en el nombre, así que nunca cambian y el navegador puede guardarlos un año. Nginx los servirá directamente desde disco, sin pasar por Node.js, y enviará el resto de peticiones a la aplicación. Crea el bloque de servidor: ```bash sudo nano /etc/nginx/sites-available/myapp ``` ```nginx server { listen 80; listen [::]:80; server_name your_domain www.your_domain; location /_next/static/ { alias /var/www/myapp/.next/static/; add_header Cache-Control "public, max-age=31536000, immutable"; access_log off; } location / { proxy_pass http://127.0.0.1:3000; proxy_http_version 1.1; include proxy_params; } } ``` El archivo `proxy_params` de Ubuntu añade las cabeceras `Host`, `X-Real-IP`, `X-Forwarded-For` y `X-Forwarded-Proto`, que Next.js usa para construir URL absolutas y en los redirects. Activa el sitio, desactiva el sitio por defecto y comprueba la sintaxis: ```bash sudo ln -s /etc/nginx/sites-available/myapp /etc/nginx/sites-enabled/ sudo rm /etc/nginx/sites-enabled/default sudo nginx -t sudo systemctl reload nginx ``` Comprueba que los estáticos salen de Nginx con la cabecera de caché. Toma el nombre de un archivo JavaScript de la página principal: ```bash curl -s http://your_domain | grep -o '/_next/static/[^"]*\.js' | head -1 ``` ```output /_next/static/chunks/0a1b2c3d4e5f6a7b.js ``` Y pide ese archivo, sustituyendo la ruta por la que obtuviste: ```bash curl -I http://your_domain/_next/static/chunks/0a1b2c3d4e5f6a7b.js ``` ```output HTTP/1.1 200 OK Server: nginx/1.24.0 (Ubuntu) Content-Type: application/javascript Cache-Control: public, max-age=31536000, immutable ``` ## Paso 5: Activar HTTPS con Let's Encrypt Instala Certbot con su plugin para Nginx y solicita el certificado. Certbot añade la configuración TLS y la redirección de HTTP a HTTPS: ```bash sudo apt install certbot python3-certbot-nginx sudo certbot --nginx -d your_domain -d www.your_domain ``` Comprueba que la renovación automática funciona: ```bash sudo certbot renew --dry-run ``` Abre `https://your_domain` en el navegador y deberías ver tu aplicación servida por HTTPS. ## Paso 6: Ajustes de rendimiento Con esta configuración, Next.js ya aplica las optimizaciones principales: prerenderiza las páginas estáticas durante la compilación, comprime las respuestas con gzip y optimiza las imágenes de `next/image` con `sharp`. Hay dos ajustes que merece la pena revisar en un servidor propio. **Caché de imágenes y de ISR.** Las imágenes optimizadas y las páginas regeneradas con ISR se guardan en `.next/cache`. El servicio se ejecuta con tu usuario, propietario del directorio, así que puede escribir en él sin cambiar permisos. Comprueba que se llena tras visitar páginas con imágenes: ```bash du -sh /var/www/myapp/.next/cache ``` **Comprimir en Nginx en vez de en Node.js.** Si prefieres que la compresión la haga Nginx, desactívala en Next.js añadiendo `compress: false` a `next.config.js` (o `next.config.ts`): ```javascript const nextConfig = { compress: false, }; ``` Después activa `gzip` para los tipos de texto en `/etc/nginx/nginx.conf` (Ubuntu ya trae `gzip on;` en el bloque `http`, y `gzip_types` y las demás directivas comentadas), vuelve a compilar y reinicia el servicio. ## Actualizar la aplicación Para desplegar cambios, descarga el código, instala dependencias, compila y reinicia el servicio: ```bash cd /var/www/myapp git pull npm ci npm run build sudo systemctl restart myapp ``` Durante `npm run build` el directorio `.next` se reemplaza mientras el servidor sigue en marcha, y algunas peticiones pueden fallar durante unos segundos. Si necesitas despliegues sin cortes, compila en un directorio nuevo y cambia un enlace simbólico al terminar, o compila en un pipeline de CI. ## Solución de problemas - **`JavaScript heap out of memory` o el proceso muere al compilar**: el servidor no tiene memoria suficiente para `next build`. Añade swap o compila en una máquina con más RAM. - **502 Bad Gateway**: el servicio no está en marcha. Revisa `sudo journalctl -u myapp -n 50`; si ves `Could not find a production build`, ejecuta `npm run build` antes de arrancar. - **404 en archivos de `/_next/static/`**: la ruta de `alias` no coincide con el directorio real o falta la barra final en `alias` o en `location`. - **Una variable `NEXT_PUBLIC_` no cambia**: se incrusta en la compilación. Vuelve a ejecutar `npm run build` y reinicia el servicio. ## Conclusión Tu aplicación Next.js se ejecuta como servicio de systemd con Node.js 24, escucha solo en local y Nginx la publica por HTTPS sirviendo los estáticos con caché de un año. Como siguientes pasos puedes: - Usar `output: "standalone"` en `next.config.js` para generar un servidor mínimo que no necesite `node_modules` completo en producción. - Compilar en un pipeline de CI y copiar solo el resultado al servidor para evitar cortes durante el despliegue. - Poner una CDN delante de `/_next/static/` si tienes tráfico de varias regiones.