Deploying Node.js Applications (Nuxt + NestJS) on Ubuntu 24.04
We used AI while writing this content.
Supported Platforms
| Ubuntu 24.04 LTS | ✅ |
| Ubuntu 22.04 LTS | ✅ |
| Debian 12+ | ✅ |
| Other Linux distributions | ✅ (with adjustments) |
Setup
1. Install Node.js and npm
Update your system and install Node.js:
sudo apt update
sudo apt install -y curl
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
sudo apt install -y nodejs
Verify installation:
node --version
npm --version
Tip: Node.js 20.x is the current LTS (Long Term Support) version. Adjust the version number as needed.
2. Install PM2 process manager
PM2 keeps your application running in the background and restarts it automatically on crashes or server reboots:
sudo npm install -g pm2
3. Create dedicated user
Running node-js from a user without root permission is much safer, since even if somehow the process is hijacked, the attacker gains only user-level permission. Therefore, we should create a dedicated user :
sudo useradd <app_user>
sudo passwd <app_user>
4. Clone and Build your application
Navigate to your deployment directory and clone your repository, then install dependencies:
sudo mkdir -p /var/www
cd /var/www
sudo mkdir -p <app-name>
cd <app-name>
sudo git clone https://github.com/yourusername/your-repo.git .
cd <app-git-name> #git clone creates a subfolder
For NestJS (Backend)
sudo npm install
npm run build
For Nuxt (Frontend)
cd frontend
sudo npm install
npm run build
This creates a .output directory with your production-ready application.
This compiles TypeScript to JavaScript in the dist directory.
5. Configure environment variables
Create a .env file in your project root:
cd .. # make sure you are at project root folder
nano .env
Add your production configuration:
NODE_ENV=production
PORT=3000
DATABASE_URL=postgresql://user:password@localhost:5432/dbname
API_SECRET=your-secret-key
Do the same for frontend/ :
nano frontend/.env
# Backend API base URL
NUXT_PUBLIC_API_BASE=http://localhost:3010
MAPTILER_API_KEY="get_your_free_key_at_https://maptiler.com"
Security note: Never commit
.envfiles to version control. Keep sensitive credentials secure.
If you are using Prisma as database :
# Generate Prisma Client
npx prisma generate
# Run migrations
npx prisma migrate deploy
6. Start application with PM2
Switch to the dedicated app user :
sudo chown -R <app_user>:<app_user_group> <full-app-folder-path> # grant adequate permission to the app user
su <app_user>
Create an ecosystem.config.js:
module.exports = {
apps: [
{
name: 'nuxt-frontend',
script: '.output/server/index.mjs',
env: {
NODE_ENV: 'production',
PORT: 3000
}
},
{
name: 'nestjs-backend',
script: 'dist/main.js',
env: {
NODE_ENV: 'production',
PORT: 3001
}
}
]
};
pm2 start ecosystem.config.js
7. Configure PM2 to start on system boot
Switch back to a user with sudo permission
su <sudo-user>
pm2 startup systemd
pm2 save
Follow the command output instructions (you may need to run a generated command with sudo).
8. Set up Nginx as reverse proxy
Install Nginx:
sudo apt install -y nginx
Create a new Nginx configuration:
sudo nano /etc/nginx/sites-available/myapp
Add the following configuration:
server {
listen 80;
server_name yourdomain.com www.yourdomain.com;
# Frontend (Nuxt)
location / {
proxy_pass http://localhost:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
# Backend API (NestJS)
location /api {
proxy_pass http://localhost:3001;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
}
Enable the site and restart Nginx:
sudo ln -s /etc/nginx/sites-available/myapp /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl restart nginx
9. Configure firewall
sudo ufw allow 'Nginx Full'
sudo ufw allow OpenSSH
sudo ufw enable
Test connection from another machine:
curl http://<server-ip-address>
You should see the nginx welcome page. You do not see your actual site content since nginx is built for multi-site hosting and you must specify the web domain name in your request header to resolve to the actual site.
See guide on uncomplicated firewall if the site is not accessible from the public internet
If the server is now publically available via HTTP, add the following DNS records in your domain name configuration through your DNS provider :
; A records (replace <SERVER_IPV4> with your server IP)
@ IN A <SERVER_IPV4>
www IN A <SERVER_IPV4>
; Optional IPv6
@ IN AAAA <SERVER_IPV6>
www IN AAAA <SERVER_IPV6>
; Allow Let's Encrypt to issue certificates
@ IN CAA 0 issue "letsencrypt.org"
10. Set up SSL with Let's Encrypt (optional but recommended)
Install Certbot:
sudo apt install -y certbot python3-certbot-nginx
Obtain and install SSL certificate:
sudo certbot --nginx -d yourdomain.com -d www.yourdomain.com
Follow the prompts. Certbot will automatically configure Nginx for HTTPS.
Useful PM2 commands
Monitor applications:
pm2 status
pm2 logs
pm2 monit
Restart applications:
pm2 restart all
pm2 restart nuxt-app
Stop applications:
pm2 stop all
pm2 delete all
Updating your application
cd /var/www/myapp
git pull origin main
npm install
npm run build
pm2 restart all
Useful Links
- Node.js Official Documentation
- PM2 Documentation
- Nuxt Deployment Guide
- NestJS Deployment Guide
- Nginx Documentation
- Let's Encrypt Documentation
Copyleft Statement
Renoncé du droit d'auteur
Much of our content is freely available under the Creative Commons BY-NC-ND 4.0 licence, which allows free distribution and republishing of our content for non-commercial purposes, as long as Ronzz.org is appropriately credited and the content is not being modified materially to express a different meaning than it is originally intended for. It must be noted that some images on Ronzz.org are the intellectual property of third parties. Our permission to use those images may not cover your reproduction. This does not affect your statutory rights.
Nous mettons la plupart de nos contenus disponibles gratuitement sous la licence Creative Commons By-NC-ND 4.0, qui permet une distribution et une republication gratuites de notre contenu à des fins non commerciales, tant que Ronzz.org est correctement crédité et que le contenu n'est pas modifié matériellement pour exprimer un sens différent que prévu à l'origine.Il faut noter que certaines images sur Ronzz.org sont des propriétés intellectuelles de tiers. Notre autorisation d'utiliser ces images peut ne pas couvrir votre reproduction. Cela n'affecte pas vos droits statutaires.
Member discussion