TL;DR
Complete guide to deploying a production Nuxt 3 application on Ubuntu 24.04 with Node.js, PM2, nginx, and SSL.
Key facts
- Topology
- Nuxt 3 on Ubuntu 24.04
TL;DR
This guide walks through deploying Nuxt 3 on a fresh Ubuntu 24.04 server — from system preparation through Node.js installation, build process, PM2 configuration, nginx reverse proxy, and SSL termination.
Prerequisites
- Ubuntu 24.04 LTS with root or sudo access
- A domain name with DNS pointing to your server's IP
- Your Nuxt 3 project in a Git repository
Step 1 — System preparation
Update the system and install essentials:
sudo apt update && sudo apt upgrade -y
sudo apt install -y curl git build-essential
Create a deploy user:
sudo adduser deploy
sudo usermod -aG sudo deploy
su - deploy
Step 2 — Install Node.js 20 LTS
Install via NodeSource:
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
sudo apt install -y nodejs
node -v && npm -v
Step 3 — Clone and build
sudo mkdir -p /var/www/nuxt-app
sudo chown deploy:deploy /var/www/nuxt-app
cd /var/www/nuxt-app
git clone git@github.com:yourorg/nuxt-app.git .
npm ci
Create your production environment file:
cp .env.example .env
# Edit with production values: NUXT_PUBLIC_API_BASE, etc.
Build the application:
npx nuxt build
This produces the .output directory with the self-contained Nitro server.
Step 4 — PM2 process management
sudo npm install -g pm2
Create ecosystem.config.cjs:
module.exports = {
apps: [{
name: 'nuxt-app',
script: '.output/server/index.mjs',
cwd: '/var/www/nuxt-app',
instances: 'max',
exec_mode: 'cluster',
max_memory_restart: '512M',
exp_backoff_restart_delay: 100,
env: {
NODE_ENV: 'production',
NUXT_HOST: '127.0.0.1',
NUXT_PORT: 3000,
},
}],
}
Start and persist:
pm2 start ecosystem.config.cjs
pm2 startup systemd
pm2 save
Verify:
pm2 status
curl -I http://127.0.0.1:3000/
Step 5 — nginx reverse proxy
sudo apt install -y nginx
Create /etc/nginx/sites-available/nuxt-app:
server {
listen 80;
server_name example.com;
gzip on;
gzip_types text/plain text/css application/json application/javascript text/xml;
gzip_min_length 1000;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
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_read_timeout 60s;
proxy_connect_timeout 10s;
}
location /_nuxt/ {
alias /var/www/nuxt-app/.output/public/_nuxt/;
expires 365d;
add_header Cache-Control "public, immutable";
access_log off;
}
}
Enable and test:
sudo ln -s /etc/nginx/sites-available/nuxt-app /etc/nginx/sites-enabled/
sudo rm -f /etc/nginx/sites-enabled/default
sudo nginx -t && sudo systemctl reload nginx
Step 6 — SSL with Certbot
sudo apt install -y certbot python3-certbot-nginx
sudo certbot --nginx -d example.com
Certbot configures auto-renewal automatically. Verify:
sudo systemctl status certbot.timer
Step 7 — Firewall
sudo ufw allow 'Nginx Full'
sudo ufw allow OpenSSH
sudo ufw enable
sudo ufw status
Step 8 — Log management
Install PM2 log rotation to prevent disk fill:
pm2 install pm2-logrotate
pm2 set pm2-logrotate:max_size 50M
pm2 set pm2-logrotate:retain 7
pm2 set pm2-logrotate:compress true
Deployment script
For subsequent deploys:
#!/bin/bash
set -euo pipefail
cd /var/www/nuxt-app
git pull origin main
npm ci
npx nuxt build
pm2 reload ecosystem.config.cjs
sleep 3
curl -sf http://127.0.0.1:3000/ > /dev/null && echo "Deploy OK" || echo "Deploy FAILED"
With Reflex
Install reflexd on your Ubuntu server to gain continuous monitoring, automated deploys, and incident recovery for your Nuxt 3 application. Reflex manages PM2 process health, nginx configuration, SSL renewal, disk/memory thresholds, and zero-downtime deployments — replacing manual SSH maintenance with audited, repeatable playbooks. See How it works.