Mikroservis Mimarisi Yönetimi: Nginx Reverse Proxy Kurulum ve Yapılandırma
Mikroservis mimarisine geçiş yapan ekiplerin en büyük baş ağrısı, onlarca küçük servisin dışarıya nasıl sunulacağı meselesidir. Her servise ayrı bir IP ve port mı versek? Her biri için ayrı SSL sertifikası mı yönetelim? İstemciler hangi servise hangi adresten ulaşacağını nasıl bilecek? İşte tam bu noktada Nginx reverse proxy devreye giriyor ve hayatı ciddi anlamda kolaylaştırıyor.
Bu yazıda gerçek dünya senaryoları üzerinden Nginx’i mikroservis mimarinizin önüne nasıl koyacağınızı, load balancing’den health check’e, rate limiting’den circuit breaker benzeri yapılara kadar her şeyi ele alacağız.
Reverse Proxy Nedir ve Neden Mikroservislerde Kritik?
Klasik proxy, istemcinin kimliğini gizleyerek sunucuya bağlanır. Reverse proxy ise tam tersi yönde çalışır: sunucuların kimliğini gizleyerek istemciye hizmet verir. İstemci sadece tek bir adrese bağlanır, arkadaki karmaşık yapıyı görmez.
Mikroservis senaryosunda düşünelim: E-ticaret uygulamanızda user-service port 3001’de, product-service port 3002’de, order-service port 3003’te, payment-service port 3004’te çalışıyor olsun. Bu servislerin hepsini doğrudan internete açmak hem güvenlik riski hem de yönetim kabusu yaratır.
Nginx’i önüne koyduğunuzda:
- Tek bir SSL sertifikası yönetirsiniz
- Tüm servisler
api.siteniz.com/users,api.siteniz.com/productsgibi temiz URL’lerle erişilebilir olur - Rate limiting, authentication, logging tek noktadan yönetilir
- İstemciler backend değişikliklerinden etkilenmez
Temel Nginx Kurulumu ve Yapılandırması
Önce temiz bir Ubuntu 22.04 üzerinde Nginx kuralım ve temel yapıyı oluşturalım.
# Nginx kurulumu
sudo apt update && sudo apt install -y nginx
# Nginx'in çalıştığını doğrula
sudo systemctl enable nginx
sudo systemctl start nginx
sudo systemctl status nginx
# Yapılandırma dizin yapısını incele
ls -la /etc/nginx/
# sites-available ve sites-enabled klasörlerini göreceksin
Mikroservis yapılandırmaları için conf.d altında ayrı dosyalar tutmak daha temiz bir yaklaşım. /etc/nginx/nginx.conf dosyasında şu ayarların olduğundan emin ol:
# /etc/nginx/nginx.conf içindeki worker ayarları
cat /etc/nginx/nginx.conf | grep -A5 "worker"
# Performans için worker_processes'ı CPU çekirdek sayısına göre ayarla
sudo sed -i 's/worker_processes auto/worker_processes 4/' /etc/nginx/nginx.conf
# Bağlantı limitini artır
# worker_events bloğunda worker_connections 1024'ten 4096'ya çıkar
sudo nano /etc/nginx/nginx.conf
İlk Reverse Proxy Yapılandırması
Basit bir senaryo ile başlayalım. Backend’de Node.js ile yazılmış bir user service çalışıyor.
# /etc/nginx/conf.d/microservices.conf dosyası oluştur
sudo tee /etc/nginx/conf.d/microservices.conf > /dev/null <<'EOF'
# Upstream tanımlamaları - backend servislerini burada gruplandırıyoruz
upstream user_service {
server 127.0.0.1:3001;
keepalive 32;
}
upstream product_service {
server 127.0.0.1:3002;
keepalive 32;
}
upstream order_service {
server 127.0.0.1:3003;
keepalive 32;
}
server {
listen 80;
server_name api.siteniz.com;
# Genel timeout ayarları
proxy_connect_timeout 10s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
# Proxy header'ları - backend'e gerçek IP ve protokol bilgisini ilet
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;
# User Service rotası
location /api/v1/users {
proxy_pass http://user_service;
}
# Product Service rotası
location /api/v1/products {
proxy_pass http://product_service;
}
# Order Service rotası
location /api/v1/orders {
proxy_pass http://order_service;
}
# Health check endpoint'i
location /health {
access_log off;
return 200 "healthyn";
add_header Content-Type text/plain;
}
}
EOF
# Yapılandırmayı test et ve yeniden yükle
sudo nginx -t && sudo nginx -s reload
Load Balancing ile Yüksek Erişilebilirlik
Servislerinizi tek instance olarak çalıştırmak riskli. Birden fazla instance’ı Nginx ile dengeleyebilirsiniz.
sudo tee /etc/nginx/conf.d/loadbalancer.conf > /dev/null <<'EOF'
# Round-robin (varsayılan) load balancing
upstream product_service_cluster {
# least_conn; # En az bağlantı olan sunucuya gönder
# ip_hash; # Aynı IP'yi hep aynı sunucuya yönlendir (session affinity)
server 127.0.0.1:3002 weight=3; # Bu sunucu 3x daha fazla istek alır
server 127.0.0.1:3012 weight=1;
server 127.0.0.1:3022 weight=1;
# Backup sunucu - diğerleri çökünce devreye girer
server 127.0.0.1:3032 backup;
# Health check parametreleri
# max_fails: Kaç başarısız denemeden sonra sunucuyu devre dışı bırak
# fail_timeout: Devre dışı bırakma süresi (saniye)
server 127.0.0.1:3042 max_fails=3 fail_timeout=30s;
keepalive 64;
keepalive_requests 1000;
keepalive_timeout 60s;
}
server {
listen 80;
server_name api.siteniz.com;
location /api/v1/products {
proxy_pass http://product_service_cluster;
proxy_next_upstream error timeout invalid_header http_500 http_502 http_503;
proxy_next_upstream_tries 3;
proxy_next_upstream_timeout 10s;
}
}
EOF
proxy_next_upstream direktifi kritik: bir backend sunucu hata döndürürse Nginx otomatik olarak bir sonrakine geçer. Bu basit ama etkili bir failover mekanizması.
SSL Termination ve HTTPS Yönetimi
Tüm SSL işlemlerini Nginx üzerinde sonlandırıp backend servislerine HTTP ile bağlanmak standart yaklaşım. Bu şekilde backend servisler SSL yükünden kurtulur.
# Certbot ile Let's Encrypt sertifikası al
sudo apt install -y certbot python3-certbot-nginx
sudo certbot --nginx -d api.siteniz.com --non-interactive --agree-tos -m [email protected]
# SSL yapılandırması Certbot tarafından eklenir
# Manuel olarak optimize etmek istersen:
sudo tee /etc/nginx/conf.d/ssl-microservices.conf > /dev/null <<'EOF'
server {
listen 443 ssl http2;
server_name api.siteniz.com;
ssl_certificate /etc/letsencrypt/live/api.siteniz.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/api.siteniz.com/privkey.pem;
# Modern SSL ayarları
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers off;
# SSL session cache - performans için
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1d;
ssl_session_tickets off;
# HSTS - tarayıcıya bir yıl boyunca sadece HTTPS kullan de
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
# OCSP Stapling
ssl_stapling on;
ssl_stapling_verify on;
resolver 8.8.8.8 8.8.4.4 valid=300s;
location /api/v1/users {
proxy_pass http://user_service;
proxy_set_header X-Forwarded-Proto https;
}
}
# HTTP'yi HTTPS'e yönlendir
server {
listen 80;
server_name api.siteniz.com;
return 301 https://$server_name$request_uri;
}
EOF
sudo nginx -t && sudo nginx -s reload
Rate Limiting ile API Koruması
Açık API’ler DDoS ve brute force saldırılarına davetiye çıkarır. Nginx’in limit_req modülü ile bu sorunu kolayca çözebilirsiniz.
sudo tee /etc/nginx/conf.d/rate-limiting.conf > /dev/null <<'EOF'
# Rate limit zone'larını http bloğunda tanımla
# Bu satırları /etc/nginx/nginx.conf içindeki http {} bloğuna ekle
# veya include edilen bir dosyaya yaz
# limit_req_zone: İstek limitleme zone'u
# $binary_remote_addr: İstemci IP'sine göre sınırla
# zone=api_limit:10m: "api_limit" adında 10MB hafıza kullan
# rate=10r/s: Saniyede maksimum 10 istek
limit_req_zone $binary_remote_addr zone=api_general:10m rate=10r/s;
limit_req_zone $binary_remote_addr zone=api_auth:10m rate=5r/m;
limit_req_zone $binary_remote_addr zone=api_search:10m rate=30r/m;
limit_req_status 429;
# API key bazlı rate limiting için map kullan
map $http_x_api_key $api_client_zone {
default "api_general";
"premium-key-abc123" "api_premium";
"enterprise-key-xyz" "api_enterprise";
}
limit_req_zone $http_x_api_key zone=api_premium:10m rate=100r/s;
limit_req_zone $http_x_api_key zone=api_enterprise:10m rate=500r/s;
server {
listen 443 ssl http2;
server_name api.siteniz.com;
# Authentication endpoint'leri daha sıkı sınırla
location /api/v1/auth/login {
limit_req zone=api_auth burst=10 nodelay;
limit_req_log_level warn;
proxy_pass http://auth_service;
}
# Genel API endpoint'leri
location /api/v1/ {
limit_req zone=api_general burst=20 nodelay;
proxy_pass http://backend_services;
# Rate limit bilgisini response header'a ekle
add_header X-RateLimit-Limit 10;
add_header X-RateLimit-Remaining $limit_req_status;
}
# Arama endpoint'i için özel limit
location /api/v1/search {
limit_req zone=api_search burst=5;
proxy_pass http://search_service;
}
}
EOF
burst parametresi önemli: Normalde saniyede 10 istek sınırı var ama kısa süreli trafik patlamalarına izin vermek için burst=20 ile 20 isteğin kuyruğa alınmasını sağlıyoruz. nodelay ile bu kuyruktaki istekler bekletilmeden işleniyor.
Gerçek Dünya Senaryosu: E-Ticaret Mikroservis Yapısı
Şimdi daha gerçekçi bir senaryo kuralım. Bir e-ticaret uygulamasında şu servisler var:
- auth-service: Kullanıcı girişi ve JWT üretimi (port 3001)
- user-service: Kullanıcı profil yönetimi (port 3002)
- product-service: Ürün kataloğu (port 3003, 3004, 3005 – 3 instance)
- cart-service: Sepet işlemleri (port 3006)
- order-service: Sipariş yönetimi (port 3007)
- notification-service: E-posta ve SMS (port 3008)
sudo tee /etc/nginx/conf.d/ecommerce-api.conf > /dev/null <<'EOF'
# Upstream tanımlamaları
upstream auth_backend {
server 127.0.0.1:3001 max_fails=2 fail_timeout=10s;
keepalive 16;
}
upstream user_backend {
server 127.0.0.1:3002 max_fails=2 fail_timeout=10s;
keepalive 16;
}
upstream product_backend {
least_conn;
server 127.0.0.1:3003 max_fails=3 fail_timeout=30s;
server 127.0.0.1:3004 max_fails=3 fail_timeout=30s;
server 127.0.0.1:3005 max_fails=3 fail_timeout=30s;
keepalive 32;
}
upstream cart_backend {
ip_hash; # Session affinity - aynı kullanıcı hep aynı instance'a gitsin
server 127.0.0.1:3006;
keepalive 16;
}
upstream order_backend {
server 127.0.0.1:3007 max_fails=2 fail_timeout=15s;
keepalive 16;
}
# Ortak proxy ayarları için değişkenler
map $request_method $cors_method {
OPTIONS 204;
default 0;
}
server {
listen 443 ssl http2;
server_name api.eticaret.com;
ssl_certificate /etc/letsencrypt/live/api.eticaret.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/api.eticaret.com/privkey.pem;
# CORS header'ları
add_header Access-Control-Allow-Origin "https://www.eticaret.com" always;
add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS" always;
add_header Access-Control-Allow-Headers "Authorization, Content-Type, X-API-Key" always;
# OPTIONS pre-flight request'leri hızlıca yanıtla
if ($request_method = OPTIONS) {
return 204;
}
# Security header'ları
add_header X-Content-Type-Options nosniff always;
add_header X-Frame-Options DENY always;
add_header X-XSS-Protection "1; mode=block" always;
# Auth servisi - JWT olmadan erişilebilir
location /api/v1/auth/ {
limit_req zone=api_auth burst=5 nodelay;
proxy_pass http://auth_backend/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
# Ürün listeleme - cache'lenebilir, rate limit gevşek
location /api/v1/products {
limit_req zone=api_general burst=50 nodelay;
proxy_pass http://product_backend;
proxy_cache_valid 200 30s;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
# Sepet - session affinity ile
location /api/v1/cart {
auth_request /auth/validate;
proxy_pass http://cart_backend;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
# Siparişler - daha uzun timeout (ödeme işlemi sürebilir)
location /api/v1/orders {
auth_request /auth/validate;
proxy_pass http://order_backend;
proxy_read_timeout 120s;
proxy_send_timeout 120s;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
# Auth doğrulama için internal endpoint
location = /auth/validate {
internal;
proxy_pass http://auth_backend/validate;
proxy_pass_request_body off;
proxy_set_header Content-Length "";
proxy_set_header X-Original-URI $request_uri;
}
}
EOF
sudo nginx -t && sudo nginx -s reload
Nginx Caching ile Performans Artırma
Özellikle ürün katalog gibi sık değişmeyen veriler için Nginx cache’leme ciddi fark yaratır.
# /etc/nginx/nginx.conf içindeki http {} bloğuna eklenecek cache tanımı
sudo tee /etc/nginx/conf.d/cache-config.conf > /dev/null <<'EOF'
# Cache dizini ve parametreleri
# levels=1:2: İki seviyeli dizin yapısı
# keys_zone=api_cache:10m: 10MB meta-data için hafıza
# max_size=1g: Maksimum disk kullanımı
# inactive=60m: 60 dakika erişilmezse sil
proxy_cache_path /var/cache/nginx/api levels=1:2 keys_zone=api_cache:10m max_size=1g inactive=60m use_temp_path=off;
server {
listen 443 ssl http2;
server_name api.eticaret.com;
location /api/v1/products {
proxy_cache api_cache;
proxy_cache_valid 200 30s;
proxy_cache_valid 404 1m;
proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;
proxy_cache_background_update on;
proxy_cache_lock on;
# Cache key'e query string'i dahil et
proxy_cache_key "$scheme$request_method$host$request_uri";
# Cache durumunu header olarak ekle (debug için kullanışlı)
add_header X-Cache-Status $upstream_cache_status;
proxy_pass http://product_backend;
}
}
EOF
# Cache dizinini oluştur
sudo mkdir -p /var/cache/nginx/api
sudo chown nginx:nginx /var/cache/nginx/api
sudo nginx -t && sudo nginx -s reload
Loglama ve Monitoring
Mikroservis ortamında hangi servisin ne kadar sürede yanıt verdiğini takip etmek şart.
sudo tee /etc/nginx/conf.d/logging.conf > /dev/null <<'EOF'
# Detaylı log formatı tanımla
log_format microservice_log '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent" '
'rt=$request_time '
'uct=$upstream_connect_time '
'uht=$upstream_header_time '
'urt=$upstream_response_time '
'ups=$upstream_addr '
'cache=$upstream_cache_status';
# JSON formatında log (log management sistemleri için daha kullanışlı)
log_format json_log escape=json
'{"time": "$time_iso8601",'
'"remote_addr": "$remote_addr",'
'"request": "$request",'
'"status": $status,'
'"bytes_sent": $body_bytes_sent,'
'"request_time": $request_time,'
'"upstream_response_time": "$upstream_response_time",'
'"upstream_addr": "$upstream_addr",'
'"cache_status": "$upstream_cache_status"}';
server {
listen 443 ssl http2;
server_name api.eticaret.com;
# Her servis için ayrı log dosyası
access_log /var/log/nginx/api_access.log json_log;
error_log /var/log/nginx/api_error.log warn;
location /api/v1/products {
access_log /var/log/nginx/products_access.log microservice_log;
proxy_pass http://product_backend;
}
location /api/v1/orders {
access_log /var/log/nginx/orders_access.log microservice_log;
proxy_pass http://order_backend;
}
}
EOF
# Log analizi için yararlı komutlar
# En yavaş yanıt veren endpoint'leri bul
sudo awk '{print $10, $7}' /var/log/nginx/api_access.log | sort -rn | head -20
# 500 hatalarını filtrele
sudo grep '"status": 5' /var/log/nginx/api_access.log | tail -50
# Belirli upstream'in response time ortalaması
sudo awk '/product_backend/ {sum+=$10; count++} END {print "Avg:", sum/count}' /var/log/nginx/api_access.log
Health Check ve Otomatik Failover
Nginx Plus’ta aktif health check var ama açık kaynak versiyonda pasif health check ile idare edebilirsiniz. Buna ek olarak basit bir script ile servis durumunu izleyebilirsiniz.
# Basit upstream health check scripti
sudo tee /usr/local/bin/nginx-health-check.sh > /dev/null <<'SCRIPT'
#!/bin/bash
SERVICES=("http://127.0.0.1:3001/health" "http://127.0.0.1:3002/health" "http://127.0.0.1:3003/health")
SERVICE_NAMES=("auth-service" "user-service" "product-service")
ALERT_EMAIL="[email protected]"
for i in "${!SERVICES[@]}"; do
RESPONSE=$(curl -s -o /dev/null -w "%{http_code}" --max-time 5 "${SERVICES[$i]}")
if [ "$RESPONSE" != "200" ]; then
echo "[$(date '+%Y-%m-%d %H:%M:%S')] HATA: ${SERVICE_NAMES[$i]} yanıt vermiyor! HTTP: $RESPONSE"
# Nginx log'una yaz
logger -t nginx-healthcheck "Service DOWN: ${SERVICE_NAMES[$i]} (HTTP: $RESPONSE)"
# Mail gönder (mailutils kurulu ise)
echo "${SERVICE_NAMES[$i]} servisi yanıt vermiyor. HTTP Status: $RESPONSE" |
mail -s "Mikroservis Alert: ${SERVICE_NAMES[$i]} DOWN" "$ALERT_EMAIL" 2>/dev/null
else
echo "[$(date '+%Y-%m-%d %H:%M:%S')] OK: ${SERVICE_NAMES[$i]} çalışıyor"
fi
done
SCRIPT
chmod +x /usr/local/bin/nginx-health-check.sh
# Cron job olarak her dakika çalıştır
echo "*/1 * * * * root /usr/local/bin/nginx-health-check.sh >> /var/log/nginx/health-check.log 2>&1" |
sudo tee /etc/cron.d/nginx-health-check
Sorun Giderme İpuçları
Nginx konfigürasyonu ile uğraşırken en çok karşılaşılan sorunlar ve çözümleri:
- 502 Bad Gateway: Backend servis çalışmıyor ya da upstream adresi yanlış.
curl -v http://127.0.0.1:3001ile direkt test et - 504 Gateway Timeout: Backend çok yavaş yanıt veriyor.
proxy_read_timeoutdeğerini artır - 413 Request Entity Too Large: Upload boyutu limitini
client_max_body_size 50m;ile artır - “upstream sent invalid header”: Backend yanlış HTTP response döndürüyor, servis loglarını kontrol et
- SSL_ERROR_RX_RECORD_TOO_LONG: Backend’e HTTP ile bağlanman gerekirken HTTPS yapılandırmış olabilirsin
# En kullanışlı debug komutları
sudo nginx -T # Tüm aktif konfigürasyonu göster
sudo nginx -t # Syntax kontrolü
sudo tail -f /var/log/nginx/error.log # Canlı hata takibi
sudo nginx -s reload # Sıfır downtime ile yeniden yükle
sudo nginx -s reopen # Log dosyalarını rotate et
# Upstream bağlantısını test et
curl -H "Host: api.eticaret.com" http://127.0.0.1/api/v1/products
Sonuç
Nginx’i mikroservis mimarinizin önüne koymak, dağıtık sistemlerin getirdiği karmaşıklığı yönetilebilir bir seviyeye çekiyor. Tek SSL noktası, merkezi rate limiting, otomatik failover ve detaylı loglama ile gecenin üçünde alarm alan birisi olmak yerine sabah raporlarına bakan biri olabilirsiniz.
Bu yazıda anlattıklarımı bir kenara not düşelim:
- Upstream grupları ile load balancing ve failover sağlıyorsunuz
- SSL termination backend servis karmaşıklığını azaltıyor
- Rate limiting zone’ları API’yi kötü niyetli kullanıma karşı koruyor
- Proxy cache tekrarlayan isteklerde backend yükünü ciddi azaltıyor
- JSON log formatı loglama ve monitoring altyapısıyla entegrasyonu kolaylaştırıyor
Bir sonraki adım olarak Nginx Plus’ın aktif health check özelliğini veya açık kaynak alternatifleri olan nginx_upstream_check_module modülünü incelemenizi öneririm. Kubernetes ortamına geçiyorsanız da bu konfigürasyonların büyük bölümünün Ingress Controller’a nasıl taşındığını araştırın; temel kavramlar aynı kalıyor.
