Moja aplikacija o imovini funkcionera dobila je 100.000 poseta za dan, a za 12 sati stiglo je 50 USD na Vercelu i 50 USD na Neonu. Detaljan vodič kroz cene, optimizaciju, budžete i prelazak na VPS, sa interaktivnim kalkulatorom.

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”:
- 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.
- 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.
- 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.
- 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či | Zašto je važna za račun |
|---|---|---|
| Unikatni posetilac | Browser ili uređaj koji analitika prepozna kao jednog posetioca | Govori koliko ljudi je došlo, ne koliko posla je urađeno |
| Poseta (sesija) | Jedan dolazak na sajt sa nizom radnji | Jedna osoba može imati više sesija |
| Prikaz stranice | Učitavanje ili prikaz stranice po pravilima analitike | Kod klijentske navigacije ne mora da znači novi HTML zahtev |
| HTTP zahtev | Pojedinačna komunikacija sa CDN-om ili serverom | Jedan prikaz može da izazove desetine zahteva za JS, CSS, slike i API |
| Poziv funkcije | Izvršavanje serverless ili backend koda | Ne izaziva ga svaki zahtev; keširan odgovor ne pokreće funkciju |
| Upit prema bazi | SQL operacija nad bazom | Jedan 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:
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 analitika | Posete, prikaze, izvore saobraćaja, raspodelu po satima |
| Vercel Usage | Koje obračunske stavke su porasle, po projektu i servisu |
| Vercel Observability | Najčešće rute i funkcije, trajanje, prenos, greške |
| Neon Billing i Monitoring | Compute (CU-hours), veličinu compute-a kroz vreme, storage, prenos |
| Aplikacioni i pristupni logovi | Najskuplje 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

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:
| Stavka | Frankfurt (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
fetchkeširanje iliunstable_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:
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:
| Stavka | Launch 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 prenos | 500 GB po projektu mesečno uključeno, zatim $0,10 po GB |
| Autoscaling | do 16 CU (64 GB RAM) |
| Scale to zero | posle 5 minuta neaktivnosti, može se isključiti |
Nekoliko proračuna da se osete razmere:
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:
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,
SETnaredbe koje treba da traju kroz sesiju i migracije šeme zahtevaju direktnu konekciju bez-poolersufiksa.
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
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
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
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
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
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
| Kriterijum | Vercel + Neon | Cloudflare + VPS | Dva VPS-a |
|---|---|---|---|
| Početna implementacija | Jednostavna | Srednje zahtevna | Zahtevnija |
| Operativno održavanje | Malo | Veće | Najveće |
| Elastičnost | Izražena | Ograničena resursima VPS-a | Zahteva planiranje |
| Predvidljivost osnovne cene | Zavisi od potrošnje | Visoka | Visoka |
| Administracija baze | Managed | Samostalna | Samostalna |
| Backup i oporavak | Delimično managed | Vaša odgovornost | Vaša odgovornost |
| Kontrola infrastrukture | Ograničenija | Visoka | Visoka |
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

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:
// 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:
// 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:
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 startinstancu 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 krozcacheHandlersa 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:
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:
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:
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

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 rute | Rizik | Preporučena mera |
|---|---|---|
| Statički sadržaj | Velik prenos podataka | CDN, kompresija, browser keš |
| Javni API za liste | Ogroman broj poziva | Keš, paginacija, rate limit |
| Pretraga | Skupi upiti | Ograničenja, indeksi, validacija ulaza |
| Izveštaji i agregacije | CPU i baza | Unapred izračunati rezultati, kontrola učestalosti |
| Prijava | Automatizovani pokušaji | Rate limit, bezbednosna kontrola |
| Izvoz podataka | Veliki odgovori | Kvote, asinhrona obrada, autorizacija |
| Administracija | Neovlašćen pristup | Stroga 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:
- 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.
- 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.
- 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.
- 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. - 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:
vercel budgets
Budžet od 200 USD koji pri dostizanju pauzira produkciju i poziva webhook:
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:
vercel budgets alerts
Uklanjanje budžeta bez potvrde, korisno u automatizaciji:
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 |
|---|---|---|
| Informativni | Potrošnja je primetno porasla | Pogledati trend, bez intervencije |
| Provera | Rast nije objašnjen normalnim saobraćajem | Pronaći servise, rute i zahteve koji rastu |
| Kritičan | Trošak raste brže od plana | Ograničiti skupe funkcije, uključiti zaštitu, zaustaviti poslove |
| Poslednja linija | Nastavak je skuplji od prekida | Automatski 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
| Metrika | 10.000 poseta | 100.000 poseta | 1.000.000 poseta |
|---|---|---|---|
| Prikazi stranica | 30.000 | 600.000 | 6.000.000 |
| API zahtevi | 60.000 | 1.200.000 | 12.000.000 |
| Zahtevi do origina uz 90% keša | 6.000 | 120.000 | 1.200.000 |
| Stvarni prenos | 21 GB | 420 GB | 4.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:
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
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:
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:
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.
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
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:
- Prvo menjajte keš pogodak i gledajte koliko pada broj poziva koji stižu do funkcija.
- Zatim smanjite prenos po prikazu. Na milionima prikaza i desetine kilobajta po stranici prave razliku.
- 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

1. Prvo utvrdite da li se selidba isplati
Migracija nije automatski pravi odgovor na prvi veći račun. Uporedite najmanje tri opcije:
- optimizaciju na postojećoj platformi (keš, statičke stranice, Flat Rate CDN, granice autoscalinga),
- delimičnu migraciju, na primer samo baze ili samo backenda,
- 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:
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:
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:
// 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:
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
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
frontendmreži i nema pristup bazi, aplikacija je u obe. - Verzija baze (
postgres:17) treba da odgovara glavnoj verziji koju koristite na Neonu, da bipg_restoreprošao bez iznenađenja. - Tajne su u
.envfajlu koji nije u repozitorijumu. Ako lozinka uDATABASE_URLima 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:
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:
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:
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:
- pripremite i testirajte novu infrastrukturu,
- uradite probnu migraciju i izmerite koliko traje,
- po potrebi najavite kratku servisnu pauzu,
- zaustavite nove upise na staroj aplikaciji,
- sačekajte završetak aktivnih transakcija i poslova,
- napravite završni dump,
- vratite ga u ciljnu bazu,
- proverite integritet i kritične funkcije,
- prebacite upise na novu bazu,
- 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
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
| Sloj | Metrike |
|---|---|
| Aplikacija | Zahtevi u sekundi, p50/p95/p99, greške 4xx i 5xx, memorija Node.js procesa, zastoji event loop-a |
| Sistem | CPU i load, slobodan RAM, swap, disk IOPS i latencija, slobodan prostor, mrežni prenos, restartovanja kontejnera |
| PostgreSQL | Aktivne konekcije, najskuplji upiti, čekanja na zaključavanja, veličina baze, cache hit rate, checkpoint i WAL, uspeh backupa |
| Bezbednost | Blokirani zahtevi, neobični obrasci pristupa, pokušaji prijave, promene firewall-a, bezbednosna ažuriranja |
| Finansije | Cena 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:
- Broj poseta ne govori koliko je aplikacija zahtevna. Govore broj zahteva, poziva funkcija, upita i prenetih bajtova.
- Keš, optimizovan backend i dobri SQL upiti često vrede više od promene provajdera.
- Filtriranje nepotrebnog saobraćaja nije samo bezbednosno, nego i finansijsko pitanje.
- Troškovi se prate zbirno. Obaveštenje za jedan servis ne pokriva ostale.
- 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.
- Planirajte trenutke kada niste prisutni. Aplikacija ne prestaje da prima korisnike zato što spavate, putujete ili ste zauzeti.
- 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
- Pricing: planovi, Pro kredit, podrazumevani budžet i Flat Rate CDN
- Regional Pricing i cene za Frankfurt (fra1)
- Fluid compute: naplata Active CPU, Provisioned Memory i poziva
- Spend Management
- CLI: vercel budgets
- Simplifying runtime caching on Vercel
- Vercel Firewall i WAF Rate Limiting
Neon
Next.js
Cloudflare, PostgreSQL, Caddy i k6
Podelite vaše utiske, pitanja ili savete u vezi sa ovim člankom.