Nginx ile reverse proxy (ters vekil) kurulumu
Ters vekil (reverse proxy), ziyaretçi ile uygulamanız arasında duran bir sunucudur: internetten gelen isteği karşılar, arkadaki uygulamaya iletir ve uygulamanın yanıtını ziyaretçiye geri gönderir. Ziyaretçi yalnızca ters vekili görür; uygulamanın hangi bağlantı noktasında, hangi dille çalıştığını bilmez.
Node.js, Python, Java, .NET ya da Go ile yazılmış uygulamalar çoğunlukla 3000 ya da 8080 gibi bir bağlantı noktasında kendi küçük web sunucularıyla çalışır. Bu uygulamayı doğrudan internete açmak yerine önüne Nginx koymak; tek adresten birden fazla uygulama sunmayı, HTTPS'i tek yerde yönetmeyi, statik dosyaları hızlı vermeyi ve istek boyutu ile zaman aşımı (timeout) gibi sınırları merkezî olarak belirlemeyi sağlar. Kavramın ayrıntısı için ters vekil nedir rehberine bakabilirsiniz.
Bu rehber, tek bir arka uç sunucusu (backend) için çalışan bir yapılandırmayı adım adım kurar. Örneklerde alan adı ornek.com, uygulama adresi 127.0.0.1:3000 kabul edilmiştir.
Kısaca
- Nginx isteği karşılar, proxy_pass ile arkadaki uygulamaya iletir.
- proxy_pass sonundaki eğik çizgi, arka uca giden yolu değiştirir.
- Host ve X-Forwarded-* başlıkları iletilmezse uygulama gerçek IP ve https bilgisini göremez.
- Her değişiklikten sonra nginx -t ile test edin, sonra yeniden yükleyin.
Gerekenler
- Nginx kurulu bir sunucu ve yönetici (sudo) yetkisi
- Sunucuda çalışan bir uygulama ve dinlediği bağlantı noktası (örnekte 127.0.0.1:3000)
- Sunucunun IP adresine yönlendirilmiş bir alan adı
- Yapılandırma dosyalarını düzenleyebileceğiniz bir SSH oturumu
Not
Örnekler yalnız 80 numaralı bağlantı noktasını (HTTP) gösterir. Canlı sitede HTTPS de gerekir; sertifika ve 443 ayarları ayrı bir rehberde anlatılmıştır.
Bu sayfada
Adım adım kurulum
-
Uygulamayı yalnız yerel adrese dinletin
Nginx ile uygulama aynı sunucudaysa uygulamanın
0.0.0.0(tüm ağ arayüzleri) yerine127.0.0.1adresini dinlemesini sağlayın. Böylece uygulamaya yalnızca aynı sunucudaki Nginx ulaşabilir; kimse Nginx'i atlayıphttp://sunucu-ip:3000adresinden doğrudan bağlanamaz.Uygulama başka bir sunucudaysa iç ağ adresini (ör.
10.0.0.5) dinletin ve güvenlik duvarında o bağlantı noktasına yalnızca Nginx sunucusunun erişmesine izin verin. Bu adım, ileride anlatılan "gerçek IP" ayarının güvenli olmasının da ön koşuludur.
: Büyüt -
server bloğunu oluşturun
Nginx'te her site bir
serverbloğuyla tanımlanır. Yeni bir yapılandırma dosyası açın. Dosyanın yeri dağıtıma göre değişir:/etc/nginx/conf.d/altındaki.confdosyaları yaygın bir düzendir; Debian ve Ubuntu'da/etc/nginx/sites-available/ilesites-enabled/düzeni kullanılır.Nginx# Örnek dosya: /etc/nginx/conf.d/ornek.com.conf (yol dağıtıma göre değişir) server { listen 80; server_name ornek.com www.ornek.com; location / { # Tüm istekleri arkadaki uygulamaya ilet proxy_pass http://127.0.0.1:3000; } }listendinlenecek bağlantı noktasını,server_namebu bloğun hangi alan adlarına yanıt vereceğini belirler.location /bloğu tüm adresleri kapsar; içindekiproxy_passyönergesi (directive) isteğin nereye iletileceğini söyler. -
proxy_pass ve sondaki eğik çizgiyi doğru kullanın
En sık yapılan hata buradadır.
proxy_passadresinde sunucu adından sonra bir yol (tek bir/bile) varsa, Nginx isteğinlocationile eşleşen bölümünü bu yolla değiştirir. Yol yoksa istek adresi olduğu gibi iletilir.location proxy_pass Gelen istek Arka uca giden yol /uygulama/http://127.0.0.1:3000/uygulama/giris/uygulama/giris/uygulama/http://127.0.0.1:3000//uygulama/giris/giris/eski/http://127.0.0.1:3000/yeni//eski/sayfa/yeni/sayfa/uygulamahttp://127.0.0.1:3000//uygulama/giris//giris(hatalı)Nginx# 1) proxy_pass'te yol YOK: adres olduğu gibi iletilir # /uygulama/giris -> /uygulama/giris location /uygulama/ { proxy_pass http://127.0.0.1:3000; } # 2) proxy_pass "/" ile bitiyor: eşleşen ön ek silinir # /api/liste -> /liste location /api/ { proxy_pass http://127.0.0.1:3001/; } # 3) proxy_pass'te başka bir yol var: ön ek o yolla değiştirilir # /eski/sayfa -> /yeni/sayfa location /eski/ { proxy_pass http://127.0.0.1:3000/yeni/; }Kural olarak
locationileproxy_passyolunu aynı biçimde bitirin: ikisi de eğik çizgiyle bitsin ya daproxy_pass'te hiç yol olmasın. Uygulamanız bir alt yolda (ör./uygulama/) çalışacak biçimde ayarlanmışsa ön eki silmeyin; kök dizinde çalıştığını varsayıyorsa silin. Düzenli ifadeyle tanımlananlocationbloklarındaproxy_passyol içeremez; Nginx yapılandırma testinde hata verir.
: Büyüt -
Gerekli başlıkları iletin
Nginx isteği arka uca kendi adına yeniden gönderir. Ek ayar yapılmazsa uygulama, ziyaretçinin değil Nginx'in IP adresini görür;
Hostbaşlığı daproxy_pass'te yazan adres olur. Şu dört başlık bu bilgiyi uygulamaya taşır:Nginxproxy_pass http://127.0.0.1:3000; # Ziyaretçinin istediği alan adı proxy_set_header Host $host; # Nginx'e bağlanan istemcinin IP adresi proxy_set_header X-Real-IP $remote_addr; # İsteğin geçtiği adresler (mevcut listeye eklenir) proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; # Ziyaretçinin kullandığı şema: http ya da https proxy_set_header X-Forwarded-Proto $scheme;- Host: Ziyaretçinin istediği alan adı. Uygulama bağlantı üretirken ve birden fazla alan adını ayırt ederken bunu kullanır.
- X-Real-IP: Nginx'e bağlanan istemcinin IP adresi.
- X-Forwarded-For: İsteğin geçtiği adreslerin listesi.
$proxy_add_x_forwarded_for, istemcinin gönderdiği listeye bağlanan adresi ekler. - X-Forwarded-Proto: Ziyaretçinin kullandığı şema (
httpya dahttps).
Dikkat:
proxy_set_headeryönergeleri üst düzeyden yalnızca o düzeyde hiçproxy_set_headeryoksa devralınır. Birlocationiçine tek bir başlık eklersenizserverdüzeyinde yazdıklarınız o blokta geçerliliğini yitirir; hepsini yeniden yazmanız gerekir. -
WebSocket desteğini ekleyin
Canlı sohbet, bildirim ya da anlık pano gibi özellikler WebSocket kullanır. WebSocket, sıradan bir HTTP isteğinin
Upgradebaşlığıyla kalıcı bir bağlantıya yükseltilmesiyle başlar. Bu başlıklar vekil sunucudan (proxy) kendiliğinden geçmez; açıkça iletilmeleri ve arka uçla HTTP/1.1 konuşulması gerekir.Nginx# http düzeyinde (server bloğunun dışında) bir kez tanımlanır map $http_upgrade $connection_upgrade { default upgrade; '' close; } server { listen 80; server_name ornek.com; location / { proxy_pass http://127.0.0.1:3000; # WebSocket için HTTP/1.1 ve yükseltme başlıkları proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $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; # Boşta kalan WebSocket bağlantısı bu süre sonunda kapatılır proxy_read_timeout 300s; } }mapbloğuhttpdüzeyinde (server bloğunun dışında) yer alır: istemci yükseltme istediyseConnection: upgrade, istemediyseConnection: closegönderilmesini sağlar. Böylece aynılocationhem normal istekler hem WebSocket için çalışır.WebSocket bağlantısında
proxy_read_timeoutsüresince hiç veri gelmezse Nginx bağlantıyı kapatır. Süreyi uzatın ya da uygulamanın düzenli aralıklarla "ping" göndermesini sağlayın.
: Büyüt -
Zaman aşımlarını ve gövde boyutunu ayarlayın
Yönerge Ne belirler? Varsayılan proxy_connect_timeoutArka uçla bağlantı kurulması için beklenen süre 60s proxy_send_timeoutİstek arka uca gönderilirken iki yazma işlemi arasındaki en uzun bekleme 60s proxy_read_timeoutArka uçtan yanıt okunurken iki okuma işlemi arasındaki en uzun bekleme 60s client_max_body_sizeİstemcinin gönderebileceği istek gövdesinin (ör. dosya yükleme) üst sınırı 1m Nginx# Dosya yükleme sınırı (varsayılan 1m); aşılırsa 413 döner client_max_body_size 20m; location / { proxy_pass http://127.0.0.1:3000; proxy_connect_timeout 5s; # arka uçla bağlantı kurma proxy_send_timeout 60s; # arka uca istek gönderme proxy_read_timeout 60s; # arka uçtan yanıt bekleme } # Yalnız uzun süren rapor adresi için daha uzun bekleme location /rapor/ { proxy_pass http://127.0.0.1:3000; proxy_read_timeout 180s; }Okuma ve yazma zaman aşımları toplam süreyi değil, iki işlem arasındaki sessizliği ölçer. Uygulama 60 saniye boyunca hiç yanıt göndermezse ziyaretçi 504 hatası görür. Dosya yükleme sınırı aşılırsa Nginx 413 hatası döndürür; uygulamanın kendi yükleme sınırını da aynı değere getirmeyi unutmayın. Süreleri gereğinden uzun tutmayın: uzun rapor ya da dışa aktarma gibi belirli adreslere özel
locationyazmak, tüm site için sınırı yükseltmekten iyidir. Bu hataların ayrıntısı 502, 504 ve diğer Nginx hataları rehberindedir. -
Yapılandırmayı test edin ve yeniden yükleyin
Nginx yapılandırma dosyasını kendiliğinden yeniden okumaz. Önce sözdizimini test edin, test başarılıysa yeniden yükleyin (reload). Yeniden yükleme açık bağlantıları koparmaz; yapılandırma hatalıysa Nginx eski ayarlarla çalışmayı sürdürür.
Bash# 1) Yapılandırmayı test edin sudo nginx -t # 2) Test başarılıysa yeniden yükleyin (bağlantılar kopmaz) sudo systemctl reload nginx # systemd kullanılmayan sistemlerde aynı işlem: sudo nginx -s reloadnginx -tyalnızca sözdizimini ve yönerge bağlamını denetler; arka ucun ayakta olup olmadığına bakmaz. Bu yüzden ardından siteyicurlile ya da tarayıcıdan deneyin.
: Büyüt -
Uygulamaya vekile güvenmesini öğretin
Nginx başlıkları gönderse bile uygulama bunları kendiliğinden kullanmaz. Çoğu uygulama çatısında bunun için "güvenilen proxy" (trusted proxy) adıyla bir ayar bulunur: buraya ters vekilinizin adresini (aynı sunucudaysa
127.0.0.1) yazarsınız; çatı da yalnızca o adresten gelen isteklerdeX-Forwarded-*başlıklarını dikkate alır. Ayarın adı ve yeri kullandığınız çatıya göre değişir; belgelerinde "proxy" başlığına bakın.Bu ayar yapılmazsa tipik belirtiler şunlardır: günlüklerde tüm ziyaretçiler
127.0.0.1görünür, IP'ye dayalı oran sınırlama herkesi tek kişi sayar, uygulama kendinihttpsanıp sonsuz yönlendirme döngüsüne girer ya da bağlantılarıhttp://ile üretir.Güvenlik kuralı:
X-Forwarded-*başlıklarını herkes gönderebilir. Bunlara yalnızca istek kendi ters vekilinizden geliyorsa güvenin; "tüm adreslere güven" türü ayarlardan kaçının. Aksi hâlde bir saldırgan sahte başlıkla IP kısıtlarını ve oran sınırlarını atlatabilir. Çatı kullanmayan bir PHP uygulamasında aynı mantık şöyle kurulur:PHP<?php // Yalnız kendi ters vekilinizin adresleri (Nginx aynı sunucudaysa 127.0.0.1) $guvenilenProxyler = array('127.0.0.1'); $uzakAdres = $_SERVER['REMOTE_ADDR'] ?? ''; $istemciIp = $uzakAdres; $httpsMi = !empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off'; // Başlıklara yalnız istek güvenilen vekilden geldiyse bakılır if (in_array($uzakAdres, $guvenilenProxyler, true)) { $gercekIp = $_SERVER['HTTP_X_REAL_IP'] ?? ''; if (filter_var($gercekIp, FILTER_VALIDATE_IP) !== false) { $istemciIp = $gercekIp; } $httpsMi = ($_SERVER['HTTP_X_FORWARDED_PROTO'] ?? '') === 'https'; }Örnek
X-Real-IPbaşlığını okur; çünkü Nginx bu başlığı her istekte kendi gördüğü adresle yeniden yazar.X-Forwarded-Forise istemcinin gönderdiği değerin sonuna ekleme yapar; listenin başındaki adres sahte olabilir, güvenilir olan vekilinizin eklediği son adrestir.
: Büyüt
Tam örnek yapılandırma
Aşağıdaki dosya önceki adımların tümünü bir araya getirir. Alan adını ve uygulama adresini kendinize göre değiştirin.
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
server {
listen 80;
server_name ornek.com www.ornek.com;
# İstek gövdesi üst sınırı (dosya yükleme)
client_max_body_size 20m;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
# Uygulamanın gerçek alan adını, IP'yi ve şemayı görmesi için
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;
# WebSocket
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
# Zaman aşımları
proxy_connect_timeout 5s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
}
}HTTPS eklemek için Nginx'te HTTPS kurulumu rehberine geçin. HTTPS açıldığında $scheme değişkeni kendiliğinden https olur; başlık satırlarını değiştirmeniz gerekmez. Birden fazla uygulama sunucusuna dağıtım için yük dengeleme rehberine bakın.
Sık yapılan hatalar
- Eğik çizgi uyumsuzluğu:
location /apiileproxy_pass …/birlikte kullanılır; arka uca//yolgider ya da uygulama 404 döner. - Host başlığını unutmak: Uygulama bağlantıları
127.0.0.1:3000adresiyle üretir ya da yanlış siteyi gösterir. - Bir location içinde tek başlık yazmak: Üst düzeydeki diğer
proxy_set_headersatırları o blokta devralınmaz. - WebSocket'i unutmak: Sayfa açılır ama canlı özellikler çalışmaz; tarayıcı konsolunda bağlantı hatası görülür.
- Arka ucu internete açık bırakmak: Uygulama
0.0.0.0dinliyorsa Nginx'teki tüm sınırlar ve erişim kuralları atlanabilir. - Test etmeden yeniden başlatmak: Hatalı yapılandırmayla yeniden başlatma (restart) Nginx'in hiç açılmamasına yol açabilir. Önce
nginx -t, sonra yeniden yükleme. - Uygulamada herkese güvenmek: Güvenilen proxy listesini "tüm adresler" yapmak, başlıkların sahtesinin de kabul edilmesi demektir.
Kurulumu doğrulama
- Sunucunun içinden uygulamayı doğrudan deneyin: yanıt geliyorsa arka uç ayaktadır.
- Aynı isteği alan adıyla Nginx üzerinden deneyin: yanıt aynıysa vekil çalışıyordur.
- Sunucunun dışından
http://sunucu-ip:3000adresinin açılmadığını doğrulayın. - Uygulamanın günlüğünde ziyaretçi IP'sinin
127.0.0.1değil gerçek adres olduğunu kontrol edin. - Sorun varsa Nginx hata günlüğüne bakın; çoğu kurulumda
/var/log/nginx/error.logdosyasıdır.
# Sunucunun içinden: uygulama doğrudan yanıt veriyor mu?
curl -I http://127.0.0.1:3000/
# Nginx üzerinden: alan adıyla aynı yanıt geliyor mu?
curl -I http://ornek.com/
# Hata varsa son günlük satırları (yol çoğu kurulumda böyledir)
sudo tail -n 50 /var/log/nginx/error.logSık sorulan sorular
proxy_pass sonuna eğik çizgi koymalı mıyım?
Uygulamanız isteği hangi yolla bekliyorsa ona göre. Eğik çizgi (ya da başka bir yol) varsa Nginx location ile eşleşen ön eki o yolla değiştirir; yoksa adresi olduğu gibi iletir. Tüm siteyi "location /" ile ilettiğiniz yalın durumda ikisi aynı sonucu verir.
Uygulamam neden tüm ziyaretçileri 127.0.0.1 olarak görüyor?
Çünkü bağlantıyı ziyaretçi değil Nginx kuruyor. X-Real-IP ve X-Forwarded-For başlıklarını Nginx'te iletin, uygulamada da ters vekilinizin adresini güvenilen proxy olarak tanımlayın.
reload ile restart arasındaki fark nedir?
Yeniden yükleme (reload) yapılandırmayı açık bağlantıları koparmadan devreye alır; yapılandırma hatalıysa Nginx eski ayarlarla çalışmayı sürdürür. Yeniden başlatma (restart) Nginx'i durdurup açar; yapılandırma hatalıysa hiç açılmayabilir. Günlük değişikliklerde yeniden yükleme yeterlidir.
Uygulama başka bir sunucudaysa ne değişir?
proxy_pass adresine o sunucunun iç ağ adresini yazarsınız (ör. http://10.0.0.5:3000). Uygulamayı iç ağ adresine dinletin, güvenlik duvarında bağlantı noktasını yalnız Nginx sunucusuna açın ve uygulamadaki güvenilen proxy listesine Nginx sunucusunun iç adresini yazın.
Nginx ile uygulama arasındaki trafik de şifreli olmalı mı?
İkisi aynı sunucudaysa trafik sunucudan çıkmaz; HTTPS'in Nginx'te sonlandırılması (SSL sonlandırma, SSL termination) yaygın ve yeterli bir düzendir. Trafik güvenmediğiniz bir ağdan geçiyorsa arka uç bağlantısını da şifrelemeyi değerlendirin.
BYK Yazılım Destek Ekibi
Bu rehber BYK Yazılım destek ekibi tarafından hazırlanır ve düzenli olarak gözden geçirilir. Son güncelleme: 04.10.2026.
İlgili rehberler
- Reverse proxy (ters vekil) nedir?Ters vekilin görevleri, tipik mimariler, gerçek ziyaretçi IP'si ve başlıklar, CDN ile ilişkisi ve kısa Nginx örneği.
- Nginx'te HTTPS: SSL sertifikası kurulumuNginx'te sertifika alma, HTTPS'e yönlendirme, HSTS, SSL sonlandırma ve otomatik yenileme adımları.
- 502, 504 ve diğer Nginx hataları: nedenleri ve çözümleri502, 504, 413, 499, 403 ve 404 hatalarının anlamı, olası nedenleri, günlüklerle teşhisi ve çözümü.
- Yük dengeleme (load balancing) nedir?İstekleri birden çok sunucuya dağıtmanın mantığı, Nginx upstream ayarları, sağlık kontrolü ve oturum sorunu.
Web sitenizin altyapısını birlikte konuşalım
BYK Yazılım kurumsal web siteleri geliştirir. Sitenizle ilgili sorularınız için bize yazabilirsiniz.
Bize ulaşın Kurumsal web sitesi hizmetimiz