Prodüksiyon ortamında çalışan bir web sunucusunu yeniden başlatmak, yöneticilerin en çok kaçındığı işlemlerden biridir. “Şimdi restart atsam kaç kullanıcı etkilenir?” sorusu kafanızı meşgul ediyorsa, Nginx’in graceful restart ve zero downtime reload mekanizmalarını iyi anlamanın zamanı gelmiş demektir. Bu yazıda, gerçek dünya senaryoları üzerinden Nginx’i hiç kesinti yaşatmadan nasıl yeniden yükleyebileceğinizi, sinyal mekanizmasının nasıl çalıştığını ve olası sorunları nasıl aşabileceğinizi ele alacağız.
Nginx’in Sinyal Tabanlı Yönetimi
Nginx, süreç yönetimi için Unix sinyallerini kullanır. Bu yapıyı anlamak, zero downtime reload’ın mantığını kavramanızı kolaylaştıracaktır.
Master process, worker process’leri yönetir ve sinyalleri dinler. Bir sinyal aldığında, bu sinyalin türüne göre davranışını belirler. Worker process’ler ise gerçek HTTP trafiğini işleyen birimlerdir.
Nginx’in kabul ettiği temel sinyaller şunlardır:
- SIGHUP: Konfigürasyonu yeniden yükle, graceful restart başlat
- SIGTERM: Hızlı kapatma (mevcut bağlantıları keserek)
- SIGQUIT: Graceful kapatma (mevcut bağlantılar tamamlanınca kapat)
- SIGUSR1: Log dosyalarını yeniden aç
- SIGUSR2: Executable dosyayı yerinde güncelle (hot upgrade)
- SIGWINCH: Worker process’leri graceful olarak durdur
Bu sinyalleri doğrudan kill komutuyla veya nginx -s parametresiyle gönderebilirsiniz.
# Nginx PID'ini öğren
cat /var/run/nginx.pid
# Sinyali doğrudan gönder
kill -HUP $(cat /var/run/nginx.pid)
# Ya da nginx komutunu kullan
nginx -s reload
nginx -s quit
nginx -s stop
nginx -s reopen
Graceful Restart Nasıl Çalışır?
Graceful restart sürecini adım adım anlamak, neden “zero downtime” olduğunu netleştirecektir.
nginx -s reload veya kill -HUP komutu çalıştırdığınızda şu süreç işler:
- Master process yeni konfigürasyonu okur ve doğrular
- Konfigürasyon geçerliyse, yeni konfigürasyonla yeni worker process’ler başlatır
- Eski worker process’lere SIGQUIT sinyali gönderir
- Eski worker process’ler yeni bağlantı kabul etmeyi bırakır ancak mevcut bağlantıları tamamlamaya devam eder
- Mevcut bağlantılar kapandıkça eski worker process’ler sonlanır
- Yeni worker process’ler artık tüm trafiği karşılar
Bu süreçte hiçbir zaman “sunucu yok” durumu yaşanmaz. Yeni ve eski worker process’ler bir süre yan yana çalışır.
# Reload öncesi process durumunu gör
ps aux | grep nginx
# Reload işlemini yap
sudo nginx -s reload
# Reload sonrası process durumunu gör (geçici olarak daha fazla worker görebilirsiniz)
ps aux | grep nginx
Konfigürasyon Doğrulama: Reload Öncesinin Altın Kuralı
Zero downtime reload’ın en kritik adımı, konfigürasyonu deploy etmeden önce doğrulamaktır. Hatalı bir konfigürasyonla reload yapmaya çalışırsanız Nginx mevcut konfigürasyonla çalışmaya devam eder, bu iyi bir şeydir. Ancak neyin nereye bağlı olduğunu bilmeden çalışmak tehlikelidir.
# Konfigürasyonu test et
sudo nginx -t
# Daha ayrıntılı çıktı için
sudo nginx -T
# Belirli bir konfigürasyon dosyası belirterek test et
sudo nginx -t -c /etc/nginx/nginx.conf
Başarılı bir test şu çıktıyı verir:
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
Pratik öneri: Konfigürasyon değişikliği yapan herhangi bir script veya CI/CD pipeline’ında her zaman nginx -t çalıştırın ve çıktısı başarılı değilse reload adımına geçmeyin.
#!/bin/bash
# Güvenli reload scripti
CONFIG_FILE="/etc/nginx/nginx.conf"
echo "Konfigürasyon test ediliyor..."
if nginx -t -c $CONFIG_FILE; then
echo "Test başarılı, reload yapılıyor..."
nginx -s reload
echo "Nginx reload tamamlandı."
else
echo "HATA: Konfigürasyon testi başarısız! Reload yapılmadı."
exit 1
fi
Systemd ile Graceful Reload
Modern Linux sistemlerinde Nginx genellikle systemd tarafından yönetilir. systemctl reload nginx komutu, arka planda tam olarak nginx -s reload ile aynı işlemi yapar.
# Graceful reload
sudo systemctl reload nginx
# Reload ile restart arasındaki fark
sudo systemctl reload nginx # Zero downtime, konfigürasyonu yeniden yükler
sudo systemctl restart nginx # Nginx'i tamamen yeniden başlatır, kısa kesinti olabilir
# Önce test, sonra reload - tek satırda
sudo nginx -t && sudo systemctl reload nginx
# Durum kontrolü
sudo systemctl status nginx
systemctl restart kullanmanız gereken durumlar da vardır. Örneğin Nginx’in kendisini güncellediyseniz veya binary dosyası değiştiyse, reload yeterli olmayabilir. Bu durumda hot upgrade mekanizmasına bakmak gerekir.
Hot Upgrade: Binary Güncelleme Sırasında Zero Downtime
Nginx binary’sini güncellerken bile kesinti yaşamamak mümkündür. Bu işlem, SIGUSR2 ve SIGWINCH sinyalleriyle gerçekleştirilir.
# Adım 1: Mevcut PID'yi kaydet
OLD_PID=$(cat /var/run/nginx.pid)
echo "Eski master PID: $OLD_PID"
# Adım 2: Yeni binary'yi yerleştir (paket yöneticisi veya manuel)
# apt upgrade nginx ya da yeni binary'yi kopyala
# Adım 3: Master process'e SIGUSR2 gönder
# Bu, yeni bir master process başlatır
kill -USR2 $OLD_PID
# Adım 4: Yeni PID dosyasının oluşmasını bekle
sleep 2
NEW_PID=$(cat /var/run/nginx.pid)
echo "Yeni master PID: $NEW_PID"
# Adım 5: Eski worker process'leri graceful olarak durdur
kill -WINCH $OLD_PID
# Adım 6: Her şey yolundaysa eski master'ı kapat
# (eski master process hala ayakta, rollback için hazır)
kill -QUIT $OLD_PID
Eğer yeni versiyonla sorun yaşarsanız rollback yapabilirsiniz:
# Rollback: Eski master process'i yeniden aktifleştir
kill -HUP $OLD_PID
# Yeni master process'i graceful olarak durdur
kill -QUIT $NEW_PID
Gerçek Dünya Senaryosu: SSL Sertifikası Yenileme
Let’s Encrypt kullanan bir prodüksiyon ortamında sertifika yenileme işlemi sıkça yapılır. Certbot ile entegre çalışan bir Nginx kurulumunda, sertifika yenilendikten sonra Nginx’i yeniden başlatmak gerekir. Bunu kesintisiz yapmak için:
# /etc/letsencrypt/renewal-hooks/deploy/nginx-reload.sh
#!/bin/bash
echo "$(date): SSL sertifikası yenilendi, Nginx reload yapılıyor..." >> /var/log/certbot-reload.log
# Önce konfigürasyon testi
if /usr/sbin/nginx -t 2>> /var/log/certbot-reload.log; then
/usr/sbin/nginx -s reload
echo "$(date): Nginx başarıyla reload edildi." >> /var/log/certbot-reload.log
else
echo "$(date): HATA: Nginx konfigürasyonu hatalı, reload yapılmadı!" >> /var/log/certbot-reload.log
exit 1
fi
# Script'i çalıştırılabilir yap
chmod +x /etc/letsencrypt/renewal-hooks/deploy/nginx-reload.sh
# Manuel test
certbot renew --dry-run
Gerçek Dünya Senaryosu: Blue-Green Deployment ile Upstream Değiştirme
Mikroservis mimarisi veya blue-green deployment yapıyorsanız, upstream’i değiştirirken zero downtime çok önemlidir. Aşağıdaki senaryo, iki uygulama sunucusu (blue ve green) arasında geçişi gösterir.
Mevcut upstream.conf dosyanız şöyle olsun:
# /etc/nginx/conf.d/upstream.conf - Blue aktif
upstream app_backend {
server 127.0.0.1:8081; # Blue - aktif
# server 127.0.0.1:8082; # Green - pasif
keepalive 32;
}
server {
listen 80;
server_name example.com;
location / {
proxy_pass http://app_backend;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_connect_timeout 5s;
proxy_read_timeout 60s;
}
}
Green’e geçiş için:
#!/bin/bash
# blue-green-switch.sh
NGINX_CONF="/etc/nginx/conf.d/upstream.conf"
BACKUP_CONF="/etc/nginx/conf.d/upstream.conf.bak"
# Mevcut konfigürasyonu yedekle
cp $NGINX_CONF $BACKUP_CONF
# Green'e geçiş yap (sed ile satırları değiştir)
sed -i 's/server 127.0.0.1:8081; # Blue - aktif/# server 127.0.0.1:8081; # Blue - pasif/' $NGINX_CONF
sed -i 's/# server 127.0.0.1:8082; # Green - pasif/server 127.0.0.1:8082; # Green - aktif/' $NGINX_CONF
# Test et
if nginx -t; then
nginx -s reload
echo "Green deployment aktif."
else
echo "Hata! Eski konfigürasyona dönülüyor..."
cp $BACKUP_CONF $NGINX_CONF
nginx -t && nginx -s reload
exit 1
fi
Worker Process Sayısı ve Bağlantı Yönetimi
Zero downtime reload’ın etkinliği, worker process konfigürasyonunuzla da yakından ilişkilidir.
# /etc/nginx/nginx.conf
# CPU çekirdek sayısına göre ayarla
worker_processes auto;
# Her worker'ın açabileceği maksimum bağlantı sayısı
events {
worker_connections 1024;
use epoll;
multi_accept on;
}
http {
# Keepalive bağlantıları için timeout
keepalive_timeout 65;
keepalive_requests 1000;
# Worker process'lerin kapanma süresi için timeout
# Bu süre içinde eski worker'lar mevcut bağlantılarını tamamlar
# proxy_read_timeout değerinizden büyük olmalı
upstream backend {
server 127.0.0.1:8080;
keepalive 32;
}
}
Reload sırasında eski worker process’lerin ne kadar süre yaşayacağı, mevcut bağlantıların süresine bağlıdır. Uzun süreli WebSocket bağlantılarınız varsa bu önemlidir.
# Eski worker process'lerin hala çalışıp çalışmadığını kontrol et
ps aux | grep "nginx: worker process is shutting down"
# Kaç tane aktif bağlantı var
ss -tn | grep :80 | wc -l
# Nginx bağlantı istatistikleri (stub_status modülü aktifse)
curl http://localhost/nginx_status
Stub Status ile İzleme
Reload süreci sırasında ne olduğunu gözlemlemek için stub_status modülünü kullanabilirsiniz.
# /etc/nginx/conf.d/status.conf
server {
listen 127.0.0.1:8080;
server_name localhost;
location /nginx_status {
stub_status on;
access_log off;
allow 127.0.0.1;
deny all;
}
}
# Reload öncesi istatistikler
curl -s http://127.0.0.1:8080/nginx_status
# Reload yap
nginx -s reload
# Reload sonrası istatistikler (birkaç saniye aralıkla)
watch -n 1 'curl -s http://127.0.0.1:8080/nginx_status'
Çıktı şu şekilde görünür:
Active connections: 43
server accepts handled requests
1234 1234 5678
Reading: 2 Writing: 5 Waiting: 36
- Active connections: Mevcut aktif bağlantı sayısı
- accepts/handled: Toplam kabul edilen ve işlenen bağlantılar
- Reading: İstek header’ı okunan bağlantılar
- Writing: Yanıt yazılan bağlantılar
- Waiting: Keepalive bağlantıları bekleyen istemciler
Log Rotation ile Birlikte Kullanım
Log dosyaları rotate edildiğinde Nginx’in yeni dosyalara yazmaya başlaması için SIGUSR1 sinyali gönderilmesi gerekir. Bu işlem de kesintisiz yapılır.
# Log rotation için logrotate konfigürasyonu
# /etc/logrotate.d/nginx
/var/log/nginx/*.log {
daily
missingok
rotate 52
compress
delaycompress
notifempty
create 0640 www-data adm
sharedscripts
postrotate
# Nginx'i yeniden başlatmadan log dosyalarını yeniden açtır
if [ -f /var/run/nginx.pid ]; then
kill -USR1 $(cat /var/run/nginx.pid)
fi
endscript
}
# Manuel log yenileme
nginx -s reopen
# Ya da sinyal ile
kill -USR1 $(cat /var/run/nginx.pid)
# Yeni log dosyasına yazıldığını doğrula
tail -f /var/log/nginx/access.log
Yaygın Sorunlar ve Çözümleri
Sorun 1: Worker process’ler kapanmıyor
Uzun süreli bağlantılar (WebSocket, Server-Sent Events) nedeniyle eski worker process’ler kapanmayabilir. Bu durumda:
# Kapanmayı bekleyen worker'ları gör
ps aux | grep "shutting down"
# Belirli bir süre sonra zorla kapat (dikkatli kullanın)
# Önce normal yöntemle dene, beklemeye değer
sleep 300 # 5 dakika bekle
ps aux | grep "shutting down" | awk '{print $2}' | xargs kill -TERM
Sorun 2: Konfigürasyon testi geçiyor ama reload sonrası sorun çıkıyor
Bazı sorunlar konfigürasyon testinde yakalanmaz. Örneğin SSL sertifikası dosyası var ama içeriği bozuksa:
# SSL sertifikasını doğrula
openssl x509 -in /etc/nginx/ssl/cert.pem -noout -text | head -20
# Private key ile eşleşiyor mu?
openssl x509 -noout -modulus -in /etc/nginx/ssl/cert.pem | md5sum
openssl rsa -noout -modulus -in /etc/nginx/ssl/private.key | md5sum
# İki hash aynı olmalı
Sorun 3: Upstream sağlık kontrolü olmadan reload
Upstream sunucuların hazır olduğundan emin olmadan upstream konfigürasyonunu değiştirmek sorunlara yol açar:
#!/bin/bash
# Upstream hazır mı kontrol et
UPSTREAM_HOST="127.0.0.1"
UPSTREAM_PORT="8082"
TIMEOUT=30
INTERVAL=2
ELAPSED=0
echo "Upstream $UPSTREAM_HOST:$UPSTREAM_PORT bekleniyor..."
while ! nc -z $UPSTREAM_HOST $UPSTREAM_PORT 2>/dev/null; do
if [ $ELAPSED -ge $TIMEOUT ]; then
echo "HATA: Upstream $TIMEOUT saniye içinde hazır olmadı!"
exit 1
fi
sleep $INTERVAL
ELAPSED=$((ELAPSED + INTERVAL))
done
echo "Upstream hazır. Nginx reload yapılıyor..."
nginx -t && nginx -s reload
Ansible ile Otomasyona Alma
Prodüksiyon ortamında manuel reload yapmak yerine Ansible ile bu süreci otomatize etmek daha güvenlidir.
# nginx-reload.yml
---
- name: Nginx Zero Downtime Reload
hosts: webservers
become: yes
tasks:
- name: Nginx konfigürasyonunu kopyala
copy:
src: "{{ config_source }}"
dest: /etc/nginx/conf.d/app.conf
owner: root
group: root
mode: '0644'
register: nginx_config_changed
- name: Nginx konfigürasyonunu test et
command: nginx -t
when: nginx_config_changed.changed
register: nginx_test
failed_when: nginx_test.rc != 0
- name: Nginx'i graceful reload yap
command: nginx -s reload
when:
- nginx_config_changed.changed
- nginx_test.rc == 0
- name: Nginx durumunu doğrula
uri:
url: http://localhost/nginx_status
status_code: 200
when: nginx_config_changed.changed
# Ansible playbook'u çalıştır
ansible-playbook nginx-reload.yml -e "config_source=./app.conf"
Monitoring ve Alerting Entegrasyonu
Reload işlemlerini izlemek ve anormalliklerden haberdar olmak için basit bir monitoring scripti:
#!/bin/bash
# /usr/local/bin/nginx-health-check.sh
NGINX_STATUS_URL="http://127.0.0.1:8080/nginx_status"
ALERT_EMAIL="[email protected]"
LOG_FILE="/var/log/nginx-health.log"
check_nginx() {
# Process kontrolü
if ! pgrep -x nginx > /dev/null; then
echo "$(date): KRITIK - Nginx process çalışmıyor!" | tee -a $LOG_FILE
# mail -s "Nginx Down!" $ALERT_EMAIL < $LOG_FILE
return 1
fi
# HTTP yanıt kontrolü
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" --max-time 5 http://localhost/)
if [ "$HTTP_CODE" != "200" ] && [ "$HTTP_CODE" != "301" ] && [ "$HTTP_CODE" != "302" ]; then
echo "$(date): UYARI - Nginx beklenmedik HTTP kodu döndürüyor: $HTTP_CODE" | tee -a $LOG_FILE
return 1
fi
# Kapanmayı bekleyen worker sayısı
SHUTTING_DOWN=$(ps aux | grep "shutting down" | grep -v grep | wc -l)
if [ $SHUTTING_DOWN -gt 0 ]; then
echo "$(date): BILGI - $SHUTTING_DOWN worker process kapanmayı bekliyor." >> $LOG_FILE
fi
echo "$(date): Nginx sağlıklı. HTTP: $HTTP_CODE" >> $LOG_FILE
return 0
}
check_nginx
Sonuç
Nginx’in zero downtime reload ve graceful restart mekanizmaları, doğru anlaşıldığında prodüksiyon ortamlarında hayat kurtarır. Temel noktalara bakacak olursak:
- Reload öncesinde her zaman
nginx -tile konfigürasyonu doğrulayın nginx -s reloadveyasystemctl reload nginxkomutlarını kullanın,restartdeğil- Binary güncelleme gerekiyorsa SIGUSR2 ve SIGWINCH sinyallerini kullanarak hot upgrade yapın
- Uzun süreli bağlantılarınız varsa eski worker process’lerin kapanma süresini göz önünde bulundurun
- Reload işlemlerini Ansible gibi araçlarla otomatize ederek insan hatası riskini azaltın
- Stub status modülüyle reload sürecini aktif olarak izleyin
Birkaç dakikalık bir downtime kabul edilebilir gibi görünse de bunu kurtarmak için harcanan itibar ve kullanıcı güveni çok daha değerlidir. Nginx bu konuda size gereken tüm araçları sunuyor, bunları doğru kullanmak sizin elinizde.