Back to blog

Wednesday, April 9, 2025

Complete Guide: Deploy Next.js to VPS with Nginx, PM2 & GitHub Auto-Deploy

cover

Complete Guide to Deploying Next.js on VPS

Deploying a Next.js application to a VPS is a common task for developers looking to run their app in a production environment. In this guide, we will walk through setting up the server, deploying your application, setting up a reverse proxy with Nginx, managing your application with PM2, and automating deployments with GitHub Actions. We’ll be using Ubuntu 22.04 LTS for the server setup and GitHub Actions for automating the deployment pipeline.

Before You Start:

This guide assumes you have basic knowledge of Linux commands and GitHub workflows. We will use Ubuntu 22.04 for demonstration, but the steps can be adapted for other distributions as well.

Prerequisites

Before we begin, make sure you have the following prerequisites:

1

1. VPS Requirements

  • Ubuntu 22.04 server (or any other Ubuntu-based VPS) - Root SSH access to the server - Domain name pointed to the server IP for production use
2

2. Development Setup

  • A Next.js project stored in a GitHub repository - A working production build of the project locally - An SSH key pair for GitHub access (so the server can securely fetch updates from GitHub)

Server Setup

Step 1: Initial Server Configuration

To begin, you need to connect to your VPS and set it up. We’ll start by logging in to the server, updating packages, and installing the required software.

# Connect to your server
ssh root@your_server_ip

# Update the system's package list and upgrade existing packages
apt update && apt upgrade -y

# Install necessary tools: Git for version control, Nginx for reverse proxy, Node.js and npm for running Next.js
apt install -y git nginx nodejs npm

# Set up the firewall to allow HTTP traffic (for Nginx) and SSH connections
ufw allow 'Nginx Full'
ufw allow ssh
ufw enable

Security Tip:

Important: Always use SSH keys for authentication and create a non-root user for deployment. This improves security and helps avoid any accidental system changes as the root user.

Step 2: Configure a Non-Root User

It’s a good practice to create a non-root user for application deployment. Running commands as root can be dangerous, as it allows accidental system-wide changes. You can create a user and grant them sudo privileges:

# Add a new user
adduser deploy

# Give the user sudo privileges
usermod -aG sudo deploy

# Switch to the new user
su - deploy

Application Deployment

Now that the server is prepared, let's focus on deploying the Next.js application.

Step 3: Clone the Repository and Install Dependencies

We’ll begin by cloning your Next.js project from GitHub and installing the necessary dependencies.

1

Clone Repository

# Clone your Next.js project repository from GitHub
git clone https://github.com/yourusername/your-nextjs-app.git
cd your-nextjs-app
2

Install Packages

# Install required Node.js packages and build the production version of the app
npm install
npm run build

Step 4: Configure PM2 to Manage the Application

Next.js runs as a Node.js process, so we will use PM2 (Process Manager 2) to keep the application running in the background. PM2 ensures that the app is restarted automatically if it crashes or when the server reboots.

# Install PM2 globally
npm install -g pm2

# Start the application in production mode using PM2
pm2 start npm --name "next-app" -- start

# Save the PM2 process list to ensure it persists across reboots
pm2 save

# Enable PM2 to start on system boot
pm2 startup systemd

Nginx Reverse Proxy Configuration

Nginx will act as a reverse proxy to forward incoming HTTP requests to the Next.js app, which will be running on a local port (3000). This setup ensures that Nginx handles incoming traffic and provides better performance, security, and scalability.

Step 5: Create Nginx Configuration File

We need to create a new Nginx configuration file for our application. This file will specify that Nginx should forward requests to the Next.js app running on port 3000.

server {
listen 80;
server_name yourdomain.com; # Replace with your domain

    location / {
        # Forward requests to the local Next.js app
        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;
    }

}

Step 6: Enable the Nginx Configuration

Now, let’s enable the new configuration and restart Nginx to apply the changes.


# Create a symbolic link to enable the site
ln -s /etc/nginx/sites-available/next-app.conf /etc/nginx/sites-enabled/

# Test Nginx configuration for errors
nginx -t

# Restart Nginx to apply changes
systemctl restart nginx

SSL Bonus:

Bonus: You can secure your site with HTTPS by using Let's Encrypt. Install the required packages and run the following command to automatically configure SSL certificates: bash apt install certbot python3-certbot-nginx certbot --nginx -d yourdomain.com

Automating Deployment with GitHub Actions

GitHub Actions allow us to automate deployments. Every time you push updates to your repository, GitHub will trigger a workflow to automatically deploy the changes to your VPS.

Step 7: Set Up GitHub Actions Workflow

Create a file .github/workflows/deploy.yml in your repository. This workflow file will define the steps to deploy your Next.js app to the VPS using SSH.

name: Auto Deploy

on:
  push:
    branches:
      - main # Trigger deployment when changes are pushed to the 'main' branch

jobs:
  deploy:
    runs-on: ubuntu-latest # Use the latest Ubuntu for the runner
    steps:
      - name: SSH Deploy
        uses: appleboy/ssh-action@v1
        with:
          host: ${{ secrets.SSH_HOST }} # The server IP
          username: ${{ secrets.SSH_USER }} # The deployment user
          key: ${{ secrets.SSH_PRIVATE_KEY }} # SSH private key stored in GitHub secrets
          script: |
            # Navigate to the app directory
            cd /var/www/your-nextjs-app

            # Pull the latest changes from the repository
            git pull origin main

            # Install any new dependencies
            npm install

            # Build the app for production
            npm run build

            # Restart the app with PM2
            pm2 restart next-app

Step 8: Configure GitHub Secrets

For security, store your server credentials (SSH keys, username, and host) as secrets in your GitHub repository. This prevents sensitive information from being exposed in your workflow.

  1. Go to your repository on GitHub.
  2. Navigate to Settings > Secrets > New Repository Secret.
  3. Add the following secrets:
    • SSH_HOST: Your server IP address
    • SSH_USER: The user with deployment permissions (e.g., deploy)
    • SSH_PRIVATE_KEY: Your SSH private key used for authentication

Add these secrets in GitHub repo settings: - SSH_HOST: Server IP - SSH_USER: Deployment user - SSH_PRIVATE_KEY: SSH private key

Now, whenever you push to the main branch, the GitHub Action will deploy the latest code to your server automatically!

🎉Conclusion

n this guide, we’ve walked through the process of setting up a production-grade environment for your Next.js application on a VPS. By leveraging Nginx as a reverse proxy, PM2 for process management, and automating deployments with GitHub Actions, we’ve built a robust, scalable, and easy-to-maintain infrastructure. 💻⚙️

Deploying applications to a VPS is an essential skill for developers looking to take control of their own infrastructure. With these steps, you can ensure your app runs smoothly with minimal downtime and optimized performance. 🌐💪

Happy coding and deploying! 🚀💙