module.exports = {
apps: [
{
name: 'next-app',
script: 'node_modules/next/dist/bin/next',
args: 'start',
instances: 'max',
exec_mode: 'cluster',
env: {
PORT: 3000,
NODE_ENV: 'production'
}
}
]
};Mi-am luat destule bătăi de cap cu Vercel când au început să ne taxeze la bandwidth de ne-a usturat buzunarul. La un proiect cu vreo 12k useri activi pe zi, am mutat totul pe un VPS de 6 euro de la Hetzner și am redus costurile de 10 ori. În postarea asta îți arăt exact cum am configurat PM2, Nginx și logrotate ca să am zero downtime și zero bătăi de cap.
Evident, există un trade-off destul de mare în toată ecuația asta. Pe Vercel dai un simplu push în git și ai uitat de el. Aici, pe VPS-ul tău, tu ești sysadmin-ul. Dacă se blochează baza de date sau moare serverul la 3 dimineața, ești singurul responsabil. Pentru mine însă, economia de bani și controlul total pe mașină au meritat din plin efortul de setup inițial.
PM2 în mod cluster pentru zero downtime
Dacă rulezi simplu npm start, aplicația ta rulează pe un singur thread. Dacă dă crash o singură rută din cauza unui bug neprevăzut, pică tot site-ul până când își dă restart procesul (dacă are cine să-i dea). De asta folosim PM2 în mod cluster. Acesta spawnează câte un proces pentru fiecare core de procesor și face load balancing între ele direct la nivel de rețea locală.
Când faci deploy la o versiune nouă, în loc de clasicul restart care ar opri site-ul pentru câteva secunde, folosim pm2 reload. PM2 va reporni procesele pe rând. Clientul nu va simți absolut nicio întrerupere, request-urile fiind redirecționate doar către procesele active.
Nginx ca reverse proxy
Aplicația Next.js rulează local pe portul 3000. Nu vrei să expui portul ăsta direct în exterior, ci punem Nginx în față ca să preia traficul pe portul 80/443 și să-l trimită intern.
Configurația de Nginx e destul de clasică, dar ai grijă să pasezi headerele corecte pentru IP-ul real al clientului (X-Real-IP, X-Forwarded-For). Altfel, în logurile Next.js o să vezi că toate request-urile vin de la localhost (127.0.0.1). De asemenea, îți recomand să configurezi direct directiva client_max_body_size 10M (sau cât ai nevoie) dacă ai upload de fișiere, altfel Nginx îți va da un blocaj scurt cu eroarea 413 Payload Too Large.
Logurile pot să-ți omoare serverul rapid
Am pățit o fază stupidă la un moment dat. PM2 scrie tot ce dă Next.js în stdout și stderr în niște fișiere text simple în folderul .pm2. După vreo 3 luni de rulare fără probleme, site-ul a început să dea erori ciudate de baza de date și să refuze conexiuni. Când m-am conectat prin SSH, am realizat că spațiul de stocare de pe SSD era 100% plin. Un singur fișier de log de la PM2 ajunsese la peste 25GB din cauza unor warning-uri repetitive.
Soluția pe care o folosesc acum este utilitarul nativ din Linux numit logrotate. Îi faci o regulă simplă în /etc/logrotate.d/pm2 care să verifice logurile zilnic, să le comprime în format .gz și să păstreze doar ultimele 7-14 zile. Curat, simplu și fără module npm în plus care să ruleze în background.
Certbot pentru HTTPS în 2 minute
Nu mai are rost să cumperi certificate SSL sau să te complici manual. Certbot și Let's Encrypt fac treaba asta gratuit. Rulezi sudo certbot --nginx -d domeniul-tau.ro și scriptul își face singur de cap: modifică automat config-ul de Nginx, adaugă rutele de SSL și configurează un cron job în sistem pentru reînnoire automată înainte să expire cele 90 de zile de valabilitate.
Voi cum faceți deploy la Next.js când vreți să evitați serverless-ul celor de la Vercel? Mergeți pe VPS clasic configurat manual sau ați trecut deja la Docker și Kubernetes chiar și pentru proiecte de dimensiuni medii?