Nginx Reverse Proxy Nedir: Temel Yapılandırma Rehberi

Bir web uygulaması geliştirdiniz, sunucuya deploy ettiniz ve artık dışarıdan erişilebilir olmasını istiyorsunuz. Ama bekleyin – uygulamanız 3000 portunda çalışıyor, SSL yok, birden fazla servis var ve hepsini yönetmeniz gerekiyor. İşte tam bu noktada nginx reverse proxy devreye giriyor ve hayatınızı kurtarıyor.

Reverse Proxy Nedir

Basitçe söylemek gerekirse, reverse proxy istemci ile arka uç sunucular arasında duran bir ara katmandır. İstemci isteği doğrudan arka uç uygulamaya değil, önce nginx’e gelir. Nginx bu isteği alır, uygun arka uç sunucuya iletir, cevabı alır ve istemciye döndürür.

Normal bir proxy’de (forward proxy) istemci tarafında çalışır ve istemcinin kimliğini gizler. Reverse proxy ise sunucu tarafında çalışır ve arka uç sunucuların kimliğini gizler. Bu ayrımı anlamak önemli çünkü çok farklı kullanım senaryoları doğuruyor.

Neden reverse proxy kullanırsınız?

  • SSL sonlandırma: SSL/TLS işlemini nginx üstlenir, arka uç uygulamalar şifrelemeyle uğraşmaz
  • Load balancing: Trafiği birden fazla sunucuya dağıtır
  • Caching: Sık kullanılan içerikleri önbelleğe alır
  • Güvenlik: Arka uç sunucuları doğrudan internete açmadan korur
  • Tek port yönetimi: 80/443 üzerinden birden fazla uygulamaya erişim sağlar
  • Rate limiting: İstek sınırlama ve DDoS koruması
  • Gzip sıkıştırma: Bant genişliği optimizasyonu

Nginx Kurulumu

Ubuntu/Debian sistemlerde kurulum oldukça basit:

sudo apt update
sudo apt install nginx -y

# Servis durumunu kontrol et
sudo systemctl status nginx

# Nginx'i başlat ve sistem açılışında otomatik başlamasını sağla
sudo systemctl enable --now nginx

# Nginx versiyonunu kontrol et
nginx -v

CentOS/RHEL sistemlerde:

sudo yum install epel-release -y
sudo yum install nginx -y
sudo systemctl enable --now nginx

# Firewall izinleri
sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --permanent --add-service=https
sudo firewall-cmd --reload

Kurulum tamamlandıktan sonra /etc/nginx/ dizini ana çalışma alanınız olacak. Temel yapı şöyle:

  • /etc/nginx/nginx.conf: Ana konfigürasyon dosyası
  • /etc/nginx/sites-available/: Mevcut site konfigürasyonları
  • /etc/nginx/sites-enabled/: Aktif site konfigürasyonları (symlink)
  • /etc/nginx/conf.d/: Ek konfigürasyon dosyaları
  • /var/log/nginx/: Log dosyaları

Temel Reverse Proxy Yapılandırması

En basit senaryoyla başlayalım: 3000 portunda çalışan bir Node.js uygulamasını 80 portundan yayınlamak.

sudo nano /etc/nginx/sites-available/myapp
server {
    listen 80;
    server_name myapp.example.com;

    location / {
        proxy_pass http://localhost:3000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        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_cache_bypass $http_upgrade;
    }
}

Konfigürasyonu aktif hale getirin:

# Symlink oluştur
sudo ln -s /etc/nginx/sites-available/myapp /etc/nginx/sites-enabled/

# Konfigürasyonu test et
sudo nginx -t

# Nginx'i yeniden yükle
sudo systemctl reload nginx

Bu konfigürasyondaki her direktif önemli:

  • proxy_pass: İsteğin iletileceği arka uç sunucu adresi
  • proxy_http_version 1.1: WebSocket desteği için HTTP 1.1 kullan
  • proxy_set_header Upgrade: WebSocket bağlantılarını destekler
  • proxy_set_header Connection: Bağlantı türünü iletir
  • proxy_set_header Host: Orijinal host başlığını korur
  • proxy_set_header X-Real-IP: İstemcinin gerçek IP adresini arka uca iletir
  • proxy_set_header X-Forwarded-For: Proxy zincirini takip etmek için
  • proxy_set_header X-Forwarded-Proto: HTTP mi HTTPS mi olduğunu belirtir

Gerçek Dünya Senaryosu: Çoklu Uygulama Yönetimi

Diyelim ki aynı sunucuda birden fazla uygulama çalışıyor: bir React frontend (port 3000), bir Django API (port 8000) ve bir Grafana dashboard (port 3001). Hepsini farklı domain veya path üzerinden yayınlamak istiyorsunuz.

# /etc/nginx/sites-available/production

# React Frontend
server {
    listen 80;
    server_name myapp.example.com;

    location / {
        proxy_pass http://localhost:3000;
        proxy_http_version 1.1;
        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;
    }
}

# Django API - subdomain ile
server {
    listen 80;
    server_name api.example.com;

    location / {
        proxy_pass http://localhost:8000;
        proxy_http_version 1.1;
        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;

        # API için timeout ayarları
        proxy_connect_timeout 60s;
        proxy_send_timeout 60s;
        proxy_read_timeout 60s;
    }
}

# Grafana - path bazlı routing
server {
    listen 80;
    server_name monitoring.example.com;

    location /grafana/ {
        proxy_pass http://localhost:3001/;
        proxy_http_version 1.1;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

Path bazlı routing yaparken dikkat edilmesi gereken bir nokta var: proxy_pass direktifinde sondaki / karakteri önemli. proxy_pass http://localhost:3001/ şeklinde yazarsanız nginx /grafana/ prefix’ini soyarak iletir. Bunu çok insanın gözden kaçırdığını görüyorum.

SSL/TLS Yapılandırması

Production ortamında HTTP kullanmak kabul edilemez. Let’s Encrypt ile ücretsiz SSL sertifikası ekleyelim:

# Certbot kurulumu
sudo apt install certbot python3-certbot-nginx -y

# Sertifika al ve nginx konfigürasyonunu otomatik güncelle
sudo certbot --nginx -d myapp.example.com -d api.example.com

# Sertifika yenilemeyi test et
sudo certbot renew --dry-run

# Crontab ile otomatik yenileme
echo "0 12 * * * /usr/bin/certbot renew --quiet" | sudo crontab -

Certbot nginx konfigürasyonunuzu otomatik güncelleyecek ama manuel yapılandırmayı da bilmek önemli:

server {
    listen 80;
    server_name myapp.example.com;
    # HTTP'yi HTTPS'e yönlendir
    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl http2;
    server_name myapp.example.com;

    ssl_certificate /etc/letsencrypt/live/myapp.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/myapp.example.com/privkey.pem;

    # Güvenli SSL ayarları
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512:ECDHE-RSA-AES256-GCM-SHA384;
    ssl_prefer_server_ciphers off;
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 10m;

    # HSTS header
    add_header Strict-Transport-Security "max-age=63072000" always;
    add_header X-Frame-Options DENY;
    add_header X-Content-Type-Options nosniff;

    location / {
        proxy_pass http://localhost:3000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        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;
    }
}

Upstream Bloğu ile Load Balancing

Uygulamanızı birden fazla instance üzerinde çalıştırıyorsanız upstream bloğu işinizi kolaylaştırır:

upstream myapp_backend {
    # Round-robin (default) - sırayla dağıtır
    server localhost:3000;
    server localhost:3001;
    server localhost:3002;
    
    # Keepalive bağlantıları
    keepalive 32;
}

upstream api_backend {
    # Least connections - en az bağlantısı olan sunucuya gönderir
    least_conn;
    server 192.168.1.10:8000 weight=3;
    server 192.168.1.11:8000 weight=1;
    server 192.168.1.12:8000 backup;  # Sadece diğerleri çökünce devreye girer
    
    keepalive 16;
}

server {
    listen 443 ssl http2;
    server_name myapp.example.com;

    # SSL ayarları burada...

    location / {
        proxy_pass http://myapp_backend;
        proxy_http_version 1.1;
        proxy_set_header Connection "";
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }

    location /api/ {
        proxy_pass http://api_backend/;
        proxy_http_version 1.1;
        proxy_set_header Connection "";
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

Upstream ayarlarındaki önemli parametreler:

  • weight: Sunucuya gönderilecek trafik oranı, varsayılan 1
  • max_fails: Sunucunun kaç başarısız istekten sonra geçici olarak devre dışı kalacağı
  • fail_timeout: Başarısız sunucunun kaç saniye devre dışı kalacağı
  • backup: Diğer tüm sunucular çöktüğünde devreye giren yedek sunucu
  • down: Sunucuyu kalıcı olarak devre dışı bırakır, bakım için kullanışlı

Rate Limiting ve Güvenlik

Production’da mutlaka rate limiting eklemeniz gerekiyor. Özellikle API endpoint’leri için bu kritik:

# nginx.conf içinde http bloğuna ekle
http {
    # Rate limiting zone tanımları
    limit_req_zone $binary_remote_addr zone=api_limit:10m rate=10r/s;
    limit_req_zone $binary_remote_addr zone=login_limit:10m rate=1r/s;
    limit_conn_zone $binary_remote_addr zone=conn_limit:10m;
    
    # Log formatı
    log_format main '$remote_addr - $remote_user [$time_local] "$request" '
                    '$status $body_bytes_sent "$http_referer" '
                    '"$http_user_agent" "$http_x_forwarded_for"';
}
server {
    listen 443 ssl http2;
    server_name api.example.com;

    # Genel API limiti
    location /api/ {
        limit_req zone=api_limit burst=20 nodelay;
        limit_conn conn_limit 10;
        
        proxy_pass http://localhost:8000/;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }

    # Login endpoint'i için daha sıkı limit
    location /api/auth/login {
        limit_req zone=login_limit burst=5 nodelay;
        
        proxy_pass http://localhost:8000/auth/login;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }

    # Belirli IP bloğu
    location /admin/ {
        allow 10.0.0.0/8;
        allow 192.168.1.0/24;
        deny all;
        
        proxy_pass http://localhost:8000/admin/;
        proxy_set_header Host $host;
    }
}

limit_req direktifindeki burst parametresi anlık trafikte tolerans sağlar. nodelay ise burst kapasitesi dolana kadar gecikme eklemeden işlem yapar.

Buffer ve Timeout Ayarları

Yavaş veya büyük dosya transferi yapan uygulamalar için buffer ayarlarını optimize etmek gerekir:

server {
    listen 443 ssl http2;
    server_name myapp.example.com;

    # Buffer ayarları
    proxy_buffering on;
    proxy_buffer_size 128k;
    proxy_buffers 4 256k;
    proxy_busy_buffers_size 256k;
    proxy_temp_file_write_size 256k;

    # Timeout ayarları
    proxy_connect_timeout 30s;
    proxy_send_timeout 60s;
    proxy_read_timeout 60s;
    send_timeout 60s;
    
    # Büyük dosya yüklemeleri için
    client_max_body_size 100M;
    client_body_buffer_size 128k;

    location / {
        proxy_pass http://localhost:3000;
        proxy_http_version 1.1;
        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;
    }
    
    # Statik dosyalar için doğrudan servis et
    location /static/ {
        alias /var/www/myapp/static/;
        expires 30d;
        add_header Cache-Control "public, immutable";
        gzip_static on;
    }
}

Gzip Sıkıştırma

Bant genişliği kullanımını azaltmak için gzip kesinlikle açık olmalı:

# nginx.conf http bloğunda
http {
    gzip on;
    gzip_vary on;
    gzip_proxied any;
    gzip_comp_level 6;
    gzip_buffers 16 8k;
    gzip_http_version 1.1;
    gzip_min_length 256;
    gzip_types
        application/atom+xml
        application/geo+json
        application/javascript
        application/x-javascript
        application/json
        application/ld+json
        application/manifest+json
        application/rdf+xml
        application/rss+xml
        application/vnd.ms-fontobject
        application/wasm
        application/x-web-app-manifest+json
        application/xhtml+xml
        application/xml
        font/eot
        font/otf
        font/ttf
        image/bmp
        image/svg+xml
        text/cache-manifest
        text/calendar
        text/css
        text/javascript
        text/markdown
        text/plain
        text/xml
        text/vcard
        text/vnd.rim.location.xloc
        text/vtt
        text/x-component
        text/x-cross-domain-policy;
}

Log Yönetimi ve Hata Ayıklama

Sorun çıktığında loglar hayat kurtarır. Nginx loglarını doğru yapılandırmak çok önemli:

server {
    listen 443 ssl http2;
    server_name myapp.example.com;

    # Her uygulama için ayrı log
    access_log /var/log/nginx/myapp_access.log main;
    error_log /var/log/nginx/myapp_error.log warn;

    location / {
        proxy_pass http://localhost:3000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

Sık kullanacağınız debug komutları:

# Nginx konfigürasyonunu test et
sudo nginx -t

# Konfigürasyonu detaylı test et
sudo nginx -T

# Access logunu canlı takip et
sudo tail -f /var/log/nginx/access.log

# Hata logunu izle
sudo tail -f /var/log/nginx/error.log

# Belirli bir domain'in logunu filtrele
sudo grep "myapp.example.com" /var/log/nginx/access.log | tail -100

# 5xx hatalarını filtrele
sudo awk '$9 >= 500' /var/log/nginx/access.log | tail -50

# Nginx process durumu
sudo nginx -s status 2>/dev/null || systemctl status nginx

# Konfigürasyon yeniden yükle (servisi durdurmadan)
sudo systemctl reload nginx

# Aktif bağlantı sayısını kontrol et
ss -tlnp | grep nginx

Yaygın Sorunlar ve Çözümleri

Production’da karşılaşacağınız en yaygın sorunların başında 502 Bad Gateway hatası gelir. Bu genellikle arka uç uygulamanın çalışmadığı anlamına gelir. Kontrol listesi:

  • Arka uç uygulama ayakta mı? systemctl status myapp veya pm2 status
  • Port doğru mu? ss -tlnp | grep 3000
  • Nginx log’larında ne yazıyor? tail -f /var/log/nginx/error.log

413 Request Entity Too Large hatası için client_max_body_size değerini artırın.

504 Gateway Timeout için proxy_read_timeout değerini kontrol edin. Uzun süren API çağrıları için bu değeri artırmanız gerekebilir.

SELinux kullanan sistemlerde nginx’in ağ bağlantısı kurmasına izin vermeniz gerekir:

# SELinux'ta nginx'in network bağlantısı kurmasına izin ver
sudo setsebool -P httpd_can_network_connect 1

# SELinux durumunu kontrol et
sestatus

Sonuç

Nginx reverse proxy kurulumu ilk bakışta karmaşık görünse de temel mantığı kavradıktan sonra çok güçlü bir araç olduğunu anlıyorsunuz. SSL sonlandırma, load balancing, rate limiting ve statik dosya servisi gibi özellikleri tek bir yerden yönetebilmek hem güvenlik hem de performans açısından büyük avantaj sağlıyor.

Anlattıklarımı özetlemek gerekirse: Önce basit bir proxy_pass ile başlayın, sonra ihtiyaçlarınıza göre SSL, rate limiting ve buffer ayarlarını ekleyin. Konfigürasyon değişikliklerinden önce mutlaka nginx -t ile test edin ve systemctl reload nginx kullanarak kesintisiz yeniden yükleme yapın.

Bir sonraki adım olarak nginx’i API Gateway olarak kullanmayı, JWT doğrulamayı nginx katmanında yapmayı ve upstream health check mekanizmalarını inceleyebilirsiniz. Bunlar kurumsal ortamlarda çok sık ihtiyaç duyulan konular.

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir