İçeriğe geç
Süreçlerinize uygun yazılımı birlikte planlayalım. Demo ve teklif için arayın: +90 546 737 48 29

TR EN DE

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

  1. Uygulamayı yalnız yerel adrese dinletin

    Nginx ile uygulama aynı sunucudaysa uygulamanın 0.0.0.0 (tüm ağ arayüzleri) yerine 127.0.0.1 adresini dinlemesini sağlayın. Böylece uygulamaya yalnızca aynı sunucudaki Nginx ulaşabilir; kimse Nginx'i atlayıp http://sunucu-ip:3000 adresinden 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.

    Şema: istemci isteği Nginx ters vekile gelir, Nginx proxy_pass ile yalnız yerel adresi dinleyen uygulamaya iletir ve başlıkları ekler : Büyüt
  2. server bloğunu oluşturun

    Nginx'te her site bir server bloğ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 .conf dosyaları yaygın bir düzendir; Debian ve Ubuntu'da /etc/nginx/sites-available/ ile sites-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;
        }
    }

    listen dinlenecek bağlantı noktasını, server_name bu bloğun hangi alan adlarına yanıt vereceğini belirler. location / bloğu tüm adresleri kapsar; içindeki proxy_pass yönergesi (directive) isteğin nereye iletileceğini söyler.

  3. proxy_pass ve sondaki eğik çizgiyi doğru kullanın

    En sık yapılan hata buradadır. proxy_pass adresinde sunucu adından sonra bir yol (tek bir / bile) varsa, Nginx isteğin location ile eşleşen bölümünü bu yolla değiştirir. Yol yoksa istek adresi olduğu gibi iletilir.

    locationproxy_passGelen istekArka 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 location ile proxy_pass yolunu aynı biçimde bitirin: ikisi de eğik çizgiyle bitsin ya da proxy_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ımlanan location bloklarında proxy_pass yol içeremez; Nginx yapılandırma testinde hata verir.

    Karşılaştırma şeması: proxy_pass sonunda eğik çizgi yokken yol aynen iletilir, eğik çizgi varken location ön eki silinir : Büyüt
  4. 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; Host başlığı da proxy_pass'te yazan adres olur. Şu dört başlık bu bilgiyi uygulamaya taşır:

    Nginx
    proxy_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 (http ya da https).

    Dikkat: proxy_set_header yönergeleri üst düzeyden yalnızca o düzeyde hiç proxy_set_header yoksa devralınır. Bir location içine tek bir başlık eklerseniz server düzeyinde yazdıklarınız o blokta geçerliliğini yitirir; hepsini yeniden yazmanız gerekir.

  5. WebSocket desteğini ekleyin

    Canlı sohbet, bildirim ya da anlık pano gibi özellikler WebSocket kullanır. WebSocket, sıradan bir HTTP isteğinin Upgrade baş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;
        }
    }

    map bloğu http düzeyinde (server bloğunun dışında) yer alır: istemci yükseltme istediyse Connection: upgrade, istemediyse Connection: close gönderilmesini sağlar. Böylece aynı location hem normal istekler hem WebSocket için çalışır.

    WebSocket bağlantısında proxy_read_timeout sü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.

    Şema: WebSocket yükseltme isteği Nginx üzerinden Upgrade ve Connection başlıklarıyla uygulamaya iletilir, bağlantı açık kalır : Büyüt
  6. Zaman aşımlarını ve gövde boyutunu ayarlayın

    YönergeNe belirler?Varsayılan
    proxy_connect_timeoutArka uçla bağlantı kurulması için beklenen süre60s
    proxy_send_timeoutİstek arka uca gönderilirken iki yazma işlemi arasındaki en uzun bekleme60s
    proxy_read_timeoutArka uçtan yanıt okunurken iki okuma işlemi arasındaki en uzun bekleme60s
    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 location yazmak, 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.

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

    nginx -t yalnızca sözdizimini ve yönerge bağlamını denetler; arka ucun ayakta olup olmadığına bakmaz. Bu yüzden ardından siteyi curl ile ya da tarayıcıdan deneyin.

    Akış şeması: dosyayı düzenle, nginx -t ile test et, yeniden yükle, curl ile dene, günlükleri kontrol et : Büyüt
  8. 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 isteklerde X-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.1 görünür, IP'ye dayalı oran sınırlama herkesi tek kişi sayar, uygulama kendini http sanı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-IP başlığını okur; çünkü Nginx bu başlığı her istekte kendi gördüğü adresle yeniden yazar. X-Forwarded-For ise istemcinin gönderdiği değerin sonuna ekleme yapar; listenin başındaki adres sahte olabilir, güvenilir olan vekilinizin eklediği son adrestir.

    Karşılaştırma: başlıklar iletilmediğinde uygulama 127.0.0.1 ve http görür; iletilip vekile güvenildiğinde gerçek IP ve https görür : 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.

Nginx
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 /api ile proxy_pass …/ birlikte kullanılır; arka uca //yol gider ya da uygulama 404 döner.
  • Host başlığını unutmak: Uygulama bağlantıları 127.0.0.1:3000 adresiyle üretir ya da yanlış siteyi gösterir.
  • Bir location içinde tek başlık yazmak: Üst düzeydeki diğer proxy_set_header satı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.0 dinliyorsa 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:3000 adresinin açılmadığını doğrulayın.
  • Uygulamanın günlüğünde ziyaretçi IP'sinin 127.0.0.1 değil gerçek adres olduğunu kontrol edin.
  • Sorun varsa Nginx hata günlüğüne bakın; çoğu kurulumda /var/log/nginx/error.log dosyasıdır.
Bash
# 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.log

Sı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

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