Vercel büyük bir ürün. Push et, build olsun, preview URL alsın, approve edince production'a çıksın. Çok şey lütuflu. Ama her projede bunun tamamına ihtiyaç olmuyor.
Bu sitenin altında çok daha basit bir deploy pipeline var. Tek komut, altmış satır bash. Buradan başlayalım.
npm run deploy
Bu komut şunu yapar:
- Vite production build (TS + CSS + JS bundle)
- SSH ile tar'lı upload (vendor, node_modules, .git, .env hariç)
- OPcache reset (web üzerinden fetch)
- Smoke test (curl ile ana sayfa HTTP 200 mı?)
Ortalama süre: 18 saniye.
Neden Vercel değil
Vercel harika bir ürün. Ama:
- PHP desteği yok. Serverless functions var ama PHP-FPM/Apache/LiteSpeed üçlüsü yok. Bizim backend PHP.
- Database ekstra. Vercel'de DB yok, yanında Supabase/Neon gerekiyor. Bizde Hostinger'ın managed MariaDB'si var, migrasyon maliyeti sıfır.
- Aylık bedel. Hostinger'ın yıllığı Vercel'in iki ayına denk.
Kısaca: Vercel müşteri ürünleri için harika bir seçim, ama bir stüdyo kendi sitesi için overkill.
Pipeline'ın anatomisi
deploy.sh dosyasının özü şu:
npm run build # Vite build
tar -czf - . \
--exclude='./node_modules' \
--exclude='./vendor' \
--exclude='./.git' \
--exclude='./.env' \
| ssh algow "cd ~/domains/algow.net/app && tar -xzf -"
Üç şey önemli:
SSH key auth. Şifre sormayı unut. ssh-copy-id ile public key sunucuya eklenir, ~/.ssh/config içinde alias tanımlanır:
Host algow
HostName 31.223.14.46
User u123456789
IdentityFile ~/.ssh/algow_hostinger
Artık ssh algow direkt girer, deploy.sh içinde de aynı alias çalışır.
Tar + SSH pipe. Dosya dosya scp veya rsync yerine tar'lı pipe daha hızlı. Sıkıştırma sürecinde upload başlar, sunucu paralel olarak açar. Bir defa fetch, tek syscall yığını.
Exclude listesi önemli. node_modules/ uploaded olursa 200 MB+ gereksiz veri akar. vendor/ zaten composer ile sunucuda kurulur. .env kesinlikle dışarıda kalmalı (zaten sunucuda ayrı bir .env var).
OPcache reset detayı
PHP OPcache, her dosyanın "bytecode"unu RAM'de tutar. Dosya değişse bile bir sonraki requestte eski cache'i kullanır. Bu opcache.validate_timestamps=0 olan production'larda (ki öyle olmalı, performans için) ciddi sorun.
Çözüm: deploy sonrası cache reset.
ssh algow "cat > public/_reset.php" <<'EOF'
<?php
if (function_exists('opcache_reset')) {
opcache_reset();
echo 'ok';
}
EOF
curl -s https://algow.net/_reset.php
ssh algow "rm -f public/_reset.php"
Geçici bir dosya bırakıyoruz, çağırıyoruz, siliyoruz. Bu yöntem pratik ama production'da HTTP handler tarafı çalışıyor, CLI değil. CLI'dan php -r "opcache_reset();" çağırsanız PHP-FPM'in cache'i etkilenmez — her process'in kendi cache'i vardır.
Smoke test
Deploy bitince anasayfanın 200 dönüp dönmediğini test ederiz:
STATUS=$(curl -sk -o /dev/null -w '%{http_code}' "$SITE_URL/?cb=$(date +%s)")
[ "$STATUS" = "200" ] || exit 1
?cb=timestamp query parametresi CDN cache'i bypass eder (varsa).
Ek bir test yapabilirdik: HTML içinde belirli bir string var mı? (örn. data-deploy-id="$GIT_SHA"). Bu özellik production tarafında meta tag olarak render edilirse, deploy'un gerçekten güncel olduğundan emin olunur. Henüz yapmadık, muhtemelen eklenecek.
80/20 kuralı
Bu pipeline Vercel değil. Ancak:
- CI/CD yok — local'de kim push ederse o deploy eder (tek developer).
- Preview URL yok — feature branch görmek için local serve yeter.
- Rollback süreci yok — git revert + re-deploy.
- Health check'ler sade — sadece HTTP 200.
Bir ekipte, birden çok projede, çoklu environment'ta bu yeterli olmaz. Bir stüdyonun tek kendi sitesi için ise tam olarak yeterli. Ölçeğin gerektirdiğinden fazlasını inşa etmek, zamanı yanlış harcamak.
Uzun vadede
Ekip büyüdüğünde veya preview URL'ler gerektiğinde şu iki yönde evrilir:
- GitHub Actions + Hostinger deploy step. Push'ta otomatik çalışır, yine SSH key.
- Cloudflare Pages + serverless API. PHP'yi Node/Cloudflare Workers'a taşırsak.
İkinci opsiyon ciddi refactor. Birinci opsiyon çok daha az maliyetli. İhtiyaç olunca yaparız.
Özet
Deploy pipeline'ı ürün değildir. Pipeline'a harcadığın her dakika müşteriye değer üretmez. Bizim için "bir komut, 18 saniye, sessiz başarı" yeterli. Daha karmaşık bir altyapı, daha karmaşık ihtiyaca ulaşınca eklenir.
Şimdilik npm run deploy bize yetiyor.