#nextjs#deployment

Next.js Deployment 101: Easy VPS Setup with Nginx & PM2

Learn the basics of deploying a Next.js app on a VPS using Nginx and PM2, from start to finish.

15 min read
0 views

Introduction

Deploying a Next.js app to a VPS can feel tricky if it’s your first time. In this post, we’ll go through the basic steps from setting up your VPS to getting your app live using Nginx and PM2.

By the end of this guide, you will:

  • Have a Next.js app running on your domain
  • Understand the basics of how Nginx works as a reverse proxy
  • Keep your app running smoothly with PM2

This is a beginner-friendly guide, so no advanced server skills needed.

Setup Checklist

Before we start, make sure you have:

  1. A VPS (Ubuntu or Another Linux)
  2. A domain name
  3. Node.js installed or ready to install
  4. Basic terminal/SSH access
  5. Your Next.js project ready to deploy

That’s it. Once you have these, we’re good to go.

Step 1: Connect to Your VPS

First, log in to your VPS using SSH.
Open your terminal and run:

bash
ssh your-username@your-vps-ip

Step 2: Install Node.js and PM2

Once you’re in your VPS, install Node.js (LTS version) and PM2. PM2 is a process manager for Node.js apps. It keeps your app running 24/7, restarts it if it crashes, and can even start it automatically after a server reboot.

Run these commands:

bash
# Update packages sudo apt update && sudo apt upgrade -y # Install Node.js LTS curl -fsSL https://deb.nodesource.com/setup_lts.x | sudo -E bash - sudo apt install -y nodejs # Install PM2 globally sudo npm install -g pm2

To check if everything worked:

bash
node -v npm -v pm2 -v

If you see version numbers, you’re good to go. For example:

bash
v20.11.1 10.5.0 5.3.0

Step 3: Upload Your Next.js App to the VPS

Now we need to get your Next.js project onto the VPS.
The easiest way is to use Git (make sure your code is already pushed to GitHub, GitLab, or similar).

On your VPS, run:

bash
# Install Git if you don't have it sudo apt install -y git # Clone your repository git clone https://github.com/your-username/your-repo.git # Go into the project folder cd your-repo

Step 4: Build and Start the App with PM2

Once your project is on the VPS, install dependencies and build the app:

bash
# Install dependencies npm install # Build the Next.js app npm run build

Now start the app with PM2. Here’s a general template:

bash
pm2 start "npm run start -- -p YOUR_PORT" \ --name "[YOUR_APP_NAME]" \ --cwd /path/to/your/project

Or if you already at the path of your folder project use this:

bash
# Default port from your project (usually 3000) pm2 start "npm run start" --name "[your_app_name]" # Custom port pm2 start "npm run start -- -p [your_custom_port]" --name "[your_app_name]"

Now check if it’s already running:

bash
pm2 list

Example if it's already running

psql
┌─────┬─────────────────────┬──────┬──────┬─────────┬───────────┬────────┐ │ id │ name │ mode │ pid │ status │ restart │ cpu │ ├─────┼─────────────────────┼──────┼──────┼─────────┼───────────┼────────┤ │ 0 │ your_app_name │ fork │ 1234 │ online │ 0 │ 0% │ └─────┴─────────────────────┴──────┴──────┴─────────┴───────────┴────────┘

If the status says online, it means PM2 has started the process. However, “online” doesn’t always mean your app is working correctly. So, you should also check the logs.

bash
pm2 logs [your_app_name]

Example output if it's already works:

bash
0|[your_app_name] | ready - - Local: http://localhost:[your_port] 0|[your_app_name] | ready - ... 0|[your_app_name] | ready - ... 0|[your_app_name] | info ✓ Starting... 0|[your_app_name] | info ✓ Ready in 1163ms

If you see Ready and no errors in the logs, your Next.js app is running successfully.

Step 5: Install and Configure Nginx

We’ll use Nginx as a reverse proxy.
Simply put, Nginx will take requests from your domain (port 80 or 443) and forward them to your Next.js app running on another port (like 3000 or 3002).
This way, visitors don’t have to type the port in the URL.

First, install Nginx:

bash
sudo apt install -y nginx

Check if Nginx is running:

bash
sudo systemctl status nginx

If it’s active (green), we’re good.

Next, create a config file for your app:

bash
sudo nano /etc/nginx/sites-available/[your_app_name].conf

Example config:

conf
server { listen 80; server_name [yourdomain] www.[yourdomain]; # for example: # server_name instagram.com www.instagram.com; location / { proxy_pass http://localhost:[your_app_port]; # for example: # 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; } }

Enable the config and restart Nginx:

bash
sudo ln -s /etc/nginx/sites-available/[your_app_name].conf /etc/nginx/sites-enabled/[your_app_name].conf

Make sure the file name in sites-available and sites-enabled is exactly the same.

Check syntax:

bash
sudo nginx -t

If nginx -t shows syntax is ok and test is successful, it means the configuration is valid and ready to use.

bash
sudo systemctl restart nginx

Now, if your domain is already pointed to your VPS IP in your DNS settings,
you can just type https://yourdomain.com in the browser and it will load your Next.js app.

Step 6: Keep the App Running After Logout or Reboot

PM2 can keep your app alive even after you close SSH or the server reboots.

  1. Save the current process list
bash
pm2 save

This tells PM2 to “Remember what I’m running right now.”

PM2 will print a command. Copy and run it. Example:

  1. Enable auto start on reboot
bash
pm2 startup

PM2 will show a command, so just copy and run it.

Example:

bash
sudo env PATH=$PATH:/usr/bin pm2 startup systemd -u your_user --hp /home/your_user
  1. Enable auto start on reboot
bash
pm2 save

Now, even if your VPS restarts, PM2 will automatically start your app again.

Step 7: Enable HTTPS with Certbot

Right now your app is running on HTTP (not secure).
Let’s make it secure with HTTPS using a free SSL certificate from Let’s Encrypt.

  1. Install Certbot and the Nginx plugin
bash
sudo apt install -y certbot python3-certbot-nginx
  1. Request and install the SSL certificate

Replace yourdomain.com with your actual domain:

bash
sudo certbot --nginx -d yourdomain.com -d www.yourdomain.com
  1. Follow the prompts
  • Certbot will ask for your email (for renewal notices)
  • Agree to the terms
  • Choose whether to redirect HTTP to HTTPS (recommended: Yes)
  1. Check HTTPS

Open https://yourdomain.com in your browser. If the padlock icon appears, you’re good to go.

  1. Auto-renew

Let’s Encrypt SSL certificates only last 90 days.
If you don’t renew them, your site will lose HTTPS and show a “Not Secure” warning.

To make it renew automatically before it expires, enable Certbot’s auto-renew service:

bash
sudo systemctl enable certbot.timer sudo systemctl start certbot.timer

Now your Next.js app is secure and will automatically keep its SSL certificate up to date.