eduardweb.
DevOps & VPSIntermediar#nextjs#devops#vps#github-actions#ssh

Cum mi-am configurat pipeline-ul de GitHub Actions pentru Next.js pe VPS (fără Vercel)

De Dan Ciobanu, 28 mai 2026 · 5 vizualizări · 3 like-uri

Postat 28 mai 2026
yaml
name: Deploy Next.js App

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: Install dependencies
        run: npm ci

      - name: Build application
        env:
          NEXT_PUBLIC_API_URL: ${{ secrets.NEXT_PUBLIC_API_URL }}
        run: npm run build

      - name: Copy build to VPS
        uses: appleboy/scp-action@master
        with:
          host: ${{ secrets.VPS_IP }}
          username: ${{ secrets.VPS_USER }}
          key: ${{ secrets.SSH_PRIVATE_KEY }}
          source: ".next,public,package.json,package-lock.json,next.config.js"
          target: "/var/www/my-app"

      - name: Restart App via SSH
        uses: appleboy/ssh-action@master
        with:
          host: ${{ secrets.VPS_IP }}
          username: ${{ secrets.VPS_USER }}
          key: ${{ secrets.SSH_PRIVATE_KEY }}
          script: |
            cd /var/www/my-app
            npm ci --only=production
            pm2 reload my-next-app || pm2 start npm --name "my-next-app" -- start

Vercel e genial pentru MVP-uri, dar când proiectul începe să aibă tracțiune, costurile devin ridicole. Am mutat recent o aplicație Next.js cu 12.000 de utilizatori activi pe un VPS de 6 euro de la Hetzner și am automatizat totul printr-un pipeline simplu de GitHub Actions.

Dacă vrei control total și costuri fixe, varianta asta e sfântă. Pierzi preview deploys-urile automate, dar salvezi bani grei.

Structura pipeline-ului: Cache-ul e rege

Cea mai mare greșeală pe care o văd la configurarea CI/CD pentru Next.js este ignorarea cache-ului. Fără el, fiecare build descarcă iar node_modules și recompilează absolut tot de la zero.

La primul run pe proiectul meu, build-ul a durat aproape 6 minute. Destul de enervant când ai de dat un hotfix rapid. După ce am configurat corect cache-ul pentru npm și .next/cache, timpul a scăzut la 1 minut și 40 de secunde. Am economisit cam 70% din timp la fiecare rulare a pipeline-ului.

Workflow-ul rulează pe trei piloni simpli: linting, teste și build-ul propriu-zis. Doar dacă toate astea trec cu succes, trecem la faza de deploy.

Deploy-ul prin SSH: Cum facem update fără downtime mare

Pentru deploy, am ales varianta clasică: rsync și PM2. Rulăm build-ul direct în runner-ul de GitHub, apoi copiem doar fișierele necesare pe server (fără codul sursă necompilat). E mult mai curat așa decât să faci git pull și npm run build direct pe serverul de producție, unde ai risca să blochezi CPU-ul VPS-ului în timpul compilării.

Folosesc appleboy/scp-action ca să urc build-ul și apoi appleboy/ssh-action ca să rulez un script de restart. Pe server, PM2 se ocupă de rularea procesului Next.js în fundal.

Capcane de care m-am lovit

Cea mai mare bătaie de cap am avut-o cu variabilele de mediu (.env). Next.js are nevoie de variabilele care încep cu NEXT_PUBLIC_ în timpul build-ului (build-time), nu doar la runtime. Dacă le pui doar pe server, client-side-ul nu le va vedea și te trezești cu API calls către undefined. Am rezolvat asta injectând secretele din GitHub direct în pasul de build din workflow.

Un alt trade-off e downtime-ul de o secundă când PM2 dă restart. Pentru un proiect mic spre mediu, e perfect acceptabil. Dacă ai nevoie de zero-downtime real, trebuie să te uiți spre un reverse proxy mai deștept sau Docker cu blue-green deployment, dar asta adaugă o complexitate pe care s-ar putea să nu o vrei încă.

Voi cum faceți? Rămâneți pe Vercel până când factura devine o problemă, sau preferați bătaia de cap inițială cu un VPS configurat manual?

Răspunsuri 0

Se încarcă răspunsurile…

Loghează-te pentru a răspunde

Doar membrii comunității pot lăsa comentarii.