name: Deploy Next.js to VPS
on:
push:
branches: [ main ]
jobs:
build-and-deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: 18
cache: 'npm'
- name: Cache Next.js build
uses: actions/cache@v3
with:
path: ${{ github.workspace }}/.next/cache
key: ${{ runner.os }}-nextjs-${{ hashFiles('**/package-lock.json') }}-${{ hashFiles('**.[jt]s', '**.[jt]sx') }}
restore-keys: |
${{ runner.os }}-nextjs-${{ hashFiles('**/package-lock.json') }}-
- name: Install dependencies
run: npm ci
- name: Run Lint & Tests
run: |
npm run lint
npm run test -- --watchAll=false
- name: Build application
run: npm run build
env:
DATABASE_URL: ${{ secrets.DATABASE_URL }}
- name: Compress build files
run: tar -czf deploy.tar.gz .next public package.json package-lock.json next.config.js
- name: Copy archive to VPS via SSH
uses: appleboy/scp-action@master
with:
host: ${{ secrets.VPS_IP }}
username: ${{ secrets.VPS_USER }}
key: ${{ secrets.SSH_PRIVATE_KEY }}
source: "deploy.tar.gz"
target: "/var/www/my-next-app"
- name: Deploy and Restart PM2
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.VPS_IP }}
username: ${{ secrets.VPS_USER }}
key: ${{ secrets.SSH_PRIVATE_KEY }}
script: |
cd /var/www/my-next-app
tar -xzf deploy.tar.gz
rm deploy.tar.gz
npm ci --only=production
pm2 reload my-next-app || pm2 start npm --name "my-next-app" -- startSă fim sinceri, Vercel este genial pentru prototipuri sau proiecte mici, dar când începi să ai trafic sau vrei să legi baza de date local, costurile devin ridicole. La un proiect recent, cu vreo 14.000 de utilizatori activi pe lună, am decis să mut totul pe un VPS ieftin de la Hetzner.
Marea provocare a fost să nu pierd confortul acelui „git push” care declanșează deploy-ul automat. Așa că mi-am scris propriul workflow în GitHub Actions. Am trecut prin toate erorile posibile de permisiuni și build-uri eșuate până am ajuns la o variantă stabilă, care rulează în mai puțin de 3 minute.
Optimizarea cache-ului: Cum am redus timpul de build cu 60%
Cea mai mare greșeală pe care o văd în pipeline-urile de Next.js este lipsa cache-ului pentru folderul .next/cache. Fără el, Next.js recompilează absolut fiecare pagină și componentă de la zero la fiecare rulare.
Inițial, build-ul meu dura aproape 7 minute pe runner-ul gratuit de la GitHub. După ce am configurat corect cache-ul pentru node_modules și .next/cache folosind actions/cache, timpul a scăzut la puțin sub 2 minute și jumătate. Diferența e uriașă când ai de făcut hotfix-uri rapide în producție.
Build pe runner vs. Build pe VPS
Aici e un trade-off important de care m-am lovit. Ai două opțiuni: faci build-ul pe serverul tău sau îl faci direct în GitHub Actions și trimiți doar rezultatul.
Eu am ales să fac build-ul pe runner-ul de GitHub dintr-un motiv simplu: next build mănâncă foarte multă memorie RAM. Dacă ai un VPS cu 2GB RAM și rulezi build-ul direct acolo în timp ce ai și utilizatori pe site, sunt șanse mari ca procesul să fie omorât de sistem (out of memory) sau site-ul să devină extrem de lent timp de un minut.
Prin urmare, pipeline-ul meu face build-ul în cloud, arhivează folderele .next, public, package.json și next.config.js, le trimite prin SSH pe VPS, le dezarhivează și dă restart la procesul de Node.js.
Compromisul sincer: Avantaje și dezavantaje
Să fim realiști, soluția asta nu e perfectă.
Ce câștigi: Plătești doar VPS-ul (5-10 euro pe lună), ai control total asupra serverului, poți rula baze de date sau procese de background pe aceeași mașină și nu ai limite de bandwidth absurde ca pe platformele serverless.
Ce pierzi: Trebuie să te ocupi singur de reverse proxy (Nginx sau Caddy), de reînnoirea certificatelor SSL cu Certbot și de monitorizarea proceselor. Dacă PM2 moare la 3 dimineața, e treaba ta să îl ridici înapoi.
Pentru a evita downtime-ul în timpul deploy-ului, folosesc PM2 în modul cluster. Când dau pm2 reload app, acesta repornește instanțele una câte una, asigurând zero downtime pentru vizitatori.
Cum vă gestionați deploy-urile de Next.js? Rămâneți pe Vercel pentru confort sau preferați controlul unui server dedicat?