name: Deploy Next.js
on:
push:
branches: [main]
jobs:
build-and-deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Build project
run: npm run build
- name: Deploy via SSH
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.HOST }}
username: ${{ secrets.USERNAME }}
key: ${{ secrets.SSH_KEY }}
script: |
cd /var/www/my-app
git pull origin main
npm ci
npm run build
pm2 restart my-next-appM-am săturat să tot văd tutoriale care te trimit direct pe Vercel de parcă VPS-ul e o relicvă a trecutului. Vercel e mișto până când proiectul crește și te trezești cu facturi de sute de dolari pentru bandwidth sau funcții serverless care expiră. Recent, la un proiect de tip SaaS cu vreo 12k useri activi, am decis să rămânem pe un VPS chior de la Hetzner. Am vrut însă aceeași experiență de „git push and forget”.
Am pățit de prea multe ori să uit să rulez testele înainte de deploy sau, mai rău, să dau un npm build pe server și să-mi crape procesorul pentru că RAM-ul era deja la limită. Așa că mi-am bătut capul câteva ore să pun la punct un pipeline de GitHub Actions care să facă tot greul în cloud-ul lor, nu pe serverul meu de producție.
CI-ul: Linting și Teste (nu le sări)
Primul pas e clasic: verificăm dacă codul e scris după standarde și dacă nu am stricat ceva critic. Am configurat job-ul să ruleze la fiecare push pe main sau la orice Pull Request.
Un mic truc pe care l-am învățat: folosește mereu npm ci în loc de npm install. E mult mai rapid și mai predictibil pentru că instalează exact versiunile din package-lock.json. La proiectul menționat, am economisit cam 30% la build time doar folosind caching pentru node_modules și folderul .next/cache. Fără caching, pierzi vreo 2-3 minute aiurea la fiecare rulare.
Build-ul: Unde îl facem?
Aici e marea dilemă. Să faci build-ul direct pe VPS sau pe GitHub? Eu am ales să-l fac pe GitHub. De ce? Pentru că next build e un proces gurmand. Pe un VPS cu 2GB sau 4GB RAM, un build de Next.js poate să sufoce procesele de Node care rulează deja pentru utilizatori.
Trade-off-ul e că trebuie să muți fișierele rezultate pe server. Dacă ai un proiect gigant, transferul prin SSH poate dura. Dar pentru 90% din cazuri, e mult mai sigur să livrezi un build gata „fumat”.
Deploy-ul prin SSH și PM2
Pentru deploy, am folosit appleboy/ssh-action. E sfânt. Îi dai secretele (IP, user, cheie SSH) și el se conectează la serverul tău și execută comenzile de care ai nevoie.
Logica mea e simplă: după ce build-ul e gata pe GitHub, arhivez tot ce e relevant (folderul .next, public, package.json, next.config.js), îl trimit prin SCP pe server, îl dezarhivez și îi dau un restart la procesul de PM2.
Am avut cazul în care deploy-ul a picat la jumătate și serverul a rămas într-o stare inconsistentă. De atunci, folosesc o strategie de tip „blue-green” simplificată: dezarhivez într-un folder nou, schimb un symlink și abia apoi restartez PM2. Dacă ceva crapă, folderul vechi e încă acolo.
Concluzie și un sfat sincer
Toată distracția asta m-a dus de la un deploy manual de 10 minute (cu frica în sân că uit ceva) la o automatizare care durează sub 3 minute.
Merge bine pentru proiecte medii unde vrei să ții costurile sub control. E nasol dacă ai o echipă imensă și zeci de microservicii, unde Docker ar fi mult mai indicat pentru consistență. Dar pentru un monolitic Next.js, SSH-ul e rege.
Voi cum faceți deploy-ul pe VPS? Mergeți pe varianta „old school” cu SSH sau ați trecut toți pe Docker?