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 myappveyapm2 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.
