DEV Community

Muhammad Uzair
Muhammad Uzair

Posted on

VPS Deployment Guide (NEXT JS/REACT JS + GITHUB ACTIONS)

If you follow this exactly, your app will:

  • Deploy from GitHub with .env replaced each time
  • Serve over HTTPS automatically
  • Keep running after reboots
  • Renew SSL certs without downtime

0️⃣ Prerequisites

  • VPS with Ubuntu/Debian OR CentOS/AlmaLinux/Amazon Linux
  • Domain pointing to VPS IP (A record set in DNS)
  • GitHub repo with app code
  • SSH access to VPS
  • GitHub Actions enabled

1️⃣ Install Required Packages

Ubuntu/Debian

sudo apt update && sudo apt upgrade -y sudo apt install curl git nginx ufw -y curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash - sudo apt install -y nodejs sudo npm install -g pm2 
Enter fullscreen mode Exit fullscreen mode

CentOS / AlmaLinux / Amazon Linux

sudo yum update -y sudo yum install curl git nginx -y curl -fsSL https://rpm.nodesource.com/setup_22.x | sudo bash - sudo yum install -y nodejs sudo npm install -g pm2 
Enter fullscreen mode Exit fullscreen mode

2️⃣ Create a Repo-Level Deploy Key

ssh-keygen -t rsa -b 4096 -C "deploy-key" # Save as: /home/ubuntu/.ssh/deploy_key_example 
Enter fullscreen mode Exit fullscreen mode

Press Enter twice for no passphrase.


3️⃣ Add Public Key to GitHub Repo

cat ~/.ssh/deploy_key_example.pub 
Enter fullscreen mode Exit fullscreen mode
  • GitHub Repo → Settings → Deploy Keys → Add Deploy Key
  • Name: VPS Deploy Key
  • Paste the public key
  • ✅ Check “Allow write access” (optional)
  • Save

4️⃣ Configure SSH for GitHub

nano ~/.ssh/config 
Enter fullscreen mode Exit fullscreen mode

Paste:

Host github-example HostName github.com User git IdentityFile ~/.ssh/deploy_key_example IdentitiesOnly yes 
Enter fullscreen mode Exit fullscreen mode

5️⃣ Clone the Repo

sudo mkdir -p /var/www sudo chown $USER:$USER /var/www cd /var/www git clone git@github-example:username/repo-name.git example-app cd example-app 
Enter fullscreen mode Exit fullscreen mode

6️⃣ Install Dependencies

npm install 
Enter fullscreen mode Exit fullscreen mode

7️⃣ Build the App

Next.js

npm run build pm2 start npm --name "example-app" -- start 
Enter fullscreen mode Exit fullscreen mode

React

npm run build 
Enter fullscreen mode Exit fullscreen mode

8️⃣ Install SSL

Ubuntu/Debian

sudo apt install certbot python3-certbot-nginx -y sudo certbot certonly --nginx -d example.com 
Enter fullscreen mode Exit fullscreen mode

CentOS / AlmaLinux / Amazon Linux

sudo yum install certbot python3-certbot-nginx -y sudo certbot certonly --nginx -d example.com 
Enter fullscreen mode Exit fullscreen mode

9️⃣ Nginx Configuration (With SSL)

Ubuntu/Debian

sudo nano /etc/nginx/sites-available/example.com 
Enter fullscreen mode Exit fullscreen mode

CentOS / AlmaLinux / Amazon Linux

sudo nano /etc/nginx/conf.d/example.com.conf 
Enter fullscreen mode Exit fullscreen mode

Next.js (SSR)

server { listen 80; server_name example.com; return 301 https://$host$request_uri; } server { listen 443 ssl; server_name example.com; ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem; location / { proxy_pass http://localhost:<PORT_OF_YOUR_APP>; 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; } } 
Enter fullscreen mode Exit fullscreen mode

React (Static)

server { listen 80; server_name example.com; return 301 https://$host$request_uri; } server { listen 443 ssl; server_name example.com; ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem; root /var/www/example-app/build; index index.html index.htm; location / { try_files $uri /index.html; } } 
Enter fullscreen mode Exit fullscreen mode

🔟 Enable Config & Restart Nginx

Ubuntu/Debian

sudo ln -s /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled sudo nginx -t sudo systemctl restart nginx 
Enter fullscreen mode Exit fullscreen mode

CentOS / AlmaLinux / Amazon Linux

sudo nginx -t sudo systemctl restart nginx 
Enter fullscreen mode Exit fullscreen mode

1️⃣1️⃣ Enable PM2 Auto-Start (Next.js Only)

pm2 save pm2 startup 
Enter fullscreen mode Exit fullscreen mode

Follow the command PM2 outputs and run it.


1️⃣2️⃣ Enable Automatic SSL Renewal

sudo certbot renew --dry-run 
Enter fullscreen mode Exit fullscreen mode

Add a cron job:

sudo crontab -e 
Enter fullscreen mode Exit fullscreen mode

Paste:

0 3 * * * /usr/bin/certbot renew --quiet && /bin/systemctl reload nginx 
Enter fullscreen mode Exit fullscreen mode

1️⃣3️⃣ GitHub Actions Deployment Pipeline

Next.js

name: Deploy Next.js to VPS on: push: branches: [ main ] jobs: deploy: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - name: Deploy via SSH uses: appleboy/ssh-action@master with: host: ${{ secrets.VPS_HOST }} username: ${{ secrets.VPS_USER }} key: ${{ secrets.VPS_KEY }} script: | cd /var/www/example-app git pull origin main rm -f .env echo "${{ secrets.ENV_FILE }}" > .env npm install npm run build pm2 restart example-app 
Enter fullscreen mode Exit fullscreen mode

React

name: Deploy React to VPS on: push: branches: [ main ] jobs: deploy: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - name: Deploy via SSH uses: appleboy/ssh-action@master with: host: ${{ secrets.VPS_HOST }} username: ${{ secrets.VPS_USER }} key: ${{ secrets.VPS_KEY }} script: | cd /var/www/example-app git pull origin main rm -f .env echo "${{ secrets.ENV_FILE }}" > .env npm install npm run build sudo systemctl restart nginx 
Enter fullscreen mode Exit fullscreen mode

1️⃣4️⃣ Add GitHub Secrets

In GitHub Repo → Settings → Secrets → Actions:

  • VPS_HOST → VPS IP
  • VPS_USERubuntu (or VPS username)
  • VPS_KEY → contents of ~/.ssh/deploy_key_example
  • ENV_FILE → entire .env file contents

✅ Key Differences

Feature Next.js (SSR) React (Static)
Build Command npm run build npm run build
Serve Method PM2 Node.js process Nginx static serve
Nginx Role Reverse proxy to Node server Directly serve /build
Port Required <PORT_OF_YOUR_APP>
PM2 Required

Top comments (0)