Ofiste Gece Yarısı: Küçük Bir Kesinti, Büyük Bir Ders
Hiç başınıza geldi mi? Uykunun en tatlı yerinde telefon çalar, bildirim sesi kulağınızı deler, bir bakmışsınız Node.js uygulaması susmuş. O gece ben de aynı duyguyla telefona uzanmıştım. Sunucuda hiçbir şey yokmuş gibi duran küçük bir ayrıntı, sanki halının altına süpürülmüş bir toz topağı gibi birikti birikti, sonra koca bir öksürükle kendini belli etti. Meğer log dosyası şişmiş, reverse proxy tamponu yanlış ayarlıymış, süreç de beklenmedik bir anda nefessiz kalmış.
O zaman düşündüm: “Bu iş biraz mutfak işi. Malzemeler belli, doğru sıralamayla ve doğru ısıda pişince her şey tadında.” İşte bu yazıda o sıralamayı birlikte kuracağız. PM2 ya da systemd ile süreçleri ayakta tutmak, Nginx reverse proxy ile trafiği usulca yönlendirmek, SSL ile güveni sağlamak ve en önemlisi sıfır kesintiyle dağıtım yapmak… Hepsi bir arada, akışkan ve anlaşılır bir yolculuk olsun istiyorum. Mesela şöyle düşünün: Kod sizin, sunucu sizin, ritmi de siz belirliyorsunuz. Biz de davulun tokmaklarını doğru yerlere vuralım.
Production Aklı: Tek Bir Node Süreciyle Dünya Dönmüyor
Node.js tek bir olay döngüsüne dayanıyor, bu yüzden üretimde “tek sürece güven” yaklaşımı kırılgan. Küçük bir dosya okuma gecikmesi, beklenmeyen bir istisna, kısa süreli CPU dalgalanması… Hepsi trafiğin üstüne dalga dalga biner. Üretimde amacımız şu: süreci izlemek, yeniden başlatmak, akışa kaldığı yerden devam etmek. Burada PM2 ve systemd ikilisi devreye girer. İkisi de süreci ayakta tutar, logları kaydeder, çökünce ayağa kaldırır. Ama tarzları farklı; biri Node dünyasına yakın duran bir yardımcı, diğeri işletim sistemine gömülü, işini sessizce yapan bir servis yöneticisi.
Bir de şu küçük ama önemli ayrıntılar var: ortam değişkenleri okunabilir olmalı, loglar dönmeli, maksimum dosya tanıtıcı sayısı küçük kalmamalı, uygulama beklenmedik kapanınca kibarca yeniden başlatılmalı. Ve elbette health check… Nginx’e “Ben iyiyim” diyecek minik bir uç nokta, kimi zaman koca bir krizden döndürür.
PM2 ile Koşmak: Hızlı Kurulum, Kolay Kontrol
PM2, Node.js dünyasında bir nevi tur rehberi gibi. Komutları anlaşılır, günlük işleri kolaylaştırıyor. İlk kez canlıya geçecekseniz PM2 ile başlamak, mutfağa yumuşak bir giriş gibi hissettirir. Kendi deneyimimde en çok sevdiğim şey, tek komutla süreç başlatıp kaydedebilmek, sonra sunucu yeniden açıldığında kaldığı yerden devam ettirmesi.
Basit bir başlangıç için önce kurup temelini atalım:
npm install -g pm2
pm2 start app.js --name myapp
pm2 save
pm2 startup # Çıktıdaki komutu sudo ile çalıştırın
Sonrasında bir ecosystem dosyasıyla düzen kurmak iyi olur. Ortam değişkenlerini, kaç kopya çalışacağını, log yollarını burada netleştirirsiniz. Küçük bir örnek:
// ecosystem.config.js
module.exports = {
apps: [
{
name: 'myapp',
script: 'app.js',
instances: 'max',
exec_mode: 'cluster',
env: {
NODE_ENV: 'production',
PORT: 3000
},
max_memory_restart: '512M',
error_file: '/var/log/myapp/error.log',
out_file: '/var/log/myapp/out.log',
merge_logs: true,
time: true
}
]
}
Böylece uygulamayı şu şekilde yönetirsiniz: başlatmak için pm2 start ecosystem.config.js, güncelleme sonrası zarifçe yeniden başlatmak için pm2 reload myapp. reload komutu özellikle severim; anlık kesinti olmadan yeni sürümü devreye alır. Bir de logları tek pencerede görmek isterseniz pm2 logs rahatlatır.
PM2 hakkında aklınıza takılan her şey için resmi sayfaya şöyle bırakayım: PM2’nin sade belgeleri ve pratik komutları. Orada kaybolmadan, ne ararsanız bulursunuz.
systemd ile Koşmak: İşletim Sisteminin Omuzları
systemd bir başka dünya. “Benim uygulamam sistemin vatandaşı olsun” diyorsanız, en doğal yol bu. Ayakları yere sağlam basan bir servis tanımı, beklenmedik durumlarda otomatik toparlanma ve temiz log akışıyla sunucunuzun dilini konuşur. Birkaç kez servis dosyasını doğru modelliyorsunuz, sonrası su gibi akıyor.
Küçük bir servis birimi hazırlayalım. Uygulamanızın dizini örneğin /var/www/myapp/current olsun; bunu birazdan sıfır kesinti dağıtımda kullanacağız:
# /etc/systemd/system/myapp.service
[Unit]
Description=My Node.js App
After=network.target
[Service]
Type=simple
WorkingDirectory=/var/www/myapp/current
ExecStart=/usr/bin/node app.js
Restart=always
RestartSec=3
Environment=NODE_ENV=production
Environment=PORT=3000
# Dosya tanıtıcı sınırını artırmak iyi gelebilir
LimitNOFILE=65536
# Kibar kapatma için
KillSignal=SIGINT
[Install]
WantedBy=multi-user.target
Servisi yükleyip başlatalım:
sudo systemctl daemon-reload
sudo systemctl enable myapp
sudo systemctl start myapp
sudo systemctl status myapp
Loglar için journalctl -u myapp -f yeterli. Eğer servis güncelleme sonrası nazikçe yenilensin isterseniz, uygulamanın SIGINT veya SIGTERM ile kibarca kapanabildiğinden emin olun. Böylece systemctl restart myapp dediğinizde isteklerinizi yarı yolda bırakmaz. Bir ipucu: Node tarafında süreç kapanırken açık bağlantıları bekleyen ufak bir graceful shutdown işlevi eklemek, gece yarısı kalp kırıklıklarını önler.
Nginx Reverse Proxy: Trafiğin Şefi, WebSocket’in Dostu
Node’u doğrudan 80 veya 443’te dinletmek zorunda değilsiniz. Hatta çoğu zaman dinletmeyin. Nginx’i öne koyup Node’unuzu içeride saklamak hem güvenlik, hem performans, hem de esneklik sağlar. Mesela WebSocket bağlantıları, büyük header’lar, sıkışan tamponlar… Nginx doğru ayarlarla bu işleri ustaca süzer.
Basit bir ters vekil ayarı şöyle olabilir. WebSocket’i unutmayalım, başlıkları düzgün iletelim, zaman aşımıyla gereksiz panik yaşamayalım:
upstream myapp_upstream {
server 127.0.0.1:3000;
keepalive 64;
}
server {
listen 80;
server_name example.com;
# İleride 443'e alacağız, şimdilik HTTP
location /health {
access_log off;
return 200 'ok';
}
location / {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_read_timeout 60s;
proxy_connect_timeout 5s;
proxy_send_timeout 60s;
proxy_pass http://myapp_upstream;
}
}
Bu yapı, WebSocket dahil çoğu akışı sorunsuz geçirir. “Niye 80? SSL nerede?” derseniz, hemen bir sonraki bölümde Let’s Encrypt ile 443’e taşıyıp tadını çıkaracağız. Ayrıca Nginx tarafında HTTP/2 veya HTTP/3 gibi modern protokollerle hız kazanmak, statik dosyaları doğrudan Nginx’ten sunmak günlük hayatı rahatlatır. Tabi, aşırı kuruluma kaçmadan, neye ihtiyacınız varsa onu açmak en iyisi.
SSL’i Bağlayalım: Let’s Encrypt, HSTS ve Sağlam Bir Tarife
Güvensiz bir trafik, güzel bir yemeğin üzerine dökülen tuzlu su gibi. İster PM2, ister systemd, öndeki kapı Nginx ise HTTPS’i temiz kurmak önemli. En pratik yol Let’s Encrypt ve Certbot. Alan adınız DNS’te doğru yere işaret ediyorsa, Nginx için komutlar inanılmaz kısa sürüyor.
Önce sunucuda Certbot’u çalıştırın. Sunucunuzu ve web sunucunuzu seçtiğinizde, kurulum sizden bir iki onaydan sonra sertifikaları alıp Nginx’e ekler:
# İşletim sistemi ve web sunucunuza göre adımlar için
# bu sayfadan başlayın:
# https://certbot.eff.org/instructions
Bu işlem bittiğinde Nginx konfigürasyonuna 443 bloğu eklenir, otomatik yenileme planlanır. Geriye birkaç ince ayar kalır: güçlü şifre kümeleri, HSTS, OCSP stapling ve HTTP’den HTTPS’e temizlikle yönlendirme. Detayı bir çırpıda yazmak burada yorabilir; ama iyi bir başlangıç için şu kaynağı seviyorum: Mozilla’nın SSL yapılandırma önerileri. Basitçe profil seçip Nginx’e uygun server bloğunu düzenleyebilirsiniz.
Bu adımı bitirdiğinizde server_name alan adınızı karşılayacak, 80’den 443’e yönlendirme net olacak, sertifikalar otomatik yenilenecek. Böylece tarayıcılar yeşil kilidi gösterecek, API çağrılarınız da güvenle akacak. İsterseniz HTTP/2’yi açıp isteklerin birer tren gibi aynı hatta akmasını sağlayın; çoğu modern tarayıcı destekliyor. Nginx’in proxy ayarlarıyla birleşince performans tatlı bir seviyeye gelir.
Sıfır Kesinti Deploy: PM2 Reload, Sembolik Sürümler ve Mavi/Yeşil
Asıl heyecan burada başlıyor. Canlı trafiği kesmeden yeni sürümü devreye almak, üretim dünyasında özgüven demek. İki güzel yol var: PM2’nin reload sihri ve systemd tarafında sembolik sürümlerle yürüyen mavi/yeşil yaklaşımı.
PM2 ile yol almak isterseniz basit akış şu: yeni kodu dizine alın, bağımlılıkları kurun, database şemanız varsa migrasyonları koşun, sonra pm2 reload myapp. Reload, eski süreç kapanmadan yenisini ayağa kaldırdığı için kullanıcı fark etmez. Küçük bir örnek dağıtım adımı:
git pull origin main
npm ci --only=production
npm run build
pm2 reload myapp
Biraz daha esnek, systemd’e yakışan bir yaklaşım ise sürümlü klasörlerdir. Uygulamayı /var/www/myapp/releases/2024-11-07-1200 gibi zaman damgalı klasörlere koyarsınız. current adlı sembolik link hangi sürümün canlı olduğunu söyler. Dağıtımda yeni klasörü rsync ile doldurur, bağımlılıkları kurar, current bağlantısını yeni sürüme çevirir, sonra systemctl restart myapp dersiniz. Nginx önünde olduğu için kapatma-açma arası çok kısa kalır, bağlantılar kesilmez. Aşağı yukarı şöyle bir dağıtım betiği yeter:
#!/usr/bin/env bash
set -euo pipefail
APP_DIR=/var/www/myapp
RELEASE=$(date +"%Y-%m-%d-%H%M%S")
TARGET="$APP_DIR/releases/$RELEASE"
mkdir -p "$TARGET"
# Kodları getir
rsync -a --delete ./ "$TARGET"/
# Bağımlılıklar ve build
cd "$TARGET"
npm ci --only=production
npm run build || true
# Sağlık kontrolü için portu localde çalıştırıp bir kez yoklama da ekleyebilirsiniz
# Canlıya al
ln -sfn "$TARGET" "$APP_DIR/current"
sudo systemctl restart myapp
# İsterseniz eski sürümleri saklama politikasına göre temizleyin
Bu yöntem mavi/yeşil’e göz kırpar. İsterseniz iki farklı portta iki sürümü çalıştırır, Nginx upstream’i küçük bir konfigürasyon güncellemesiyle birinden diğerine geçirirsiniz. Risksiz geri dönmek de kolaylaşır, çünkü eski sürüm duruyor. Dağıtım akışınızı daha detaylı kurgulamak isterseniz, biz daha önce VPS’e sıfır kesinti CI/CD kurulumunu rsync ve sembolik sürümlerle adım adım anlatmıştık; oradaki mantığı Node uygulamasına uyarlamak oldukça doğal.
Son bir dokunuş: dağıtım sonrası uygulamanın “iyi misin?” dediğimiz bir health endpoint’ine yanıt verdiğini kontrol etmeyi alışkanlık yapın. Nginx’e kısa süreli bir “bekle, yeni sürüm ayaklanıyor” sabrı tanımak, ufak gecikmelerde 502 paniklerinin önüne geçer.
Loglar, İzleme ve Küçük Dokunuşlar
Her şey çalışıyor diye kenara yaslanmak yerine, kulağınızı sahaya dayayın. Loglarınız döngüye girsin, boyutlar makul kalsın. PM2 kullanıyorsanız log dönüştürme için kendi araçları var; systemd tarafında ise journalctl zaten işin büyük bölümünü hallediyor. Uygulama loglarını tek kanaldan akıtmak, sorun çözmeyi beş dakikada bitiren bir alışkanlık.
Bir süre sonra izleme ihtiyacı kendini belli ediyor. CPU’nun nabzı, bellek tüketimi, 5xx oranı, gecikmeler… Bunları ufak panolar halinde görmek, sorun çıkmadan önce size göz kırpar. Sunucu tarafında hafif bir süreç yönetimi, Nginx’te kibar zaman aşımları, uygulama tarafında ölçüm noktaları… Hepsi birlikte küçük bir orkestra gibi çalar. Bu orkestrayı kurarken belgeler bazen altın değerinde oluyor; örneğin Certbot’un basit yönergeleri tek sayfada yolu gösteriyor.
Bir de küçük bir pratik: üretimde npm install yerine npm ci kullanmak, bağımlılıkların tutarlı kurulmasını sağlar. Build adımını her seferinde temiz almak, yarın öbür gün “bende çalışıyor” cümlesini tarihe karıştırır. Ortam değişkenlerini sistem tarafında tanımlayıp, yalnızca ihtiyaç duyduklarınızı uygulamaya verin; hem güvenlik, hem taşınabilirlik için iyi gelir.
Kapanış: Ritmi Bulunca Gerisi Akıyor
Başta göz korkutucu görünen üretim düzeni, birkaç doğru taş yerini bulunca huzura kavuşuyor. PM2 ile pratik bir başlangıç yapabilir, systemd ile kök salmış bir servis mimarisi kurabilir, Nginx’i öne alıp trafiği yumuşatabilir, SSL’i temizce bağlayıp güveni sağladıktan sonra sıfır kesintili dağıtımla gönül rahatlığıyla “deploy” diyebilirsiniz. İşin güzeli, bu parçalar bir kez elinize alışınca artık her projede kendiliğinden akıyor.
Benim tavsiyem, önce küçük adımlarla ilerleyin. Health endpoint’i eklemek, logları tek yere toplamak, dağıtım betiğini sadeleştirmek gibi ufak dokunuşlar bile büyük fark yaratıyor. Sonra sırasıyla reload veya sembolik sürüm akışını oturtun, SSL’i sıkılaştırın, Nginx ayarlarınızı gözden geçirin. Bir noktada fark edeceksiniz: gece yarısı gelen telefonların sayısı düşecek, hatta belki tamamen susacak. Umarım bu yazı size o ritmi bulmada yardımcı olmuştur. Bir dahaki yazıda daha da ince ayarlarda buluşuruz; içiniz ferah olsun, üretim dünyası sandığınız kadar sert değil, doğru reçeteyle gayet uysal.
