Yazılar · Hostinger · Sunucu · Node.js
Hostinger'da bütün siteler aynı anda 503 veriyorsa: Max Processes tavanı ve kalıcı çözüm
Hostinger Cloud Startup planında hesap başına Max Processes 200'dür. Passenger altında çalışan her Next.js uygulaması, @next/swc Rust ikilisinin açtığı 64 tokio thread'iyle tek başına yaklaşık 75 process yer; dört uygulama tavanı doldurur ve PHP fork() edemez, statik siteler ayakta kalırken dinamik siteler 503 verir. Kalıcı çözüm Node'u iki çekirdeğe bağlayan bir sarmalayıcı: taskset -c 0,1 ile uygulama başına 75 → 11 thread, hesap toplamı 183 → 38.
Bir sabah hesabımdaki dinamik sitelerin tamamı aynı anda "server temporarily busy" demeye başladı. PHP siteleri, Node uygulamaları, hepsi. Statik siteler sapasağlamdı. Daha kötüsü SSH bile bağlanmıyordu; sunucu bağlantıyı kabul ediyor, sonra sessizce kesiyordu. Bu yazı o günün teşhisi ve haftalar sonra bulunan asıl sebebi anlatıyor. Aynı belirtiyi görüyorsan trafik seli ya da saldırı aramadan önce buradaki iki dakikalık kontrolü yap.
Belirti kümesi
Tek başına hiçbiri anlam ifade etmiyor; birlikte görünüyorsa imza nettir. Bütün dinamik siteler 503 verir, aynı hesaptaki statik siteler 200 dönmeye devam eder. SSH "connection reset" ya da "connection closed" der, çünkü hesap yeni bir shell bile fork edemez. hPanel'deki kaynak kartlarına bakınca CPU yüzde bir, RAM dört gigabaytın yarımı, disk ve inode yüzde sekiz gibi tertemiz görünür. Kimse bir şey yapmadan on, on beş dakika sonra her şey kendiliğinden düzelir ve ertesi gün yine olur.
Benim hesabımda cron günlükleri günlerdir aynı satırı yazıyordu: fork failed: Resource temporarily unavailable. Yani sorun o sabah başlamamıştı, tavana günlerdir çarpılıyordu; sadece o sabah herkes aynı anda içeride kalmıştı.
Ne değildi
İlk refleks saldırı ya da trafik seli aramak oluyor. İkisi de değildi: statik siteler ayakta olduğu için ağ katmanı sağlıklıydı, CPU boştaydı, hPanel'in ham istek sayıları düşüktü. Veritabanı anında cevap veriyordu, disk ve inode doluluğu yoktu, plan aktifti. Bütün bunları tek tek eleyince geriye tek bir kart kalıyor: hPanel → Hosting Plan → Resources Usage → Max Processes. Orada bir saat boyunca 200'e yapışık düz bir çizgi gördüm.
Kök neden, kanıtıyla
Hesabın process tavanı 200. Bunu dolduran şey Node uygulamalarının sayısı değil, her birinin açtığı thread sayısıydı. Sunucu shell fork edemediği için ps bile çalışmıyordu; teşhisi yalnız bash builtin'leriyle, /proc altından okumak zorunda kaldım:
for t in /proc/<pid>/task/*; do read -r ad < "$t/comm"; echo "$ad"; done | sort | uniq -c
# 64 tokio-runtime-w
# 5 node
# 4 libuv-worker
Altmış dört tokio-runtime-worker, Next.js'in derleyicisi olan @next/swc Rust ikilisinin havuzu. Tokio, worker sayısını makinenin görünen çekirdek sayısından alıyor; paylaşımlı sunucuda nproc 64 dönüyor. Sonuç: tek bir Next.js uygulaması, hiçbir şey yapmadan 75 process slotu tutuyor. Dört uygulama, 183. Geriye PHP için on yedi slot kalıyor; ilk yoğunlukta biten de o oluyor.
Bunu doğrulayan zarif bir karşı örnek de vardı. Aynı hesaptaki bir uygulama output: standalone ile çalışıyordu ve yalnız 11 thread yiyordu. Standalone çıktı çalışma anında next.config okumadığı için SWC ikilisini hiç yüklemiyor, dolayısıyla tokio havuzu hiç açılmıyor. Fark tam olarak bu.
Denenip işe yaramayanlar
Tokio'ya TOKIO_WORKER_THREADS=2 vermek işe yaramadı; bu değişkeni okumuyor, doğrudan available_parallelism() sonucuna bakıyor. Ortam değişkeni mekanizmasının kendisi çalışıyordu, çünkü aynı yoldan verilen UV_THREADPOOL_SIZE=2 libuv havuzunu dörtten ikiye düşürdü. Sorun tokio'nun kendisinde. NODE_OPTIONS'ı çalışma anında set etmek de geç kalıyor; V8 havuzu süreç başlarken kurulmuş oluyor.
Kalıcı çözüm: çekirdek sayısını yalan söylet
Tokio çekirdek sayısına bakıyorsa ona iki çekirdek göster. Linux'ta bunun aracı taskset: süreç belirli çekirdeklere bağlanınca available_parallelism() o kadar döner. Hostinger'da root gerekmez, kendi ~/bin altına bir sarmalayıcı yeter:
#!/bin/sh
# ~/bin/node22-lean
exec taskset -c 0,1 /opt/alt/alt-nodejs22/root/usr/bin/node "$@"
Sonra her Node sitesinin public_html/.htaccess dosyasında Passenger'a bu sarmalayıcıyı göster ve uygulamayı yeniden başlat:
PassengerNodejs /home/<kullanici>/bin/node22-lean
# ardından: touch <site>/source/tmp/restart.txt
Ölçülen sonuç, uygulama başına thread sayısı:
| Uygulama | Önce | Sonra |
|---|---|---|
| Next.js kurumsal site (Passenger) | 75 | 11 |
| Next.js ürün kataloğu (Passenger) | 75 | 13 |
| Node bot | 22 | 11 |
| Standalone Next.js | 11 | 9 |
| Hesap toplamı | ~183 / 200 | 38 / 200 |
Plan zaten yaklaşık iki çekirdeklik CPU veriyor; iş kapasitesi düşmüyor, sadece boşta bekleyen thread'ler gidiyor. Bütün siteler 200'e döndü ve bir daha 503 görmedim.
Kalıcılık tuzağı
Deploy script'in .htaccess'i şablondan yeniden yazıyorsa sarmalayıcı satırı ilk deploy'da silinir ve sorun sessizce geri gelir. Satırı deploy şablonuna işle; script sunucuda sarmalayıcı varsa onu, yoksa stok Node'u bassın. Ben bunu ilk projede unuttum, ikinci deploy'da sayaç yine 75'e çıktı.
Bir de yan bulgu: edge önbelleği ve deploy
Aynı gün başka bir şey daha yakaladım. Next.js, ISR sayfalarına s-maxage=3600 basıyor ve Hostinger'ın CDN'i bunu bir saat tutuyor. Deploy sonrası edge eski HTML'i servis edip artık var olmayan content-hash'li chunk'ı isteyince sayfa ChunkLoadError ile hidrasyonu kırıyor. Çözüm .htaccess'te: halka açık HTML için s-maxage=60, stale-while-revalidate=300, admin ve API yolları için private, no-store. Bunu kontrol etmeden bıraktığım bir sitede /admin/login sayfasına bir yıllık edge önbelleği basıldığını gördüm; hem oturum yüzeyi edge'e açılıyordu hem de bir yıl boyunca ölü chunk servis edilebilirdi.
Bu yazı neye dayanıyor
Hepsi kendi hesabımda, otuzu aşkın sitenin paylaştığı bir Hostinger Cloud Startup planında yaşandı; ölçümler Temmuz 2026'ya ait ve /proc çıktısı, hPanel kaynak kartı ve sarmalayıcı sonrası thread sayımı olarak kaydedildi. Sende de "hepsi birden 503, statikler ayakta, SSH kapalı" tablosu varsa önce Max Processes kartına bak; sonra Node uygulamalarının thread'lerini say.
Yazılım ve sistem mimarı, AlgowAI'da COO. Bu yazıdaki her şey canlı bir sistemde ölçülerek yaşandı; tahmin yok. Sorun sende de varsa yaz, bakarım.