DEV Community

Shelner
Shelner

Posted on

How to deploy Next.js App to VPS (Ubuntu server) with GitHub-Actions

Explain How to deploy a Next.js Application to an ubuntu server (VPS) using GitHub Actions (private repository), NginX, and SSL (Let's Encrypt).

Overall Architecture

GitHub (private repository)
   ↓ GitHub Actions 
Ubuntu VPS
  - Node.js (Next.js build & run)
  - PM2 (process manager)
  - Nginx 
  - Let's Encrypt (SSL)
Enter fullscreen mode Exit fullscreen mode

Prepare the Ubuntu

Update system

sudo apt update && sudo apt upgrade -y
Enter fullscreen mode Exit fullscreen mode

Set SSH setting

cd /etc/ssh/
vim /etc/ssh/sshd_config
Enter fullscreen mode Exit fullscreen mode
  • set the following rules
Port 2222 # any
PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes
GatewayPorts no
Enter fullscreen mode Exit fullscreen mode

Set ufw

sudo ufw limit 2222/tcp # ssh port
sudo ufw allow 80/tcp # http
sudo ufw allow 443/tcp # hppts
sudo ufw enable
sudo ufw status verbose # checking
sudo ufw reload
Enter fullscreen mode Exit fullscreen mode

install required packages

sudo apt install -y git nginx
Enter fullscreen mode Exit fullscreen mode

Install Node.js

curl -fsSL https://deb.nodesource.com/setup_lts.x | sudo -E bash -
sudo apt install -y nodejs
node -v
npm -v
Enter fullscreen mode Exit fullscreen mode

Create a Deployment User

sudo adduser deploy
sudo usermod -aG sudo deploy
su - deploy
Enter fullscreen mode Exit fullscreen mode

Clone the private GitHub Repository (SSH)

On VPS: create SSH key

mkdir -p /home/deploy/.ssh
chmod 700 /home/deploy/.ssh

# no passphrase <- this is important
ssh-keygen -t ed25519 -C "deploy@server"
cat ~/.ssh/id_ed25519.pub
Enter fullscreen mode Exit fullscreen mode

Add this public key to:

  • GitHub -> Next.js Repository -> Setting -> Deploy keys

Test:

ssh -T git@github.com
Enter fullscreen mode Exit fullscreen mode

If you create something other than id_ed25519, set this:

vim ~/.ssh/config
Enter fullscreen mode Exit fullscreen mode
Host github.com
    HostName github.com
    User git
    IdentityFile ~/.ssh/your_ssh_file_name
    IdentitiesOnly yes
Enter fullscreen mode Exit fullscreen mode
chmod 600 ~/.ssh/config
chmod 600 ~/.ssh/your_ssh_file_name
chmod 644 ~/.ssh/your_ssh_file_name.pub
ssh -T git@github.com
Enter fullscreen mode Exit fullscreen mode

Clone the repository

mkdir ~/app
chmod 755 ~/app/
cd ~/app
git clone git@github.com:USERNAME/Repository.git
cd Repository
chmod 755 ~/app/Repository
Enter fullscreen mode Exit fullscreen mode

Install pnpm and Dependencies & Build Next.js app

sudo corepack enable
corepack prepare pnpm@latest --activate
pnpm -v
pnpm install
pnpm run build
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash
source ~/.bashrc
nvm install --lts
nvm use --lts
npm install -g pm2
pm2 start npm --name "mynextjs" --start
pm2 save
pm2 startup
Enter fullscreen mode Exit fullscreen mode

Configure Nginx

Create Nginx config

sudo nano /etc/nginx/sites-available/nextjs
Enter fullscreen mode Exit fullscreen mode
server {
    listen 80;
    server_name sub.example.com;

    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;
    }
}
Enter fullscreen mode Exit fullscreen mode

Enable:

sudo ln -s /etc/nginx/sites-available/sub.example.com /etc/nginx/sites-enabled/
sudo nginx -t
sudo rm /etc/nginx/sites-enabled/default
sudo systemctl reload nginx
Enter fullscreen mode Exit fullscreen mode

※Caution
Your VPS Sometimes uses packet filter.
If it uses packet filter, you have to allow ports that are 2222, 80 and 443.


Enable SSL with Let’s Encrypt

Install Certbot

sudo apt install -y certbot python3-certbot-nginx
Enter fullscreen mode Exit fullscreen mode

Issue certificate

sudo certbot --nginx -d sub.example.com
Enter fullscreen mode Exit fullscreen mode

Auto-renew test:

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

GitHub Actions

on Local your PC

cd ~/.ssh
ssh-keygen -t ed25519 -C "github-actions"
cat ~/.ssh/for-github-actions.pub
Enter fullscreen mode Exit fullscreen mode

Access GitHub Web -> Your Repository on GitHub -> Settings -> Secrets and variables -> Actions -> New Repository secret -> Name SSH_PRIVATE_KEY

  • Private key → GitHub Secrets (SSH_PRIVATE_KEY)
  • Public key~deploy/.ssh/authorized_keys

Also set the following variables on GitHub:

paste private key as `SSH_PRIVATE_KEY`
set `SSH_HOST`` -> 111.111.111.111 (Your VPS IP Address)
set `SSH_USER` -> deploy
set `SSH_PORT` -> 2222
Enter fullscreen mode Exit fullscreen mode

On your Next.js app, create this:

.github/workflows/deploy.yml

name: Deploy Next.js

on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v4

      - name: Setup SSH
        run: |
          mkdir -p ~/.ssh
          echo "${{ secrets.SSH_PRIVATE_KEY }}" > ~/.ssh/id_ed25519
          chmod 600 ~/.ssh/id_ed25519
          ssh-keyscan -p "${{ secrets.SSH_PORT }}" -H "${{ secrets.SSH_HOST }}" >> ~/.ssh/known_hosts

      - name: Deploy
        run: |
          ssh -i ~/.ssh/id_ed25519 "${{ secrets.SSH_USER }}"@"${{ secrets.SSH_HOST }}" -p "${{ secrets.SSH_PORT }}" << 'EOF'
            export NVM_DIR="$HOME/.nvm"
            source "$NVM_DIR/nvm.sh"

            cd /home/${{ secrets.SSH_USER }}/app/Repository
            git pull origin main
            pnpm install
            pnpm run build
            pm2 restart mynextjs
          EOF
Enter fullscreen mode Exit fullscreen mode

Top comments (0)