Hizmetler Hosting & Sunucu Araçlar Blog Ara Kurumsal EnglishEN
Teklif Alın

Bir Node.js uygulamasını canlıya almak ya da statik bir HTML siteyi sunucuya taşımak istediğinizde er ya da geç bir Nginx server block yazmanız gerekir. Doğru yazılmış bir server block hem isteği doğru alan adına bağlar hem de arka plandaki uygulamanın istemci hakkında doğru bilgiye (gerçek IP, protokol, host adı) sahip olmasını sağlar. Eksik yazılmış bir server block ise genellikle sessizce yanlış çalışır: erişim logları herkesi aynı IP'den gösterir, HTTPS yönlendirmeleri bozulur ya da istek hiç beklenen yere ulaşmaz.

Server Block Nedir, Nginx Hangi Bloğu Seçer?

Tek bir sunucuda birden fazla alan adı ya da uygulama barındırmak istediğinizde, Nginx'in gelen isteği hangi siteye yönlendireceğini bilmesi gerekir. Bu işi server block yapısı üstlenir: server { ... } direktifiyle tanımlanan, belirli bir server_name ve listen kombinasyonuna gelen istekleri karşılayan yapılandırma birimi. Apache kullananlar için bu, "virtual host" kavramının karşılığıdır.

Debian/Ubuntu tabanlı sistemlerde her server block genellikle /etc/nginx/sites-available/ altında ayrı bir dosya olarak yazılır. Ancak bir dosyanın orada bulunması onu otomatik olarak etkinleştirmez — yalnızca /etc/nginx/sites-enabled/ içine sembolik link (symlink) olarak eklenen bloklar fiilen çalışır. Bu iki dizinli yapı, bir siteyi devre dışı bırakmayı, dosyayı silmeden yalnızca symlink'i kaldırarak yapmayı mümkün kılar.

Nginx bir istek aldığında eşleştirmeyi iki aşamada yapar. Önce isteğin geldiği IP ve port'u (listen direktifi) karşılayan server block'ları belirler; aynı port üzerinde birden fazla blok tanımlı olabilir. Ardından bu bloklar arasından, isteğin Host başlığındaki alan adını server_name ile eşleştirmeye çalışır. Hiçbir server_name eşleşmezse Nginx, o port için tanımlanan ilk server block'u (ya da açıkça default_server olarak işaretlenmiş bloğu) kullanır. Bu davranış, birden fazla site tanımlıyken "tarayıcıda beklenmedik bir site açılıyor" sorununun en sık kaynağıdır.

Statik Site Sunumu: root, index, try_files

Bir server block dosyaları doğrudan diskten sunacaksa arka planda çalışan bir uygulama sunucusuna ihtiyaç yoktur; Nginx isteği kendisi karşılar. root direktifi dosyaların bulunduğu dizini belirtir, index ise URL bir dizine işaret ettiğinde hangi dosyanın varsayılan olarak sunulacağını (index.html gibi) tanımlar.

try_files $uri $uri/ =404; satırı statik sunumun can damarıdır: Nginx önce isteği birebir bir dosya olarak dener ($uri), bulamazsa bir dizin olarak dener ($uri/, bu durumda index dosyasına düşer), o da yoksa 404 döner. Bu sıralama sayesinde var olmayan bir dosya için Nginx doğrudan hata döner; bir yorumlayıcıya ya da uygulamaya hiç düşmez.

server {
    listen 80;
    listen [::]:80;
    server_name example.com;

    root /var/www/example.com/html;
    index index.html index.htm;

    location / {
        try_files $uri $uri/ =404;
    }
}

Reverse Proxy: proxy_pass ve Başlıkların Önemi

Site statik dosyalardan değil de arka planda çalışan bir uygulamadan (Node.js/Express, Django, Rails vb.) besleniyorsa Nginx'in rolü değişir: isteği kendisi karşılamaz, arka plandaki uygulamaya iletir ve dönen yanıtı istemciye geri taşır. Bu modele reverse proxy denir ve proxy_pass direktifiyle kurulur — örneğin 127.0.0.1:3000 portunda dinleyen bir Node.js uygulamasına proxy_pass http://127.0.0.1:3000; ile bağlanılır. Bu ayrım, TLS sonlandırma, sıkıştırma, statik dosya önbellekleme ve yük dengeleme gibi işleri uygulama kodundan tamamen ayırmayı sağlar; uygulama yalnızca iş mantığıyla uğraşır.

Tek başına proxy_pass yeterli değildir; aşağıdaki başlıklar iletilmezse arka plandaki uygulama isteğin gerçek kaynağı hakkında yanlış bilgiye sahip olur:

  • proxy_set_header Host $host; — arka plan uygulamasının, istemcinin hangi alan adına istek attığını görmesini sağlar.
  • proxy_set_header X-Real-IP $remote_addr; — istemcinin gerçek IP adresini taşır; bu olmadan uygulama tüm istekleri Nginx'in kendi adresinden geliyormuş gibi görür.
  • proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; — istek bir proxy zincirinden geçtiyse geçtiği IP'lerin listesini tutar.
  • proxy_set_header X-Forwarded-Proto $scheme; — istemciyle Nginx arasında HTTP mi HTTPS mi konuşulduğunu arka plana bildirir.

Son başlık özellikle kritiktir. Nginx istemciyle HTTPS üzerinden konuşsa bile arka plandaki uygulamaya isteği genellikle düz HTTP olarak iletir. X-Forwarded-Proto başlığı olmadan uygulama isteğin şifresiz geldiğini sanabilir; bu da secure cookie'lerin ayarlanmamasına, https:// yerine http:// yönlendirmeleri üretilmesine ya da "mixed content" hatalarına yol açar. Express, Django, Rails gibi çoğu framework bu başlığı okuyup isteğin gerçek protokolünü buna göre belirler — ancak uygulama tarafında da genellikle "trust proxy" benzeri bir ayarın açık olması gerekir, aksi halde framework başlığı görse bile güvenmez.

WebSocket kullanan uygulamalarda (canlı bildirim, sohbet, sıcak yeniden yükleme gibi) proxy_http_version 1.1; ile birlikte Upgrade ve Connection başlıklarının da iletilmesi gerekir; aksi halde bağlantı sıradan bir HTTP isteğine düşürülür ve WebSocket el sıkışması başarısız olur.

server {
    listen 80;
    listen [::]:80;
    server_name app.example.com;
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl;
    listen [::]:443 ssl;
    server_name app.example.com;

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

    location / {
        proxy_pass http://127.0.0.1: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;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }
}

SSL/TLS Sonlandırma

HTTPS kullanan bir sitede sertifika işini genellikle Nginx üstlenir; buna TLS sonlandırma (SSL termination) denir. İstemci Nginx'e şifreli bağlanır, Nginx trafiği çözer ve — statik modda doğrudan dosyaları sunarken, proxy modunda ise çoğunlukla düz HTTP olarak — arka plana iletir. Sertifika ve özel anahtar ssl_certificate ve ssl_certificate_key direktifleriyle tanımlanır; Let's Encrypt kullanılıyorsa bu dosyalar tipik olarak /etc/letsencrypt/live/<alan-adı>/fullchain.pem ve privkey.pem yollarında bulunur.

Pratikte yalnızca 443 üzerinde SSL dinleyen bir server block yeterli değildir; 80 portunu da dinleyip tüm HTTP trafiğini return 301 https://$host$request_uri; ile HTTPS'e yönlendiren ikinci bir blok eklemek, sitenin şifresiz erişime açık kalmamasını sağlar. Yukarıdaki reverse proxy örneğinde bu iki blok bir arada gösterilmiştir: ilki yönlendirme yapar, ikincisi sertifikayı sonlandırıp isteği uygulamaya taşır.

Sık Yapılan Hatalar

HataSonuç ve çözüm
proxy_pass sonundaki eğik çizgi eksik/fazlaproxy_pass http://backend/; location ile eşleşen ön eki isteğin URI'sinden siler ve geri kalanını iletir; proxy_pass http://backend; (eğik çizgisiz) ise orijinal URI'yi olduğu gibi iletir. İkisini karıştırmak, backend'e giden yolun beklenmedik şekilde değişmesine yol açar.
Proxy başlıkları hiç ayarlanmıyorUygulama tüm istekleri Nginx'in kendi adresinden (genellikle 127.0.0.1) geliyormuş gibi görür; erişim logları gerçek istemci IP'lerini değil sürekli aynı yerel IP'yi gösterir. X-Real-IP ve X-Forwarded-For eklenmeden bu düzelmez.
Aynı listen + server_name için birden fazla blokİki server block aynı listen ve server_name kombinasyonunu tanımlarsa Nginx başlatılırken "conflicting server name" uyarısı verir ve yalnızca ilk yüklenen bloğu kullanır; diğeri sessizce devre dışı kalır.
Yapılandırma değiştirildikten sonra reload unutuluyorDosyayı kaydetmek tek başına yeterli değildir; değişiklik ancak Nginx yeniden yüklenince devreye girer. Önce sudo nginx -t ile sözdizimi test edilmeli, hata yoksa sudo systemctl reload nginx ile (aktif bağlantıları kesmeden) uygulanmalıdır.

Yapılandırmayı oluşturduktan sonra dosyayı /etc/nginx/sites-available/<alan-adı> olarak kaydedin, ardından sudo ln -s /etc/nginx/sites-available/<alan-adı> /etc/nginx/sites-enabled/ komutuyla etkinleştirin. Devreye almadan önce sözdizimini test etmeyi ve ardından restart yerine reload kullanmayı alışkanlık hâline getirmek, çoğu canlı ortam kesintisinin önüne geçer.

Yeni bir server block yazarken direktifleri elle satır satır kurmak yerine, doğru sırayı ve gerekli proxy başlıklarını otomatik üreten bir araç kullanmak yukarıdaki hataların çoğunu baştan önler.

WhatsApp