Rehber 08 Mayıs 2026 · 5 dakika okuma

WebSocket Nginx Yapılandırması: Production'da Kopma Sorunlarını Önleme

WebSocket bağlantılarınız nginx arkasında kopuyorsa sorun büyük olasılıkla config'de. Upgrade başlığı, timeout, WSS ve load balancing için net teknik rehber.

WebSocket sunucusu nginx arkasında çalıştırıldığında sıradan HTTP reverse proxy yapılandırması yetmez. HTTP Upgrade mekanizması, uzun süreli açık bağlantılar ve çok sunuculu senaryolar nginx'te standart dışı ayarlar gerektirir. Pek çok kurulum temel handshake'i geçer ama dakikalar içinde kopan bağlantılar, yük dengeleme sorunları veya WSS hataları yaşar. Bu rehberde temel proxy config'inden SSL sonlandırmaya, timeout yönetiminden load balancing'e kadar production için kritik her ayarı somut örneklerle ele alacağız.

WebSocket Nginx'te Neden Özel Yapılandırma İster?

HTTP/1.1 tabanlı WebSocket protokolü bağlantıyı standart bir HTTP isteğiyle başlatır; ancak bu istek Connection: Upgrade ve Upgrade: websocket başlıklarını taşır. Nginx bu başlıkları varsayılan olarak downstream proxy'ye iletmezConnection başlığını siler, Upgrade başlığını boşaltır. Sonuç: WebSocket handshake başarısız olur, istemci 101 Switching Protocols yerine 400 ya da 502 alır.

Buna ek olarak iki önemli fark daha vardır:

  • Uzun süreli bağlantı: HTTP isteği saniyeler içinde tamamlanır; WebSocket bağlantısı saatlerce açık kalabilir. Nginx'in varsayılan proxy_read_timeout değeri 60 saniyedir — aktivite olmayan WebSocket bağlantısını bu süre dolunca keser.
  • Durum bilgisi (stateful): Birden fazla backend sunucu varsa, aynı istemcinin her isteğinin aynı sunucuya ulaşması gerekir. Nginx'in varsayılan round-robin algoritması bunu garanti etmez.

Temel WebSocket Proxy Yapılandırması

Çalışan minimum bir WebSocket nginx config'i şu üç ek ayar olmadan tamamlanmaz:

http {
    map $http_upgrade $connection_upgrade {
        default upgrade;
        ''      close;
    }

    server {
        listen 80;
        server_name ws.example.com;

        location /ws/ {
            proxy_pass         http://websocket_backend;
            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;
        }
    }

    upstream websocket_backend {
        server 127.0.0.1:3000;
    }
}

proxy_http_version 1.1 zorunludur. HTTP/1.0, Connection: Upgrade başlığını desteklemez; bu satır olmadan handshake hiç başlamaz.

map bloğu iki işlev üstlenir: WebSocket isteği geldiğinde ($http_upgrade dolu) Connection değerini upgrade olarak ayarlar; istek normal HTTP ise ($http_upgrade boş) değeri close yapar. Aynı location'dan hem WebSocket hem HTTP trafiği geçiyorsa bu ayrım gereklidir.

Upgrade ve Connection başlıklarının proxy_set_header ile açıkça iletilmesi handshake'in nginx'ten backend'e eksiksiz ulaşmasını sağlar.

Bağlantı Kopmasını Önleyen Timeout Ayarları

Production ortamında en sık şikayet kaynağı budur: bağlantı kurulur, bir süre çalışır, sonra sessizce düşer. Nedeni çoğunlukla nginx timeout değerleridir.

Direktif Varsayılan WebSocket İçin Önerilen
proxy_read_timeout 60s 3600s
proxy_send_timeout 60s 3600s
proxy_connect_timeout 60s 10s (değiştirme)
location /ws/ {
    proxy_pass         http://websocket_backend;
    proxy_http_version 1.1;

    proxy_set_header Upgrade    $http_upgrade;
    proxy_set_header Connection $connection_upgrade;

    proxy_read_timeout 3600s;
    proxy_send_timeout 3600s;
}

proxy_connect_timeout backend'e ilk TCP bağlantısı içindir; artırmanın anlamı yoktur — backend yanıt vermiyorsa uzun beklemek sorunu çözmez, sadece hata gecikmesini uzatır.

Timeout yeterli değildir. Nginx ile backend arasındaki ara güvenlik duvarları veya NAT cihazları kendi idle timeout politikalarını uygular ve WebSocket bağlantısını nginx'e haber vermeden keser. Buna karşı önlem uygulama katmanında ping/pong kullanmaktır: her 30–45 saniyede bir ping çerçevesi göndermek bağlantıyı aktif tutar.

SSL/WSS Yapılandırması

HTTPS kullanan bir sitede WebSocket ws:// yerine wss:// protokolüyle kurulur. SSL sonlandırma nginx'te yapılıyorsa backend'e düz ws:// ile iletim yeterlidir; nginx TLS'yi uygulama sunucusu adına yönetir.

server {
    listen 443 ssl;
    server_name ws.example.com;

    ssl_certificate     /etc/letsencrypt/live/ws.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/ws.example.com/privkey.pem;
    ssl_protocols       TLSv1.2 TLSv1.3;
    ssl_ciphers         HIGH:!aNULL:!MD5;

    location /ws/ {
        proxy_pass         http://127.0.0.1:3000;
        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-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;

        proxy_read_timeout 3600s;
        proxy_send_timeout 3600s;
    }
}

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

X-Forwarded-Proto başlığını eklemek zorunludur. Uygulama bu başlığı okuyarak bağlantının HTTPS üzerinden geldiğini anlar ve kendi ürettiği URL'leri ws:// yerine wss:// olarak oluşturur. Bu başlık eksik olduğunda bazı framework'ler mixed content hatası üretir.

Load Balancing: ip_hash Neden Zorunludur?

Birden fazla backend sunucu çalıştırıyorsanız nginx'in varsayılan round-robin algoritması WebSocket'te oturum (session) tutarsızlığına yol açar.

Senaryo: İstemci WebSocket bağlantısını backend A'ya kurar, uygulama bu bağlantıya ait state'i A'da depolar. Bağlantı kopup yeniden kurulduğunda nginx isteği backend B'ye gönderir; B'nin bu istemciyle ilgili hiçbir bilgisi yoktur. Kimlik doğrulama başarısız olur ya da oturum sıfırlanır.

Çözüm ip_hash ile aynı istemci IP'sini her zaman aynı backend'e yönlendirmektir:

upstream websocket_backend {
    ip_hash;
    server 127.0.0.1:3000 max_fails=3 fail_timeout=30s;
    server 127.0.0.1:3001 max_fails=3 fail_timeout=30s;
    server 127.0.0.1:3002 max_fails=3 fail_timeout=30s;
}

ip_hash sınırlaması: Çok sayıda kullanıcı aynı NAT arkasından (kurumsal ağ, mobil operatör) bağlanıyorsa tüm bu kullanıcılar tek bir backend'e yığılır ve yük dengesi bozulur. Bu durumda iki alternatif vardır:

  • Redis Pub/Sub ile state paylaşımı: Tüm backend'ler ortak bir Redis'e yazarsa hangi backend'e düşülürse düşülsün state korunur; ip_hash zorunluluğu ortadan kalkar.
  • Cookie tabanlı yönlendirme: nginx Plus veya üçüncü taraf sticky modülü kullanılarak ilk WebSocket bağlantısında istemciye backend kimliği içeren bir cookie atanır.

Buffer Ayarları ve Boyut Optimizasyonu

WebSocket mesajları küçük (ping/pong, JSON event) veya büyük (dosya transfer, video chunk) olabilir. Nginx'in varsayılan buffer boyutları küçük HTTP yanıtları için ayarlanmıştır; büyük WebSocket mesajlarında disk geçici dosya yazımı (proxy_temp_path) devreye girer ve gecikme artar.

location /ws/ {
    proxy_pass         http://websocket_backend;
    proxy_http_version 1.1;

    proxy_set_header Upgrade    $http_upgrade;
    proxy_set_header Connection $connection_upgrade;

    proxy_read_timeout  3600s;
    proxy_send_timeout  3600s;

    proxy_buffering    off;
    proxy_buffer_size  4k;
}

proxy_buffering off WebSocket için en temiz seçenektir: nginx mesajları buffer'lamadan doğrudan istemciye iletir, gecikme düşer. Bu ayar aktifken proxy_buffer_size sadece response başlığı için geçerli olur; 4k standart başlıklar için yeterlidir.

Yalnızca büyük binary yük aktarımı yapan bir WebSocket uygulamasında (örneğin canlı video) proxy_buffering on ile birlikte proxy_buffers 16 64k; proxy_buffer_size 64k; kombinasyonu throughput'u artırabilir. İki seçeneği kendi yük tipinize göre kıyaslayın.

Sorun Giderme: Config Test ve Log Analizi

Yapılandırma değişikliklerini production'a almadan önce sözdizimini doğrulayın:

nginx -t

nginx: configuration file /etc/nginx/nginx.conf test is successful çıktısını görmeden systemctl reload nginx çalıştırmayın; hatalı config nginx'i başlatamaz duruma getirebilir.

WebSocket bağlantı sorunlarını hızlı ayıklamak için access log formatını genişletin:

log_format ws_debug '$remote_addr [$time_local] "$request" '
                    'status=$status upgrade="$http_upgrade" '
                    'upstream=$upstream_addr';

access_log /var/log/nginx/ws.log ws_debug;

Durum kodlarının anlamı:

HTTP Durum Kodu Anlam
101 Handshake başarılı, WebSocket aktif
400 Upgrade başlığı eksik veya hatalı — config sorunu
502 Backend ulaşılamaz veya port kapalı
504 proxy_read_timeout doldu — timeout değeri artırılmalı

Gerçek zamanlı izleme için 101 dışındaki kodları filtreleyin:

tail -f /var/log/nginx/ws.log | grep -v ' status=101 '

Eğer $http_upgrade alanı log'da boş geliyorsa istemci tarafı WebSocket isteği doğru göndermiyor demektir; sunucu config'inden önce istemci kodunu kontrol edin.

Sonuç

WebSocket'i nginx arkasında kararlı biçimde çalıştırmak için dört ayar kritiktir: Upgrade/Connection başlıklarının iletilmesi, proxy_read_timeout değerinin artırılması, wss:// için doğru SSL yapılandırması ve çok sunuculu ortamda ip_hash kullanımı. Bu dört nokta eksik veya yanlış olduğunda bağlantılar ya hiç kurulamaz ya da düzensiz aralıklarla kopar.

Yapılandırmanızı hazırladıktan sonra nginx -t ile sözdizimini doğrulayın, systemctl reload nginx ile uygulayın ve genişletilmiş log formatıyla ilk bağlantıları izleyin. Production'a geçmeden önce yüksek gecikme, VPN ve mobil ağ koşullarında bağlantı kararlılığını test etmek, sonradan yaşanacak kopma şikayetlerinin büyük bölümünü önceden önler.

Etiketler: #websocket #nginx #sunucu yapılandırması #reverse proxy #ssl #wss #load balancing #vds #vps

Hosting karşılaştırması yapmaya hazır mısın?

100+ firmanın fiyatlarını tek tıkla karşılaştır, en uygun paketi bul.

Hosting Karşılaştır →

İlgili Yazılar

0 ürün seçildi
NetKıyas AI
Hosting danışmanınız
Merhaba! Ben NetKıyas yapay zekâ asistanı. Hosting, VDS, VPS veya sunucu seçiminde size yardımcı olabilirim. Ne arıyorsunuz?