This guide explains how to set up automatic deployment for your Next.js application using GitHub Actions and PM2 without Docker [cite: 1].
Step 1: Create the GitHub Actions Workflow
-
In your project repository, create a workflow file at [cite: 1]:
text.github/workflows/deploy.yml -
Add the following YAML configuration [cite: 1]:
yamlname: Deploy Next.js on: push: branches: - main jobs: deploy: runs-on: ubuntu-latest steps: - name: Deploy to VPS uses: appleboy/ssh-action@v1.2.0 with: host: ${{ secrets.VPS_HOST }} username: ${{ secrets.VPS_USERNAME }} key: ${{ secrets.VPS_SSH_KEY }} port: ${{ secrets.VPS_PORT }} script: | set -e echo "===== DEPLOYMENT STARTED =====" # Verify system environment echo "User:" whoami echo "Home:" echo $HOME echo "Node Version:" /root/.nvm/versions/node/v24.18.0/bin/node -v echo "PNPM Version:" /root/.nvm/versions/node/v24.18.0/bin/pnpm -v echo "PM2 Version:" /root/.nvm/versions/node/v24.18.0/bin/pm2 -v # Navigate to project directory echo "Going to project directory..." cd /var/www/ahmadalatrash-business-acquisition-marketplace-frontend # Fetch and reset repository to latest main code echo "Pulling latest code..." git fetch origin git reset --hard origin/main # Install dependencies and build project echo "Installing dependencies..." /root/.nvm/versions/node/v24.18.0/bin/pnpm install --frozen-lockfile echo "Building Next.js..." /root/.nvm/versions/node/v24.18.0/bin/pnpm build # Restart process with PM2 echo "Restarting PM2..." /root/.nvm/versions/node/v24.18.0/bin/pm2 restart ahmadalatrash-business-acquisition-marketplace-frontend echo "===== DEPLOYMENT COMPLETE ====="
Step 2: Set Up SSH Access on Your VPS
Run these commands inside your VPS terminal to grant GitHub Actions permission to access your server via SSH:
A. Generate an SSH Key Pair
Log into your VPS via SSH and run [cite: 2]:
bashssh-keygen -t ed25519 -C "github-actions"
Example output in terminal:
textGenerating public/private ed25519 key pair. Enter file in which to save the key (/root/.ssh/id_ed25519): Enter passphrase (empty for no passphrase): Enter same passphrase again:
👉 What to do: Press Enter 3 times on your keyboard to accept default settings with no passphrase [cite: 2, 6].
B. Authorize the Public Key
Run these commands to add your new public key to the server's authorized list and set correct permissions [cite: 2, 6]:
bashcat ~/.ssh/id_ed25519.pub >> ~/.ssh/authorized_keys chmod 600 ~/.ssh/authorized_keys chmod 700 ~/.ssh
C. Retrieve the Private Key
Display the private key content on your terminal screen [cite: 2, 6]:
bashcat ~/.ssh/id_ed25519
Example output in terminal:
text-----BEGIN OPENSSH PRIVATE KEY----- b3BlbnNzaC1rZXktdjEAAAABGbaa3R5cGUAAAAEb25pb24AAAAAAA EAAACBAGS89xLKj239fKsdm843mK23kdfLSDf324sdfSDFSDf234s ... (multiple key lines) ... -----END OPENSSH PRIVATE KEY-----
👉 What to do: Copy everything from -----BEGIN OPENSSH PRIVATE KEY----- to -----END OPENSSH PRIVATE KEY----- [cite: 2, 6].
D. Verify SSH Details
- Username: Check active user by running
whoami(typicallyrootor a deployment user) [cite: 2]. - Port: Default SSH port is
22[cite: 2].
Step 3: Add Secrets to GitHub
- Open your repository on GitHub [cite: 2, 6].
- Go to Settings > Secrets and variables > Actions [cite: 2, 6].
- Click New repository secret and add the following 4 secrets [cite: 2, 6]:
| Secret Name | Description / Value | Example |
|---|---|---|
VPS_HOST | Public IP address of your VPS [cite: 2] | 159.65.123.45 [cite: 2] |
VPS_USERNAME | Your SSH login username [cite: 2] | root [cite: 2] |
VPS_SSH_KEY | Complete Private Key copied from Step 2C [cite: 2] | -----BEGIN OPENSSH PRIVATE KEY-----... [cite: 2] |
VPS_PORT | SSH connection port [cite: 2] | 22 [cite: 2] |
Step 4: Verify and Test Deployment
- Commit and push your workflow file to the
mainbranch [cite: 6]. - Navigate to the Actions tab in your GitHub repository [cite: 6].
- Click on the active workflow run to observe the real-time build and deployment logs [cite: 6].
- Once completed, your Next.js application will be automatically updated and running live on PM2 [cite: 1, 6]!