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)
Prepare the Ubuntu
Update system
sudo apt update && sudo apt upgrade -y
Set SSH setting
cd /etc/ssh/
vim /etc/ssh/sshd_config
- set the following rules
Port 2222 # any
PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes
GatewayPorts no
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
install required packages
sudo apt install -y git nginx
Install Node.js
curl -fsSL https://deb.nodesource.com/setup_lts.x | sudo -E bash -
sudo apt install -y nodejs
node -v
npm -v
Create a Deployment User
sudo adduser deploy
sudo usermod -aG sudo deploy
su - deploy
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
Add this public key to:
- GitHub -> Next.js Repository -> Setting -> Deploy keys
Test:
ssh -T git@github.com
If you create something other than id_ed25519, set this:
vim ~/.ssh/config
Host github.com
HostName github.com
User git
IdentityFile ~/.ssh/your_ssh_file_name
IdentitiesOnly yes
chmod 600 ~/.ssh/config
chmod 600 ~/.ssh/your_ssh_file_name
chmod 644 ~/.ssh/your_ssh_file_name.pub
ssh -T git@github.com
Clone the repository
mkdir ~/app
chmod 755 ~/app/
cd ~/app
git clone git@github.com:USERNAME/Repository.git
cd Repository
chmod 755 ~/app/Repository
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
Configure Nginx
Create Nginx config
sudo nano /etc/nginx/sites-available/nextjs
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;
}
}
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
※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
Issue certificate
sudo certbot --nginx -d sub.example.com
Auto-renew test:
sudo certbot renew --dry-run
GitHub Actions
on Local your PC
cd ~/.ssh
ssh-keygen -t ed25519 -C "github-actions"
cat ~/.ssh/for-github-actions.pub
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
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

Top comments (0)