Viralni skok saobraćaja, upozorenja o potrošnji i prelazak na VPS. Ilustracija; brojke na ekranu su dekorativne.
Viralni skok saobraćaja, upozorenja o potrošnji i prelazak na VPS. Ilustracija; brojke na ekranu su dekorativne.

Veliki praktični vodič · Mreže, serveri i cloud · Ažurirano: 2. novembar 2026.

Ukratko. Moja aplikacija za pregled imovine javnih funkcionera dobila je za oko 24 sata približno 100.000 unikatnih poseta i 600.000 prikaza stranica. Nisam bio za računarom. Oko 12 sati posle početka skoka stigla su dva obaveštenja: potrošnja na Vercelu dostigla je 50 USD, a na Neonu još 50 USD. Reagovao sam i prebacio aplikaciju na jeftiniji VPS. Ovaj vodič objašnjava šta se tehnički dešava u takvom trenutku, šta Vercel i Neon tačno naplaćuju po zvaničnim cenovnicima, kako se smanjuje broj skupih operacija, kako se postavlja finansijska zaštita koja zaista nešto zaustavlja i kako se migracija na VPS izvodi bez gubitka podataka.

Uvod: kada velika poseta prestane da bude samo dobra vest

Svako ko pravi aplikacije želi trenutak u kome projekat „pukne”: link počne da se deli, ljudi pišu o njemu, a brojač poseta raste brže nego ikada. Upravo zbog tog trenutka i pravimo stvari koje objavljujemo.

Postoji, međutim, strana viralnog uspeha o kojoj se mnogo manje priča. Infrastruktura koja automatski izdržava veće opterećenje istovremeno automatski povećava i račun. Što je platforma elastičnija, to brže prati saobraćaj, a s njim i potrošnju.

To sam nedavno iskusio na sopstvenom projektu.

Jedna moja aplikacija, alat za pregled i pretragu imovine javnih funkcionera, odjednom se proširila mrežama. Za približno 24 sata privukla je oko 100.000 unikatnih poseta i oko 600.000 prikaza stranica. Aplikacija je radila na Vercelu, a podatke je čuvala u PostgreSQL bazi na Neonu.

Problem nije bio u tome što aplikacija nije izdržala. Izdržala je. Problem je bio u tome što zbog privatnih obaveza nisam bio prisutan i nisam pratio šta se dešava.

Otprilike 12 sati kasnije stigla su mi obaveštenja koja nisam mogao da ignorišem:

  • na Vercelu je potrošnja dostigla 50 USD,
  • na Neonu je potrošnja dostigla još 50 USD.

Dakle, oko 100 USD evidentirane potrošnje na dva servisa, za nekoliko sati, bez ijednog planiranog troška. Nisam želeo da čekam i gledam koliko će još da poraste. Proverio sam stanje, procenio gde odlazi novac i aplikaciju preselio na jeftiniji VPS, gde je trošak predvidljiv.

Pre nego što krenemo, nekoliko važnih ograda, jer ovaj tekst ne želi da bude priča o „lošem cloudu”:

  1. Vremenske metrike nisu iste. Broj od 100.000 poseta odnosi se na period od približno 24 sata, a obaveštenja o potrošnji stigla su posle oko 12 sati. To nisu dve strane iste jednačine.
  2. Obaveštenje nije faktura. Iznosi od 50 USD su evidentirana potrošnja iz obaveštenja, ne nužno konačan iznos računa posle svih kredita i obračuna.
  3. Iz obaveštenja se ne vidi uzrok. Poruka da je potrošeno 50 USD ne kaže koliko je otišlo na CPU, memoriju, prenos podataka ili bazu. Za to su potrebni detaljni obračuni, o čemu govori prvo poglavlje.
  4. Vercel i Neon nisu loše platforme. Naprotiv. Obe su odlične za razvoj i produkciju. Problem nastaje kada model naplate ne odgovara stvarnom načinu na koji se aplikacija koristi.

Nije isto imati 10.000 posetilaca koji čitaju statičke stranice i 10.000 posetilaca od kojih svaki pokreće desetine upita prema bazi. U prvom slučaju trošak može biti zanemarljiv. U drugom, relativno mala publika pravi ozbiljno opterećenje.

U nastavku prolazimo kroz ceo problem: šta se dešava pri naglom rastu saobraćaja, šta platforme zaista naplaćuju po svojim cenovnicima, kako se otkriva najskuplji deo aplikacije, kako se trošak smanjuje keširanjem, kako se zaustavljaju botovi, kako se postavlja finansijska zaštita, kako izgleda matematika za 10.000, 100.000 i milion poseta i kako se izvodi migracija na VPS, sa konkretnim konfiguracijama za Next.js, PostgreSQL, Docker i Caddy.

Cilj nije da svako napusti cloud. Cilj je da niko ne mora da čeka neprijatno obaveštenje da bi prvi put ozbiljno razmislio o troškovima sopstvene aplikacije.

Šta se zapravo događa kada aplikacija postane viralna

1. Posete, prikazi i HTTP zahtevi nisu ista stvar

Pre bilo kakve analize treba razdvojiti metrike koje se često mešaju:

MetrikaŠta značiZašto je važna za račun
Unikatni posetilacBrowser ili uređaj koji analitika prepozna kao jednog posetiocaGovori koliko ljudi je došlo, ne koliko posla je urađeno
Poseta (sesija)Jedan dolazak na sajt sa nizom radnjiJedna osoba može imati više sesija
Prikaz straniceUčitavanje ili prikaz stranice po pravilima analitikeKod klijentske navigacije ne mora da znači novi HTML zahtev
HTTP zahtevPojedinačna komunikacija sa CDN-om ili serveromJedan prikaz može da izazove desetine zahteva za JS, CSS, slike i API
Poziv funkcijeIzvršavanje serverless ili backend kodaNe izaziva ga svaki zahtev; keširan odgovor ne pokreće funkciju
Upit prema baziSQL operacija nad bazomJedan API poziv može da izazove nijedan, jedan ili deset upita

Platforme ne naplaćuju „posete”. Naplaćuju zahteve, prenos podataka, procesorsko vreme, memoriju i rad baze. Zato je ključno pitanje koliko posla izaziva svaka poseta.

2. Šta znači 100.000 poseta i 600.000 prikaza

Odnos 600.000 prikaza prema 100.000 poseta daje grubo šest prikaza po poseti. To ne znači da je svako otvorio tačno šest stranica. Neko je otvorio jednu, neko dvadeset.

Hajde da napravimo ilustraciju. Pretpostavimo da svaki prikaz izaziva dva API poziva:

text
600.000 prikaza × 2 API poziva = 1.200.000 API zahteva

Ako svaki od tih poziva pokrene po dva SQL upita, teorijski dobijamo 2.400.000 upita prema bazi.

Ali ako postoji dobar keš, veliki deo tih zahteva nikada ne stigne do baze. Ako je poziv nepotreban, može se ukloniti. Ako hiljade ljudi traže isti javni podatak, on može da se izračuna jednom i isporuči svima.

U tome je suština cele priče: broj ljudi ne možete da kontrolišete, ali količinu posla koju svaka poseta izaziva možete, i to veoma mnogo.

3. Zašto nagli skok pravi drugačiji problem od postepenog rasta

Dnevni prosek često sakriva stvarno opterećenje. Šest stotina hiljada prikaza ravnomerno raspoređenih na 24 sata daje oko 6,94 prikaza u sekundi, što savremena infrastruktura obrađuje bez problema.

Viralni saobraćaj, međutim, nije ravnomeran. Objava popularnog naloga, deljenje u velikim grupama ili prilog u medijima šalju talas posetilaca za nekoliko minuta. Zato se infrastruktura ne posmatra kroz ukupan dnevni broj, nego kroz:

  • prosečan i maksimalan broj zahteva u sekundi,
  • broj istovremenih korisnika i otvorenih konekcija,
  • trajanje backend operacija, posebno p95 i p99 latenciju,
  • potrošnju CPU-a i memorije,
  • opterećenje baze i broj konekcija prema njoj,
  • procenat odgovora iz keša, posebno za HTML i API,
  • greške i isteke vremena,
  • izlazni saobraćaj,
  • trošak nastao tokom samih pikova.

Posebno je opasna situacija u kojoj sistem radi „dovoljno dobro”. Korisnici ne primećuju problem, stranice se otvaraju, podaci stižu. U pozadini, međutim, sistem troši sve više računarstva, prenosa i kapaciteta baze. Elastična platforma u tom trenutku radi tačno ono što treba: skalira. I naplaćuje.

4. Kako utvrditi šta je izazvalo trošak

Kada stigne obaveštenje, prvi posao je da se reaguje. Ali za ozbiljnu analizu posle toga nije dovoljno znati da je potrošeno 50 USD ovde i 50 USD tamo. Potrebno je rekonstruisati ponašanje sistema, iz najmanje pet izvora:

IzvorŠta tražimo
Web analitikaPosete, prikaze, izvore saobraćaja, raspodelu po satima
Vercel UsageKoje obračunske stavke su porasle, po projektu i servisu
Vercel ObservabilityNajčešće rute i funkcije, trajanje, prenos, greške
Neon Billing i MonitoringCompute (CU-hours), veličinu compute-a kroz vreme, storage, prenos
Aplikacioni i pristupni logoviNajskuplje endpointe, ponovljene zahteve, botove, greške

Podatke treba poravnati po vremenu, idealno u UTC-u, da bi poređenje bilo dosledno. Ako je trošak skočio u 14 časova, a istovremeno je skočio broj poziva određene API rute, to je dobar trag. Ali korelacija nije dokaz. Rast broja poziva funkcija može se poklopiti sa rastom prenosa, rada baze ili optimizacije slika. Tek obračunska kategorija, uz kod i logove, pokazuje gde je novac zaista otišao.

Važno: iz samog obaveštenja o potrošenih 50 USD nije moguće pouzdano utvrditi koliko je otpalo na CPU, memoriju, mrežu ili bazu. Zato u ovom tekstu ne tvrdim tačan tehnički uzrok svog računa, nego pokazujem kako se on traži.

Šta Vercel i Neon zaista naplaćuju

Upozorenja o potrošnji koja stižu posle viralnog skoka. Ilustracija; procenti i iznosi na ekranu su dekorativni.
Upozorenja o potrošnji koja stižu posle viralnog skoka. Ilustracija; procenti i iznosi na ekranu su dekorativni.

1. Vercel: jedna aplikacija, više nezavisnih obračunskih stavki

Vercel nije samo server na kome se nalazi aplikacija. To je globalna mreža za isporuku sadržaja, izvršno okruženje za funkcije, keš, optimizacija slika, firewall i observability, i svaki od tih slojeva ima svoju obračunsku jedinicu.

Pro plan košta 20 USD mesečno i uključuje 20 USD kredita za korišćenje. Sve preko toga plaća se po potrošnji, bez gornje granice, osim ako je sami ne postavite. Prema Vercelovom cenovniku, svi novi timovi dobijaju podrazumevani on-demand budžet od 200 USD, sa obaveštenjima, a automatsko pauziranje pri 100% je opcija koju treba posebno uključiti.

Cene su regionalne. Za Srbiju je najbliži region Frankfurt (fra1), pa u tabeli navodim zvanične on-demand stope za Frankfurt, uz raspon za sve regione:

StavkaFrankfurt (fra1)Raspon po regionima
CDN Requests$2,60 po 1M zahteva$2,00 do $3,20
Fast Data Transfer$0,15 po GB$0,15 do $0,35
Fast Origin Transfer$0,06 po GB$0,06 do $0,43
Fluid Active CPU$0,184 po satu$0,128 do $0,221
Fluid Provisioned Memory$0,0152 po GB-satu$0,0106 do $0,0183
ISR Reads / Writes$0,52 / $5,20 po 1M jedinica$0,40 do $0,64 / $4,00 do $6,40
Runtime Cache Reads / Writes$0,52 / $5,20 po 1M jedinica$0,40 do $0,64 / $4,00 do $6,40
Image Optimization Transformations$0,0601 po 1K$0,05 do $0,0812
WAF Rate Limiting$0,65 po 1M dozvoljenih zahteva$0,50 do $0,80

Pozivi funkcija na Pro planu naplaćuju se 0,60 USD po milion, a Hobby plan uključuje milion poziva mesečno. Cene su bez poreza i proverene su 2. novembra 2026. na zvaničnim stranicama za regionalne cene i Fluid compute.

Šta svaka stavka znači u praksi:

CDN Requests. Svaki zahtev koji stigne do Vercelove mreže je CDN zahtev, i to važi i za keširane odgovore. Keš štedi skuplji rad funkcija, ali ne briše sam zahtev. Jedan prikaz stranice sa 20 resursa znači 20 CDN zahteva.

Fast Data Transfer. Prenos od Vercela do browsera. Velike slike, teški JavaScript paketi, PDF-ovi i API odgovori brzo ga podižu. Vercel sam kompresuje odgovore i dodaje ETag zaglavlja da browser ne preuzima iste fajlove iznova.

Fast Origin Transfer. Prenos između CDN sloja i izvršnog okruženja. Raste kada veliki deo zahteva prolazi pored keša.

Fluid compute: CPU, memorija i pozivi. Ovo je najvažnija razlika u odnosu na stare serverless modele:

  • Active CPU se naplaćuje samo dok kod zaista radi. Dok funkcija čeka odgovor baze ili spoljnog API-ja, CPU se ne naplaćuje.
  • Provisioned Memory se naplaćuje za ceo životni vek instance, i dok funkcija čeka na I/O. Jedna instanca, međutim, obrađuje više zahteva istovremeno, pa memorija nije proporcionalna broju zahteva.
  • Invocations se broje za svaki zahtev funkciji, i kada se završi greškom.

Vercelov zvanični primer to lepo pokazuje: funkcija koja 100 ms obrađuje podatke i 400 ms čeka bazu plaća aktivni CPU samo za 100 ms. Memoriju, međutim, plaća dok instanca radi. Zato ubrzavanje SQL upita ne smanjuje CPU stavku, ali skraćuje život instance i smanjuje memoriju.

Važno za Next.js projekte na Vercelu: Vercel objedinjuje Data Cache u Runtime Cache. Prema zvaničnoj objavi, čitanja i upisi Data Cache-a koji ranije nisu bili naplaćivani preći će na cene Runtime Cache-a, a postojeći timovi detalje migracije dobijaju unapred. Ako aplikacija intenzivno koristi fetch keširanje ili unstable_cache, proverite koliko čitanja i upisa pravi pre nego što ova stavka počne da se pojavljuje na računu.

Postoji i alternativa za projekte sa nepredvidivim saobraćajem: Flat Rate CDN na Pro planu. Umesto naplate po CDN zahtevima i prenosu, plaća se fiksna mesečna cena za CDN, a privremeni skokovi ne povećavaju račun za te stavke. Funkcije i baza i dalje se naplaćuju posebno, pa ovo rešava samo deo problema, ali je vredno razmotriti pre selidbe.

2. Neon: PostgreSQL koji se plaća po vremenu rada

Neon je PostgreSQL, ali ne u klasičnom modelu „iznajmljujem server koji radi 24 sata”. Compute i storage su razdvojeni. Compute se skalira po opterećenju i može da se ugasi kada baza miruje.

Osnovna jedinica je CU (Compute Unit). Jedan CU je približno 4 GB RAM-a, uz pripadajući CPU i lokalni SSD. Obračun je jednostavan:

text
CU-hours = prosečna veličina compute-a (CU) × broj sati rada
Trošak compute-a = CU-hours × cena po CU-hour

Zvanične cene na Launch planu, provereno 2. novembra 2026:

StavkaLaunch plan
Compute$0,106 po CU-hour
Storage$0,35 po GB mesečno
Instant restore istorija$0,20 po GB mesečno, prema količini promena u izabranom periodu
Javni mrežni prenos500 GB po projektu mesečno uključeno, zatim $0,10 po GB
Autoscalingdo 16 CU (64 GB RAM)
Scale to zeroposle 5 minuta neaktivnosti, može se isključiti

Nekoliko proračuna da se osete razmere:

text
1 CU × 10 h × $0,106 = $1,06
4 CU × 12 h × $0,106 = $5,09
1 CU × 730 h (ceo mesec) × $0,106 = $77,38
8 CU × 12 h × $0,106 = $10,18

Sama compute stavka za jedan intenzivan dan nije dramatična. Ali obratite pažnju na dve stvari koje mogu da je multipliciraju: koliko dugo compute ostaje aktivan i na koju veličinu ga autoscaling podigne. Baza koja se pod opterećenjem podigne na 8 ili 16 CU i ostane tamo satima ima potpuno drugačiji račun od baze koja radi na 0,25 CU.

Autoscaling radi u opsegu koji sami zadate, na primer od 2 do 8 CU. Previsoka gornja granica dozvoljava skuplje skaliranje. Preniska izaziva usporavanje i greške pod opterećenjem. Granica je istovremeno i tehnička i finansijska odluka.

Scale to zero gasi compute posle 5 minuta neaktivnosti i budi ga za nekoliko stotina milisekundi pri sledećem upitu. To je odlično za razvoj i aplikacije sa povremenim saobraćajem. Ali stalne konekcije, periodični poslovi, health check koji gađa bazu ili logička replikacija sprečavaju bazu da se zaista ugasi. Uključen scale to zero ne znači automatski minimalan račun; treba proveriti stvarno ponašanje.

Javni mrežni prenos je stavka koju mnogi previde. Kada aplikacija na Vercelu čita podatke iz Neona, ti podaci putuju javnim internetom i ulaze u Neonov izlazni prenos. Na Launch planu 500 GB po projektu je uključeno, pa ovo retko postaje problem, ali kod aplikacija koje vraćaju velike skupove podataka vredi pratiti.

3. Konekcije i connection pooling

Kod serverless aplikacija posebno treba paziti kako se otvaraju konekcije prema PostgreSQL-u. Ako stotine kratkotrajnih funkcija istovremeno otvaraju direktne konekcije, baza troši resurse na upravljanje konekcijama umesto na korisne upite.

Neon nudi pooling preko ugrađenog PgBouncer-a, sa do 10.000 klijentskih konekcija. Pooled konekcija se dobija dodavanjem sufiksa -pooler na ime endpointa:

text
postgresql://korisnik:lozinka@ep-primer-123456-pooler.eu-central-1.aws.neon.tech/baza?sslmode=require

Dve stvari treba znati:

  • 10.000 ne znači 10.000 istovremenih upita. To je broj klijentskih konekcija koje PgBouncer prihvata; one dele mnogo manji broj stvarnih konekcija prema PostgreSQL-u.
  • Pooling radi u transaction modu. Sesijske funkcionalnosti, SET naredbe koje treba da traju kroz sesiju i migracije šeme zahtevaju direktnu konekciju bez -pooler sufiksa.

4. Zašto mojih 50 USD na Neonu ne dokazuje jedan uzrok

Lako je zaključiti da je velika poseta „potrošila 50 USD na SQL upite”. Bez detaljne statistike, takav zaključak nije dovoljno precizan. Da bi se račun rekonstruisao, moralo bi se znati kolika je bila veličina compute-a kroz vreme, koliko dugo je baza bila aktivna, koje su sve kategorije obračunate, da li su postojali drugi aktivni resursi (grane, istorija, replike) i kakvo je bilo stanje potrošnje pre samog skoka.

Brojke iz mog slučaja su stvaran povod za analizu, ali ne i dokaz jednog tehničkog uzroka. To je razlika između ozbiljnog tehničkog teksta i priče o tome kako je neka platforma „preskupa”.

Vercel, Cloudflare, VPS ili hibrid: koja arhitektura ima smisla

1. Ne postoji najjeftiniji hosting za svaku aplikaciju

Poređenje platformi po jednoj mesečnoj ceni nije dovoljno. Kod managed platforme plaćate automatizaciju, globalnu isporuku, lak deployment, preview okruženja, administraciju i skaliranje. Kod VPS-a dobijate sirove resurse i slobodu, ali na sebe preuzimate bezbednost, ažuriranja, backup, monitoring i oporavak.

Server od 15 ili 20 USD mesečno ne postaje automatski bolja infrastruktura. Za aplikaciju kojoj su potrebni visoka dostupnost, rezervni sistemi i stalno održavanje, razlika u ceni se brzo potroši na rad. Za relativno jednostavnu javnu aplikaciju u kojoj dominira čitanje, isti VPS može biti sasvim dovoljan.

2. Pet arhitektura i njihovi kompromisi

A) Vercel + Neon

text
Korisnik → Vercel CDN → Next.js funkcija → Neon PostgreSQL

Brza isporuka, jednostavne promene, mali administrativni teret. Problem nastaje kada skoro svaka poseta aktivira dinamičko izvršavanje, a ono zatim upite prema bazi. Dobro optimizovana aplikacija na ovom paru može biti vrlo ekonomična, naročito kada su javne stranice statičke, a baza se koristi samo kada mora. Ovu kombinaciju bih i dalje preporučio za veliki broj projekata.

B) Cloudflare + Vercel + Neon

text
Korisnik → Cloudflare → Vercel → Neon

Cloudflare preuzima deo zaštite i isporuke. Ali pažnja: Cloudflare po podrazumevanim podešavanjima ne kešira HTML ni JSON, kešira po ekstenziji fajla i poštuje Cache-Control zaglavlja sa origina. Dinamički sadržaj se mora posebno konfigurisati kroz Cache Rules. Dva CDN sloja zahtevaju jasno razumevanje cache zaglavlja, invalidacije i prosleđivanja IP adrese klijenta. Stranice sa prijavljenim korisnicima nikada ne smeju da se keširaju neselektivno.

C) VPS sa aplikacijom i bazom

text
Korisnik → Reverse proxy → Next.js → PostgreSQL (isti server)

Direktna kontrola nad CPU-om, memorijom, diskom i bazom, uz predvidljivu mesečnu cenu. Za aplikaciju sa mnogo javnih čitanja i umerenim upisima, vrlo ekonomično. Ali VPS ima plafon: ne pretvara se sam u deset servera, a jedan server je jedinstvena tačka otkaza bez rezervne instance i plana oporavka.

D) Cloudflare + VPS + PostgreSQL

text
Korisnik → Cloudflare CDN/WAF → VPS reverse proxy → aplikacija → PostgreSQL

Za javnu aplikaciju kojoj je kontrola troškova prioritet, ovo je jedan od najzanimljivijih modela. Cloudflare isporučuje statičke resurse i filtrira deo neželjenog saobraćaja, a VPS izvršava aplikaciju i lokalne upite. PostgreSQL ne sme biti dostupan sa interneta, a origin treba zaštititi od direktnog zaobilaženja Cloudflarea.

E) Odvojeni aplikacioni i database server

text
Korisnik → CDN/WAF → aplikacioni VPS → privatna mreža → database VPS

Nezavisno dimenzionisanje i bolja izolacija, uz više konfiguracije i ozbiljniji monitoring. Za mali projekat nije neophodno samo zato što deluje profesionalnije.

3. Uporedni pregled

KriterijumVercel + NeonCloudflare + VPSDva VPS-a
Početna implementacijaJednostavnaSrednje zahtevnaZahtevnija
Operativno održavanjeMaloVećeNajveće
ElastičnostIzraženaOgraničena resursima VPS-aZahteva planiranje
Predvidljivost osnovne ceneZavisi od potrošnjeVisokaVisoka
Administracija bazeManagedSamostalnaSamostalna
Backup i oporavakDelimično managedVaša odgovornostVaša odgovornost
Kontrola infrastruktureOgraničenijaVisokaVisoka

Tabela nije rangiranje kvaliteta. Prikazuje različite kompromise.

4. Kada bih danas izabrao VPS

Ako aplikacija ima mnogo javno dostupnih podataka, dominantno čitalački saobraćaj, relativno predvidljive zahteve i već pripremljen monitoring i backup, VPS je ozbiljna opcija. Aplikacija za pregled imovine funkcionera po prirodi je upravo takva: ljudi pretražuju i čitaju javne podatke, a upisa je malo.

Ako aplikacija traži naglo horizontalno skaliranje, visoku geografsku dostupnost, složenu distribuciju ili nema ko da održava server, prednosti managed infrastrukture lako nadmaše razliku u ceni.

Moj prelazak na VPS bio je odgovor na konkretan trošak i konkretnu aplikaciju, ne univerzalna preporuka da svi napuste Vercel ili Neon.

Optimizacija: kako sprečiti milione nepotrebnih operacija

Keširanje, statičko generisanje i pametniji API pozivi smanjuju opterećenje origina. Ilustracija; procenti na ekranu su dekorativni.
Keširanje, statičko generisanje i pametniji API pozivi smanjuju opterećenje origina. Ilustracija; procenti na ekranu su dekorativni.

Najveće uštede često ne nastaju promenom provajdera, nego promenom načina na koji aplikacija obrađuje zahteve. Ako neefikasnu aplikaciju preselite sa jedne platforme na drugu, dobićete istu neefikasnost na drugom serveru. Zato optimizacija ide sloj po sloj.

1. Prvi sloj: browser keš

Fajlovi čiji se naziv menja zajedno sa sadržajem, kao hashirani JavaScript i CSS, mogu se keširati dugo, i browser ih pri sledećoj poseti uopšte ne traži. Agresivan keš za fajlove koji se menjaju bez promene URL-a, međutim, korisnicima servira zastarele verzije. Razlikujte nepromenljive (immutable) resurse od podataka koji se ažuriraju.

2. Drugi sloj: CDN keš

CDN servira odgovor iz najbližeg čvora, bez odlaska do origina. Korisno je pratiti statuse odgovora, koji se razlikuju po provajderu, ali su obično ovakvi:

  • HIT: odgovor je pronađen u kešu,
  • MISS: nije bio u kešu i otišao je do origina,
  • BYPASS: pravila nalažu da se keš zaobiđe,
  • EXPIRED / REVALIDATED: sadržaj je istekao ili je proveren sa originom.

Ne gledajte samo ukupan procenat pogodaka. Pratite ga posebno za HTML, statičke resurse i API odgovore. Visok procenat za male ikonice ne znači ništa ako svaki glavni API poziv i dalje izvršava nekoliko skupih upita.

Cloudflare ima i jedan koristan mehanizam za viralne situacije: cache lock. Kada mnogo zahteva za isti nekeširan resurs istovremeno stigne u jedan data centar, samo prvi ide do origina, a ostali čekaju i dobijaju isti odgovor. To sprečava da talas posetilaca istovremeno udari u origin za isti fajl.

3. Treći sloj: Next.js keširanje i renderovanje

Za svaku vrstu sadržaja treba svesno izabrati način renderovanja:

  • Statički sadržaj (članci, dokumentacija, retko menjani podaci) ne treba da se generiše za svakog posetioca.
  • Dinamički sadržaj vezan za sesiju, nalog ili autorizaciju zahteva jasnu politiku svežine i privatnosti.
  • ISR i keširane komponente isporučuju sadržaj iz keša i osvežavaju ga po potrebi, bez stalnog ponovnog renderovanja.

U Next.js 16 se ovo radi kroz model Cache Components. Nove aplikacije napravljene sa create-next-app ga već imaju, a u postojećoj se uključuje u konfiguraciji:

ts
// next.config.ts
import type { NextConfig } from 'next';

const nextConfig: NextConfig = {
  cacheComponents: true,
  partialPrefetching: true,
};

export default nextConfig;

Dokumentacija traži da se partialPrefetching navede izričito, jer bez njega Next.js ispisuje upozorenje.

Za javne podatke koje je bezbedno keširati pravi se keširana funkcija sa jasnim životnim vekom i tagom:

ts
// app/lib/public-statistics.ts
import { cacheLife, cacheTag } from 'next/cache';
import { db } from '@/lib/db';

export async function getPublicStatistics() {
  'use cache';

  cacheLife({
    stale: 300, // klijent 5 minuta koristi keš bez provere
    revalidate: 900, // posle 15 minuta sledeći zahtev osvežava u pozadini
    expire: 3600, // posle sat vremena bez zahteva čeka se svež sadržaj
  });

  cacheTag('public-statistics');

  return db.statistics.getPublicSummary();
}

db.statistics.getPublicSummary() je primer funkcije koju pišete sami, nije ugrađena metoda. Next.js dokumentacija preporučuje da se cacheLife postavi u svakom use cache opsegu, kako ponašanje ne bi zavisilo od podrazumevanog profila. Uz to, expire mora biti duže od revalidate, inače Next.js prijavljuje grešku.

Kada se izvorni podaci promene, pouzdan server-side deo sistema poništava tag:

ts
import { revalidateTag } from 'next/cache';

// Posle potvrđene promene javnih podataka
revalidateTag('public-statistics', 'max');

Profil max koristi stale-while-revalidate: sledeći zahtev dobija postojeći sadržaj dok se novi priprema u pozadini, pa korisnik nikada ne čeka. To nije garancija da će svaki naredni čitalac odmah videti najnovije podatke. Oblik sa jednim argumentom, revalidateTag(tag), zastareo je u Next.js 16 i treba ga zameniti. Za administrativne akcije u kojima autor mora odmah da vidi svoju izmenu, u Server Actions postoji updateTag.

Ovakav poziv nikada ne treba izložiti javnoj API ruti bez autentifikacije. Svako ko može da ga pozove, može i da vam iznova prazni keš.

Napomena za self-hosting: keš iz ovih primera automatski radi za jednu next start instancu sa trajnim diskom. Ako pokrećete više instanci, ili kontejnere bez trajnog diska, Next.js dokumentacija traži posebnu koordinaciju keša i invalidacije, na primer kroz cacheHandler sa Redisom. Bez toga, svaka instanca ima svoj keš i svoje poništavanje.

4. Četvrti sloj: duplirani API pozivi

Jedan od najčešćih i najskupljih problema u React aplikacijama je nepotrebno ponavljanje zahteva. Uzroci su obično isti:

  • polling koji radi prečesto,
  • više komponenti koje nezavisno traže iste podatke,
  • nedostatak deduplikacije zahteva,
  • pogrešne zavisnosti u useEffect,
  • automatsko ponavljanje neuspelih poziva bez ograničenja,
  • agresivno osvežavanje pri fokusu prozora,
  • pozivi koji rade i kada je kartica u pozadini.

Računica je surova. Stranica koja svake tri sekunde osvežava podatke za jednog korisnika tokom pet minuta napravi oko 100 zahteva. Hiljadu korisnika sa otvorenom takvom stranicom napravi oko 100.000 zahteva za pet minuta, iako se podaci možda nisu ni promenili.

Bolje je koristiti duži interval, uslovno osvežavanje, HTTP revalidaciju preko ETag zaglavlja ili događaje. WebSocket i Server-Sent Events nisu automatski jeftiniji: i oni drže konekcije i memoriju. Birajte ih po stvarnom ponašanju aplikacije.

5. Peti sloj: PostgreSQL optimizacija

Kada baza postane usko grlo, kreće se od stvarnih upita. Najvažnije nije koji je upit najsporiji, nego koji troši najviše ukupnog vremena. Upit od 300 ms koji se izvrši milion puta skuplji je od upita od dve sekunde koji se pokrene deset puta dnevno.

Pratite broj poziva upita, prosečno i maksimalno trajanje, broj skeniranih i vraćenih redova, efikasnost indeksa, otvorene konekcije, zaključavanja i veličinu tabela.

Plan izvršavanja se proverava ovako:

sql
EXPLAIN (ANALYZE, BUFFERS)
SELECT id, ime, funkcija, azurirano
FROM javni_profili
WHERE status = 'objavljen'
ORDER BY azurirano DESC
LIMIT 30;

Tabela i kolone su primer. Važno: EXPLAIN ANALYZE zaista izvršava upit. Pokretanje teške analize nad produkcijom pod opterećenjem može dodatno pogoršati stvari, pa se radi na testnoj kopiji ili u kontrolisanim uslovima.

Ako analiza pokaže da obrazac pretrage nema odgovarajući indeks:

sql
CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_profili_status_azurirano
ON javni_profili (status, azurirano DESC);

Indeks se uvodi tek posle analize. Svaki indeks zauzima prostor i usporava upise, a i CONCURRENTLY troši resurse i može trajati dugo.

Agregacije. Posebno opasni su dashboardi i naslovne stranice koje pri svakom otvaranju pokreću COUNT, SUM, GROUP BY ili složene JOIN operacije nad velikim tabelama. Za podatke kojima nije potrebna trenutna tačnost postoje unapred pripremljeni agregati, materijalizovani pogledi sa periodičnim osvežavanjem, aplikacioni keš ili keširanje gotovih javnih API odgovora. Svaki od njih traži jasnu politiku osvežavanja.

6. Zašto je ova optimizacija finansijski presudna

Uzmimo 1.200.000 API zahteva iz ranijeg primera:

text
10% keša:  1.200.000 × 0,90 = 1.080.000 zahteva stiže do origina
90% keša:  1.200.000 × 0,10 =   120.000 zahteva stiže do origina

Devet puta manje zahteva do funkcija i baze. To nije nužno devet puta manji račun, jer CDN zahtevi i prenos ostaju, ali u opterećenju aplikacije i baze razlika je ogromna.

Botovi, WAF i zaštita od finansijski skupog saobraćaja

Rate limiting, WAF pravila i filtriranje botova tokom viralnog rasta. Ilustracija; brojke na ekranu su dekorativne.
Rate limiting, WAF pravila i filtriranje botova tokom viralnog rasta. Ilustracija; brojke na ekranu su dekorativne.

1. Velika poseta nije automatski legitimna poseta

Kada aplikacija postane popularna, ne dolaze samo ljudi. Dolaze pretraživački crawleri, AI crawleri, servisi za pregled linkova u društvenim mrežama i porukama, alati za arhiviranje, scraperi i zlonamerni botovi. Nisu svi isti rizik. Crawler koji indeksira sadržaj koristan je. Bot koji neprekidno poziva skup API endpoint može da napravi račun i bez klasičnog napada.

Za aplikaciju sa javnim podacima, kao što je pregled imovine funkcionera, ovo je posebno važno: takvi podaci prirodno privlače scrapere.

2. Rate limiting

Rate limiting ograničava koliko puta isti izvor sme da pogodi rutu u zadatom vremenu. Vercel WAF Rate Limiting dostupan je na svim planovima, sa fiksnim prozorom koji je podrazumevano 60 sekundi i 100 zahteva. Dve zvanične napomene su važne:

  • brojači se vode po regionu, pa saobraćaj iz više regiona može ukupno preći limit podešen za jedan region,
  • dozvoljeni zahtevi kroz rate limit pravilo se naplaćuju, u Frankfurtu $0,65 po milionu.

Ograničenje po IP adresi nije savršeno. Mnogo legitimnih korisnika deli jednu javnu adresu iza mobilnog operatera, firme ili CGNAT-a, pa agresivno pravilo blokira stvarne ljude. Veliki botnet, sa druge strane, koristi hiljade adresa. Zato se kombinuju signali: putanja, metoda, zaglavlja, identitet korisnika kada postoji i kvote po nalogu.

Kod Cloudflarea, skup polja po kojima se broji, dužine perioda i dostupne akcije zavise od plana, od Free do Enterprise sa naprednim rate limitingom. Cloudflare i sam upozorava da rate limit nad verifikovanim botovima može da utiče na SEO.

3. WAF i zaštita platforme

Vercel ima dva sloja: platformski firewall sa automatskom DDoS zaštitom, besplatan za sve, bez podešavanja, i WAF za sopstvena pravila. Cloudflare nudi WAF, upravljana pravila i bot zaštitu. Pravila uvodite postepeno, uz praćenje legitimnog saobraćaja, da korisnici ne bi ostali bez pristupa.

4. Zaštita najskupljih ruta

Sve rute ne zaslužuju istu zaštitu. Napravite pregled po trošku i riziku:

Vrsta ruteRizikPreporučena mera
Statički sadržajVelik prenos podatakaCDN, kompresija, browser keš
Javni API za listeOgroman broj pozivaKeš, paginacija, rate limit
PretragaSkupi upitiOgraničenja, indeksi, validacija ulaza
Izveštaji i agregacijeCPU i bazaUnapred izračunati rezultati, kontrola učestalosti
PrijavaAutomatizovani pokušajiRate limit, bezbednosna kontrola
Izvoz podatakaVeliki odgovoriKvote, asinhrona obrada, autorizacija
AdministracijaNeovlašćen pristupStroga autentifikacija i dozvole

Za javne API-je obavezno ograničite veličinu odgovora, dubinu paginacije, dozvoljene filtere i maksimalno vreme izvršavanja. Ako endpoint prima parametar limit, aplikacija ne sme da dozvoli da klijent zatraži neograničen broj redova.

5. Zašto robots.txt nije zaštita

robots.txt je signal za crawlere koji poštuju pravila. Nije autentifikacija i ne zaustavlja bota koji ne želi da ga poštuje. Skupa ili osetljiva ruta traži stvarnu kontrolu pristupa, keš, kvote i zaštitu na odgovarajućem sloju.

6. Zaštita ne sme da postane novi problem

Preterana zaštita blokira legitimne korisnike, kvari prijavljivanje, zasipa ljude CAPTCHA proverama, prekida indeksiranje javnog sadržaja i može doneti sopstvene troškove. Merite koliko saobraćaja se filtrira, koje rute su pogođene i da li stvarno opada broj zahteva prema originu. Mera se ocenjuje po rezultatu, ne po broju blokiranih zahteva.

Finansijski monitoring: kako da vas račun ne iznenadi

Ovo poglavlje smatram najvažnijim, upravo zbog sopstvenog iskustva. Dok sam rešavao privatne obaveze, sistem je nastavio da radi, a obaveštenja su mi tek kasnije pokazala koliko je brzo potrošnja porasla. Finansijski monitoring mora biti jednako važan kao tehnički.

1. Vercel Spend Management: šta zaista radi

Spend Management je dostupan na Pro planu i na Enterprise planu sa Flexible Commitment ugovorom, bez dodatne naknade. Upravljaju njime uloge Owner i Billing. Postavlja se On-Demand Budget za obračunski period, a pri njegovom dostizanju mogu se pokrenuti tri akcije: obaveštenja, poziv webhook-a i pauziranje produkcionih deploymenta svih projekata u timu.

Ono što je ključno, a što mnogi ne znaju:

  1. Budžet sam po sebi ne zaustavlja potrošnju. Da bi se troškovi zaista zaustavili, mora se posebno uključiti opcija Pause Production Deployments.
  2. Provera nije trenutna. Vercel proverava potrošnju na svakih nekoliko minuta, pa se obaveštenja, webhook i pauziranje mogu aktivirati nekoliko minuta posle prelaska praga. Zvanična preporuka je da se budžet postavi ispod iznosa koji ste zaista spremni da potrošite.
  3. Budžet ne pokriva sve. Na Pro planu obuhvata potrošnju preko mesečnog kredita, za sve projekte u timu. Ne obuhvata seatove, integracije sa Marketplace-a i posebne dodatke. Ako ste Neon povezali kao Vercel Marketplace integraciju, njegova potrošnja nije u ovom budžetu.
  4. Pauziranje znači nedostupan sajt. Pauzirani produkcioni deployment ne služi saobraćaj: sajt, API i funkcije vraćaju grešku 503 DEPLOYMENT_PAUSED. Svaki projekat se ponovo pokreće ručno, iz dashboarda ili preko REST API-ja, i neće se sam pokrenuti ni kada povećate budžet.
  5. Pauziranje ne gasi sve troškove. Ne zaustavlja AI Gateway i v0 potrošnju, a skladište (deployment storage, Blob, registry) se i dalje naplaćuje.

Obaveštenja na webu i mejlom stižu pri 50%, 75% i 100% budžeta, a SMS je moguće uključiti za prag od 100%. Svaki član sa Owner ili Billing ulogom podešava sopstvena obaveštenja, pa proverite da su zaista uključena na kanalima koje gledate i kada niste za računarom.

2. Budžet iz komandne linije

Vercel CLI od verzije vercel@59.23.0 ima komandu vercel budgets, koja upravlja istim budžetom kao dashboard. To znači da budžetom mogu upravljati i skripte i AI agenti, ne samo ljudi.

Pregled trenutne potrošnje i budžeta:

bash
vercel budgets

Budžet od 200 USD koji pri dostizanju pauzira produkciju i poziva webhook:

bash
vercel budgets set --amount 200 --pause --webhook https://primer.rs/potrosnja

CLI pri tome izričito upozorava da će svi projekti biti pauzirani pri 100% i da produkcioni deploymenti postaju nedostupni. Istorija upozorenja, od verzije vercel@65.2.0:

bash
vercel budgets alerts

Uklanjanje budžeta bez potvrde, korisno u automatizaciji:

bash
vercel budgets remove --yes

Budžet se odnosi na ceo tim, ne na jedan projekat. Ako u istom timu držite kritičnu poslovnu aplikaciju i eksperiment, opcija za pauziranje gasi obe. Za takve slučajeve je bolje razdvojiti projekte u različite timove.

3. Neon: obaveštenja, a ne kočnica

Neon na Launch i Scale planu ima Spending notifications. Administrator organizacije u Billing delu konzole postavi mesečni prag u dolarima, a Neon šalje mejl administratorima pri 80% i 100% praga. Potrošnja se proverava na svakih 15 minuta, a podsetnici stižu nedeljno dok ne podignete prag ili ne počne novi obračunski period.

Najvažnija rečenica iz zvanične dokumentacije: obaveštenja samo šalju upozorenja, ne zaustavljaju korišćenje. Kada se prag dostigne, projekti nastavljaju da rade i troškovi nastavljaju da rastu. Automatsko suspendovanje je najavljeno kao funkcionalnost koja tek dolazi.

Ako vam je potrebna stvarna kočnica, Neon nudi kvote potrošnje po projektu preko Management API-ja. One rade po projektu i po metrici (compute, storage, prenos podataka), a ne na ukupnom iznosu u dolarima, i mogu da suspenduju compute kada se kvota dostigne. Za produkcionu aplikaciju sa javnom posetom ovo je zaštita koju bih postavio prvu.

4. Najveći propust: svaki servis posmatran odvojeno

U mom slučaju dva servisa su istovremeno stigla do po 50 USD. Ako gledate samo Vercel, deluje da je sve pod kontrolom. Ako gledate samo Neon, isto. Ali infrastruktura košta zbir svih servisa: hosting, baza, storage, email, AI API, pretraga, monitoring, zaštita. Potreban je jedinstven pogled na ukupnu potrošnju.

5. Operativni model sa nivoima upozorenja

Za ozbiljniji projekat definisao bih nivoe prema stvarnom budžetu:

NivoŠta značiŠta se radi
InformativniPotrošnja je primetno poraslaPogledati trend, bez intervencije
ProveraRast nije objašnjen normalnim saobraćajemPronaći servise, rute i zahteve koji rastu
KritičanTrošak raste brže od planaOgraničiti skupe funkcije, uključiti zaštitu, zaustaviti poslove
Poslednja linijaNastavak je skuplji od prekidaAutomatski zaustaviti skupi deo ili ceo servis

Odluka ne sme da zavisi samo od iznosa. Mora da uzme u obzir i štetu od nedostupnosti. Za hobi projekat pauziranje je razumna poslednja linija. Za kritičan servis, prekid može biti skuplji od nastavka potrošnje.

6. Šta kada niste prisutni

Ovo sam najjače osetio. Ako aplikacija može da napravi ozbiljan račun dok ste 12 sati odsutni, obaveštenje koje vidite tek kada sednete za računar nije zaštita.

Za projekte sa finansijskim rizikom planirajte:

  • mobilna upozorenja na kanalu koji zaista gledate (SMS na Vercelu za 100%, push iz monitoringa),
  • nezavisan monitoring, koji ne zavisi od iste infrastrukture čiji problem treba da otkrije,
  • unapred definisane akcije: šta se gasi, šta se ograničava, ko odlučuje,
  • bezbedan webhook prijemnik ako automatizujete reakciju: provera autentičnosti poziva, zaštita od neovlašćenog aktiviranja i zapis o svakoj izvršenoj akciji,
  • kratku proceduru: ko reaguje, šta prvo proverava, koje funkcije sme privremeno da ugasi i kako potvrđuje da je problem rešen.

Praktičan model: 10.000, 100.000 i milion poseta

1. Zašto se ne može tvrditi koliko „košta 100.000 poseta”

Jedan sajt podnosi 100.000 poseta za nekoliko dolara jer se skoro sve isporučuje statički. Drugi za istu posetu troši višestruko više jer svaki korisnik pokreće složene upite, generisanje izveštaja, obradu slika ili AI pozive. Zato pravimo transparentan model sa poznatim pretpostavkama. Ovo nisu rezultati produkcionog testa, nego matematički scenariji.

2. Pretpostavke

  • dva API poziva po prikazu stranice,
  • 90% API poziva rešava se iz keša,
  • 0,7 MB stvarno prenetih podataka po prikazu,
  • tri prikaza po poseti u manjem scenariju, šest u većim.

3. Tri scenarija

Metrika10.000 poseta100.000 poseta1.000.000 poseta
Prikazi stranica30.000600.0006.000.000
API zahtevi60.0001.200.00012.000.000
Zahtevi do origina uz 90% keša6.000120.0001.200.000
Stvarni prenos21 GB420 GB4.200 GB

Pojedinačni zahtevi za slike, CSS, fontove i JavaScript ovde nisu uključeni, jer njihovo ponavljanje zavisi od browser i CDN keša. Nije uključen ni CPU, memorija ni baza.

4. Šta 420 GB može da znači na Vercelu

Ako bismo, samo radi ilustracije, primenili stopu za Frankfurt od 0,15 USD po GB:

text
420 GB × $0,15 = $63

Po najskupljoj regionalnoj stopi od 0,35 USD bilo bi 147 USD. Ali ovo nije procena računa. Pro kredit, obračunski period, region, Flat Rate CDN i druge kategorije mogu potpuno da promene iznos. Račun se ne računa množenjem ukupnog saobraćaja javnom jediničnom cenom.

5. Formula za Neon

text
Compute = Σ (CU × aktivni sati × $0,106)

Ako se veličina compute-a menja tokom dana, svaki interval se računa posebno. Primer sa stalnih 2 CU tokom 100 sati i 5 GB skladišta tokom celog meseca:

text
2 × 100 × $0,106 = $21,20  (compute)
5 × $0,35        =  $1,75  (storage)
Ukupno           = $22,95  pre drugih kategorija

6. Zašto pik nije isto što i ukupan dnevni saobraćaj

Pretpostavimo da sistem u proseku obrađuje 10 zahteva u sekundi, a tokom viralnog pika dobije 300. Po Littleovom zakonu, u stabilnom sistemu je broj operacija koje su istovremeno u obradi približno brzina dolaska puta prosečno trajanje:

text
300 zahteva/s × 0,2 s = oko 60 istovremenih operacija

Ako se pod zagušenjem trajanje produži na dve sekunde, isti dolazak daje oko 600 operacija u obradi ili na čekanju. Zato su p95 i p99 latencija važnije od proseka, a usporavanje baze može da izazove lavinu: duža obrada drži više instanci aktivnim, a više aktivnih instanci znači više naplaćene memorije.

7. Interaktivni kalkulator

Ispod je model koji računa iste veličine za vaše pretpostavke, po zvaničnim stopama za Vercel Frankfurt i Neon Launch. Isprobajte gotove scenarije, pa menjajte vrednosti.

Interaktivni model · tutorijali.app

Kalkulator: koliko posla i novca pravi viralni dan

Menjajte pretpostavke i pratite kako se broj poseta pretvara u zahteve, pozive funkcija, prenos podataka i rad baze. Cene su javne on-demand stope za Vercel Frankfurt (fra1) i Neon Launch, proverene 2. novembra 2026.

01 / saobraćajKo dolazi i koliko otvara
U mom slučaju oko 100.000 za približno 24 sata.
600.000 prikaza / 100.000 poseta daje oko 6.
HTML, JS, CSS, slike, fontovi. I keširani zahtev je CDN zahtev.
Stvarno preneti bajtovi posle kompresije i browser keša.
02 / backendŠta stiže do funkcija
Pozivi koji mogu da pokrenu funkciju i bazu.
Udeo poziva koji se služi iz keša, bez funkcije.
Samo vreme kada kod zaista radi, bez čekanja baze.
Uključuje čekanje na bazu i spoljne API-je.
Proverite podešavanje projekta. Model ne računa deljenje instance.
03 / baza i serverNeon i alternativa
1 CU je oko 4 GB RAM-a, uz CPU i lokalni SSD.
Baza troši samo dok radi; scale to zero posle 5 minuta.
Prosečna veličina baze tokom meseca.
Vaša ponuda, sa backupom i prenosom. Rad nije uključen.
600.000prikaza stranica
12.000.000CDN zahteva
1.200.000API poziva pre keša
480.000poziva koji stižu do funkcija
420 GBprocenjeni prenos

Vercel, bruto po stopama za fra1

CDN zahtevi12.000.000 × $2,60 / 1M$31
Fast Data Transfer420 GB × $0,15$63
Pozivi funkcija480.000 × $0,60 / 1M$0.29
Active CPU$0,184 po satu$0.98
Provisioned Memory$0,0152 po GB-h, gornja granica$1.42
Ukupno pre kredita$97

Neon Launch

Compute24 CU-h × $0,106$2.54
Skladište5 GB × $0,35 mesečno$1.75
Ukupno$4.29

Javni prenos iz Neona uključen je do 500 GB po projektu mesečno, zatim $0,10 po GB. Istorija za vraćanje, grane i drugi servisi nisu u modelu.

Poređenje u istoj jedinici

Vercel + Neon za uneti period$101
VPS za ceo mesec$25

Pažnja: levo je trošak samo za uneti period saobraćaja, desno cena servera za ceo mesec. VPS ima granicu kapaciteta i ne skalira sam; upoređujte ga sa svojim stvarnim pikom, ne samo sa računom.

Kako čitati rezultate:

  1. Prvo menjajte keš pogodak i gledajte koliko pada broj poziva koji stižu do funkcija.
  2. Zatim smanjite prenos po prikazu. Na milionima prikaza i desetine kilobajta po stranici prave razliku.
  3. Na kraju menjajte veličinu i sate Neon compute-a. Videćete da su vreme rada i veličina compute-a važniji od broja upita.

Model namerno ne prikazuje lažno precizan konačan račun. Za to nisu dovoljni broj poseta i nekoliko proseka.

Prelazak na VPS: kompletan tehnički postupak

Prelazak sa managed okruženja na VPS sa reverse proxyjem i monitoringom. Ilustracija; cene i procenti na ekranu nisu podaci projekta.
Prelazak sa managed okruženja na VPS sa reverse proxyjem i monitoringom. Ilustracija; cene i procenti na ekranu nisu podaci projekta.

1. Prvo utvrdite da li se selidba isplati

Migracija nije automatski pravi odgovor na prvi veći račun. Uporedite najmanje tri opcije:

  1. optimizaciju na postojećoj platformi (keš, statičke stranice, Flat Rate CDN, granice autoscalinga),
  2. delimičnu migraciju, na primer samo baze ili samo backenda,
  3. potpunu migraciju na VPS.

Pri poređenju računajte ukupan trošak vlasništva: server, dodatne diskove, backup i snapshot-e, prenos preko uključenog limita, monitoring, zaštitu, domen i, najvažnije, vreme za administraciju i oporavak. VPS koji je jeftiniji na računu, a traži nekoliko sati vašeg rada nedeljno, možda nije jeftiniji. Za mnoge manje i srednje javne aplikacije, ipak, samostalno održavan VPS ostaje odličan odnos cene i resursa.

2. Popis postojeće infrastrukture

Pre migracije zapišite:

  • runtime i tačnu verziju Node.js-a i Next.js-a,
  • tačnu glavnu verziju PostgreSQL-a i sve potrebne ekstenzije,
  • sve promenljive okruženja,
  • background poslove i cron zadatke,
  • lokacije upload-a i storage-a,
  • webhook adrese, DNS zapise, podešavanja autentifikacije,
  • email i druge spoljne integracije,
  • postojeće backup i restore postupke,
  • funkcionalnosti vezane za platformu (Vercel cron, Image Optimization, Edge Config, analitika), koje na VPS-u treba zameniti.

Posebno pazite na podatke koji nisu u samoj bazi. Baza može imati reference na fajlove koji su u drugom storage-u; prenos SQL podataka neće preneti i te fajlove.

3. Izbor kapaciteta

Server se ne bira po broju poseta, nego po merenjima: maksimalnom CPU opterećenju, memoriji aplikacije i baze, broju istovremenih konekcija, disk I/O zahtevima, veličini baze i radnog skupa podataka, mrežnom saobraćaju i rezervi za backup i deployment. VPS sa nekoliko vCPU jezgara i više gigabajta RAM-a dobra je polazna tačka za jednostavnu javnu aplikaciju, ali nije garancija da će podneti 100.000 poseta. Kapacitet se potvrđuje testom. Izaberite region sa dobrom latencijom za vaše korisnike.

4. Osnovna zaštita servera

Na svežoj Ubuntu Server instalaciji prvo ažurirajte sistem:

bash
sudo apt update
sudo apt upgrade

Zatim podesite administratorski nalog, pristup preko SSH ključeva i firewall. Sa UFW-om, pre uključivanja proverite da je SSH dozvoljen:

bash
sudo ufw allow OpenSSH
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable
sudo ufw status verbose

Na udaljenom serveru pogrešno pravilo vas može potpuno zaključati, pa držite otvorenu postojeću sesiju i proverite da provajder ima rezervnu konzolu. PostgreSQL port 5432 ne otvarajte prema internetu. Ako aplikacija i baza rade na istom serveru, javno izlaganje baze nije potrebno.

5. Next.js za self-hosting: standalone

Next.js zvanično podržava pokretanje na sopstvenom Node.js serveru, a za Docker je najpraktičniji standalone izlaz:

ts
// next.config.ts
import type { NextConfig } from 'next';

const nextConfig: NextConfig = {
  output: 'standalone',
};

export default nextConfig;

Build pravi .next/standalone sa minimalnim server.js. Dve stvari iz dokumentacije koje se lako previde: server.js ne kopira fasciklu public ni .next/static (namenjene su CDN-u), pa ih treba ručno kopirati, a port i adresa se zadaju promenljivama PORT i HOSTNAME. Next.js preporučuje i da se ispred servera stavi reverse proxy, koji preuzima neispravne zahteve, spore konekcije, ograničenje veličine zahteva i rate limiting.

6. Produkcioni Docker image

Primer za npm i Node.js 24 LTS. Pre primene proverite kompatibilnost sa projektom:

dockerfile
FROM node:24-bookworm-slim AS deps
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci

FROM node:24-bookworm-slim AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN npm run build

FROM node:24-bookworm-slim AS runner
WORKDIR /app
ENV NODE_ENV=production
ENV PORT=3000
ENV HOSTNAME=0.0.0.0

COPY --from=builder /app/public ./public
COPY --from=builder /app/.next/standalone ./
COPY --from=builder /app/.next/static ./.next/static

USER node
EXPOSE 3000
CMD ["node", "server.js"]

Primer pretpostavlja da projekat ima fasciklu public i package-lock.json. Dodajte .dockerignore, da u build ne uđu lokalni node_modules, tajne i nepotrebni fajlovi. U ozbiljnijem okruženju fiksirajte verzije osnovnih image-a i skenirajte ih.

7. Docker Compose: PostgreSQL, aplikacija i Caddy

yaml
services:
  db:
    image: postgres:17
    restart: unless-stopped
    environment:
      POSTGRES_DB: appdb
      POSTGRES_USER: app
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?required}
    volumes:
      - postgres_data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U app -d appdb"]
      interval: 10s
      timeout: 5s
      retries: 5
    networks:
      - backend

  app:
    build: .
    restart: unless-stopped
    environment:
      NODE_ENV: production
      DATABASE_URL: ${DATABASE_URL:?required}
    depends_on:
      db:
        condition: service_healthy
    networks:
      - backend
      - frontend

  caddy:
    image: caddy:2
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile:ro
      - caddy_data:/data
      - caddy_config:/config
    depends_on:
      - app
    networks:
      - frontend

networks:
  frontend:
  backend:

volumes:
  postgres_data:
  caddy_data:
  caddy_config:

Nekoliko odluka u ovoj konfiguraciji je namerno:

  • PostgreSQL nema sekciju ports, pa se ne objavljuje na javnom portu servera.
  • Dve mreže: Caddy je samo u frontend mreži i nema pristup bazi, aplikacija je u obe.
  • Verzija baze (postgres:17) treba da odgovara glavnoj verziji koju koristite na Neonu, da bi pg_restore prošao bez iznenađenja.
  • Tajne su u .env fajlu koji nije u repozitorijumu. Ako lozinka u DATABASE_URL ima posebne karaktere, mora biti URL-kodirana.

8. Caddy i automatski HTTPS

Caddy automatski pribavlja i obnavlja HTTPS sertifikate kada domen pokazuje na server, a portovi 80 i 443 su dostupni:

caddyfile
primer.rs {
    encode zstd gzip
    reverse_proxy app:3000
}

Za postojeći produkcioni domen preporučljivo je novu infrastrukturu prvo testirati na posebnom poddomenu. Caddy pojednostavljuje TLS, ali ne zamenjuje ostatak zaštite: zaglavlja, ograničenje veličine zahteva, monitoring i pravilno rukovanje prosleđenim IP adresama, posebno ako je ispred Cloudflare.

9. Migracija baze sa Neona

Ovo je najosetljiviji deo procesa. Pre početka proverite kompatibilnost verzija, ekstenzije, kodiranje i collation, uloge i dozvole, sekvence, strane ključeve, procedure i trigere, kao i veličinu podataka.

Izvoz. pg_dump pravi konzistentan snimak baze i dok je drugi koriste. Za izvoz sa Neona koristite direktnu konekciju, ne pooled, i klijentske alate iste ili novije glavne verzije:

bash
pg_dump "$NEON_DIRECT_URL" -F c -O -x -f baza.dump

Opcije su: -F c za prilagođeni format, -O bez vlasnika objekata i -x bez dozvola. Fajl sadrži sve podatke, pa ga čuvajte kao osetljiv.

Vraćanje u pripremljenu praznu bazu na VPS-u:

bash
pg_restore -d "$TARGET_DATABASE_URL" -O -x -e baza.dump

-e prekida vraćanje pri prvoj grešci, umesto da nastavi i ostavi polovičnu bazu. Uspeh se ne potvrđuje porukom da je komanda završena. Uporedite broj redova u ključnim tabelama, vrednosti sekvenci, kritične podatke i stvarne korisničke tokove.

10. Ključni problem: upisi tokom migracije

pg_dump hvata stanje u jednom trenutku. Sve što se upiše posle toga, u ciljnoj bazi ne postoji. Zato „dump, restore, promeni DNS” nije bezbedan plan za aplikaciju koja prima upise. Postoje dve strategije.

Strategija A: kratak, kontrolisan prekid upisa. Za manje aplikacije najjednostavnija i najbezbednija:

  1. pripremite i testirajte novu infrastrukturu,
  2. uradite probnu migraciju i izmerite koliko traje,
  3. po potrebi najavite kratku servisnu pauzu,
  4. zaustavite nove upise na staroj aplikaciji,
  5. sačekajte završetak aktivnih transakcija i poslova,
  6. napravite završni dump,
  7. vratite ga u ciljnu bazu,
  8. proverite integritet i kritične funkcije,
  9. prebacite upise na novu bazu,
  10. tek posle provere vratite normalan rad.

Aplikacija u kojoj se uglavnom čita, kao pregled javnih podataka, ovu strategiju podnosi lako, jer čitanje može da radi i dok su upisi privremeno zaustavljeni.

Strategija B: minimalan prekid. Veći sistemi koriste logičku replikaciju ili namenske alate: početna kopija, neprekidna sinhronizacija promena, praćenje zaostatka, koordinisan završni prelaz i provera konzistentnosti. Složenije je, sa ograničenjima oko DDL promena, sekvenci, ekstenzija i dozvola. Zato nije odgovorno obećavati migraciju „bez ijedne sekunde prekida” na osnovu generičke skripte. Kratak, unapred planiran prekid upisa često je sigurniji izbor.

11. Prelazak saobraćaja i plan povratka

Pri promeni DNS-a različiti resolveri i browseri neko vreme pamte stari odgovor. Smanjivanje TTL-a unapred pomaže, ali ne garantuje trenutno prebacivanje. Najvažnije pravilo: tokom prelaza stara i nova aplikacija ne smeju da primaju nezavisne upise u dve različite baze, jer se razilaženje podataka teško ispravlja.

Rollback nije samo vraćanje stare DNS adrese. Ako je nova aplikacija već prihvatila upise, povratak na staru bazu bez tih promena znači gubitak podataka. Plan mora da kaže od kog trenutka se prihvataju novi upisi, kako se oni vraćaju, koji su kriterijumi za prekid migracije i ko donosi odluku.

12. Backup posle migracije

Prelaskom sa managed baze na sopstveni PostgreSQL preuzimate i odgovornost za podatke. Docker volume nije backup, a snapshot diska nije zamena za proveren backup baze. Razlikujte:

  • backup: kopiju iz koje je moguć oporavak, čuvanu i van servera,
  • snapshot: snimak diska ili virtuelne mašine, koristan, ali ne i dovoljan,
  • point-in-time recovery: povratak na tačan trenutak, uz arhiviranje WAL zapisa.

Odredite RPO (koliko podataka smete da izgubite, izraženo u vremenu) i RTO (koliko dugo sistem sme da bude nedostupan tokom oporavka). Backup koji nikada niste vratili nije backup, nego nada.

13. CDN ispred VPS-a

Ako ispred VPS-a stavite Cloudflare, jasno definišite koje rute smeju u keš, koje ga uvek zaobilaze, kako se poništava javni sadržaj, kako se čuvaju sesije, da li origin prihvata direktne zahteve, kako se beleži stvarna IP adresa i koja su pravila rate limitinga. Pogrešno keširana privatna stranica nije problem performansi, nego bezbednosti.

Testiranje, monitoring i produkciona kontrolna lista

1. Vrste testova

  • Smoke test proverava da osnovne funkcije rade pod minimalnim opterećenjem.
  • Load test proverava očekivano i povećano opterećenje.
  • Stress test traži granicu sistema i način na koji se kvari.
  • Spike test simulira nagli skok, upravo ono što donosi viralnost.
  • Soak test otkriva probleme koji se javljaju tek posle dužeg rada, kao curenje memorije i gomilanje konekcija.

2. Primer k6 testa

javascript
import http from 'k6/http';
import { check, sleep } from 'k6';

export const options = {
  stages: [
    { duration: '30s', target: 10 },
    { duration: '1m', target: 10 },
    { duration: '30s', target: 0 },
  ],
  thresholds: {
    http_req_failed: ['rate<0.01'],
    http_req_duration: ['p(95)<1000'],
  },
};

export default function () {
  const res = http.get('https://staging.primer.rs/health');
  check(res, { 'HTTP 200': (r) => r.status === 200 });
  sleep(1);
}

Ovo je mali demonstracioni test, ne simulacija 100.000 korisnika. Uspeh na /health ne dokazuje da će ostale funkcije izdržati. Realan test modeluje najčešće korisničke tokove, stvarnu raspodelu čitanja i upisa i ponašanje baze. Pokrećite ga samo nad sistemima za koje imate ovlašćenje i imajte na umu da i sam test na managed platformi pravi trošak.

3. Šta pratiti posle prelaska na VPS

SlojMetrike
AplikacijaZahtevi u sekundi, p50/p95/p99, greške 4xx i 5xx, memorija Node.js procesa, zastoji event loop-a
SistemCPU i load, slobodan RAM, swap, disk IOPS i latencija, slobodan prostor, mrežni prenos, restartovanja kontejnera
PostgreSQLAktivne konekcije, najskuplji upiti, čekanja na zaključavanja, veličina baze, cache hit rate, checkpoint i WAL, uspeh backupa
BezbednostBlokirani zahtevi, neobični obrasci pristupa, pokušaji prijave, promene firewall-a, bezbednosna ažuriranja
FinansijeCena servera, dodatni prenos, backup i storage, spoljni API-ji, vreme utrošeno na administraciju

4. Produkciona kontrolna lista

Pre nego što aplikaciju ponovo izložite velikoj publici:

Aplikacija

  • Kritične korisničke funkcije su testirane.
  • Nema dupliranih i nepotrebnih API poziva.
  • Javni podaci se keširaju gde je bezbedno.
  • Privatni podaci ne mogu da završe u javnom kešu.
  • API ima ograničenja veličine, paginacije i vremena.
  • Najskuplji upiti su identifikovani.
  • Nema beskonačnih retry petlji.

Server

  • SSH je zaštićen ključevima.
  • Firewall dozvoljava samo neophodne portove.
  • Baza nije dostupna sa interneta.
  • Sistem i kontejneri se redovno ažuriraju.
  • TLS radi i obnavlja se automatski.
  • Logovi imaju rotaciju i ograničeno zadržavanje.

Baza

  • Verzija i ekstenzije su provereni.
  • Nema neograničenog rasta konekcija.
  • Backup je automatizovan i čuva se van servera.
  • Vraćanje podataka je stvarno testirano.
  • RPO i RTO su definisani.

Troškovi i monitoring

  • Postoje i tehnička i finansijska upozorenja.
  • Poznate su sve platforme koje naplaćuju resurse.
  • Kritična obaveštenja stižu i kada niste za računarom.
  • Na Vercelu je jasno da li je pauziranje uključeno i šta znači.
  • Na Neonu postoje kvote po projektu, a ne samo obaveštenja.
  • Postoji procedura za nagli rast saobraćaja i za preveliku potrošnju.

Viralni rast

  • Poznat je normalan saobraćaj i bar jedan izmeren pik.
  • Poznate su granice trenutne infrastrukture.
  • Najskuplje rute imaju posebnu zaštitu.
  • Legitiman saobraćaj nije nepotrebno blokiran.
  • Postoji plan za degradiran rad i osoba za hitnu intervenciju.

FAQ: često postavljana pitanja

Da li je 100.000 poseta mnogo?

Zavisi od aplikacije. Za statički sajt to je lako opterećenje. Za aplikaciju koja generiše dinamičke izveštaje ili intenzivno pristupa bazi, ozbiljan izazov. Presudni su broj i cena stvarnih operacija i njihov raspored u vremenu.

Da li je Vercel preskup za viralne projekte?

Nema univerzalnog odgovora. Dobro optimizovana aplikacija na Vercelu može biti vrlo ekonomična, a Flat Rate CDN uklanja rizik od skoka CDN stavki. Pojedini obrasci korišćenja, međutim, prave značajne troškove. Pogledajte obračunske metrike i uporedite ih sa alternativom.

Da li je Neon loš izbor za aplikaciju sa velikom posetom?

Nije. Neon ima osobine koje su odlične za razvoj i skaliranje PostgreSQL-a. Treba razumeti CU-hours, granice autoscalinga, scale to zero i ponašanje konekcija, i postaviti kvote po projektu. Managed baza može biti dobar izbor i kada aplikacija radi na VPS-u.

Da li VPS od 10 ili 20 USD može da izdrži 100.000 poseta?

Može, ali nije garantovano. Za dobro keširan javni sadržaj to je izvodljivo. Za zahtevnu aplikaciju sa mnogo upisa i složenih upita verovatno nije ni približno dovoljno. Jedini odgovoran odgovor daje merenje.

Da li je Cloudflare dovoljan da ukloni sav trošak?

Nije. Može značajno smanjiti određene vrste opterećenja, ali ne uklanja potrebu za izvršavanjem aplikacije i baze, a po podrazumevanim podešavanjima ne kešira HTML ni JSON. I neke njegove funkcije imaju sopstvene cene.

Da li upozorenje o budžetu predstavlja čvrst limit?

Ne nužno. Na Vercelu se pauziranje uključuje posebno i aktivira se sa zakašnjenjem od nekoliko minuta. Neonova obaveštenja samo šalju mejl i ne zaustavljaju potrošnju; za stvarno zaustavljanje služe kvote po projektu preko API-ja.

Da li automatsko pauziranje uvek ima smisla?

Ne. Za hobi projekat je razumno da se aplikacija privremeno zaustavi. Za kritičnu poslovnu aplikaciju prekid može biti mnogo skuplji od nastavka potrošnje. Pravila se prilagođavaju poslovnom riziku.

Da li Docker volume predstavlja backup?

Ne. Volume čuva podatke van životnog ciklusa kontejnera, ali nije nezavisna, proverena kopija. Kada otkaže disk ili se podaci oštete, volume ne pomaže.

Da li DNS promena garantuje migraciju bez prekida?

Ne. Keširanje DNS odgovora, aktivne konekcije i upisi tokom prelaza prave složenosti koje se ne vide iz same promene IP adrese. Kod baze je najvažnije obezbediti konzistentnost podataka.

Da li jeftiniji VPS znači i jeftiniju infrastrukturu?

Ne automatski. Treba uračunati backup, monitoring, održavanje, bezbednost, oporavak i sopstveno vreme. Za mnoge projekte razlika u ceni ipak opravdava dodatnu administraciju.

Zaključak: najskuplja stvar nije hosting, nego odsustvo kontrole

Aplikacija za pregled imovine javnih funkcionera za oko 24 sata privukla je približno 100.000 unikatnih posetilaca i 600.000 prikaza stranica. Dok zbog privatnih obaveza nisam bio prisutan, potrošnja je rasla. Posle oko 12 sati stigla su obaveštenja: 50 USD na Vercelu i još 50 USD na Neonu. Reagovao sam i prešao na jeftiniji VPS, primereniji ovoj konkretnoj aplikaciji.

Najvažniji zaključak, međutim, nije da je VPS bolji od Vercela ili Neona. Važnije je ovo:

  1. Broj poseta ne govori koliko je aplikacija zahtevna. Govore broj zahteva, poziva funkcija, upita i prenetih bajtova.
  2. Keš, optimizovan backend i dobri SQL upiti često vrede više od promene provajdera.
  3. Filtriranje nepotrebnog saobraćaja nije samo bezbednosno, nego i finansijsko pitanje.
  4. Troškovi se prate zbirno. Obaveštenje za jedan servis ne pokriva ostale.
  5. Budžet i obaveštenje nisu kočnica. Na Vercelu pauziranje mora biti uključeno, a na Neonu stvarnu zaštitu daju kvote po projektu.
  6. Planirajte trenutke kada niste prisutni. Aplikacija ne prestaje da prima korisnike zato što spavate, putujete ili ste zauzeti.
  7. Migracija ima smisla samo uz pripremu: zaštitu podataka, testiran backup, monitoring i realnu procenu kapaciteta.

Danas je lakše nego ikada napraviti aplikaciju i objaviti je. AI agenti i savremeni alati skratili su put od ideje do produkcije na nekoliko dana. Upravo zato je važnije nego ikada razumeti infrastrukturu koja će aplikaciju nositi kada je ljudi zaista otkriju.

Uspešna aplikacija nije ona koja radi sa deset korisnika, nego ona koja i pod neočekivanim opterećenjem ostaje upotrebljiva, bezbedna i finansijski održiva. Viralnost je odlična stvar. Tek dobra priprema čini da taj uspeh ne postane neplaniran trošak.

Metodologija i izvori

Cene i ponašanje servisa provereni su 2. novembra 2026. u zvaničnoj dokumentaciji. Cene se menjaju, pa pre odluke proverite aktuelne stranice. Finansijski primeri koji nisu iz mog iskustva su matematičke ilustracije, a ne obračuni ni rezultati produkcionih testova. Komande i konfiguracije su primeri koje treba prilagoditi sopstvenoj aplikaciji i proveriti na testnom okruženju pre produkcije.

Fotografije u članku su AI generisane konceptualne ilustracije. Ne prikazuju moj stvarni Vercel ili Neon nalog, a brojke na njihovim ekranima, kao procenti keša, cene servera ili procenat uštede, služe samo vizuelnoj predstavi teme.

Vercel

Neon

Next.js

Cloudflare, PostgreSQL, Caddy i k6