Teknoloji

Cloudflare ile WebSocket ve gRPC Yayını Nasıl Hep Canlı Kalır? Nginx Timeout, Keep‑Alive ve Kesintisiz Dağıtımın Sırları

Ofiste Bir Akşam: Sessizce Düşen Bağlantılar

Hiç başınıza geldi mi? Her şey yolunda derken, paneldeki aktif kullanıcı sayısı sabit duruyor ama sohbet odasında ses yok. Loglarda kırmızı alarm da yok, CPU rahat, bellek rahat. Ama bir şeyler eksik. O gün ben de tam bunu yaşadım. WebSocket bağlantıları birer birer düşüyor, gRPC çağrıları ara ara kesiliyor. Üstelik trafiği Cloudflare üzerinden geçiriyorum, arkada Nginx var. Birkaç dakika durup düşündüm: “Bu iş ya timeout, ya da keep‑alive ayarlarından.”

İşin aslı, WebSocket ve gRPC gibi sürekli bağlantı seven servisler, arada bir CDN/proxy katmanı ve arkada bir reverse proxy olduğunda daha nazlı oluyor. Zincirin bir halkası kısa süreliğine bile pes etse, kullanıcı orada kesintiyi hissediyor. Bu yazıda, Cloudflare ile WebSocket ve gRPC trafiğini Nginx üzerinden sorunsuz yayınlamak için neleri ayarladığımı, nerede takıldığımı ve sonunda nasıl huzurla deploy alabildiğimi anlatacağım. Teknik ama göz korkutmayan, pratik ama abartısız gidiyoruz. İsterseniz beraber ilerleyelim.

Cloudflare, WebSocket ve gRPC Üçlüsü Neden Nazlı?

Mesela şöyle düşünün: Tarayıcı bir kere bağlanıyor ve “hadi artık kopmayalım” diyor. WebSocket’te bu tek soket üzerinden konuşmaya devam ediyorsunuz. gRPC’de ise HTTP/2’nin akışlı yapısından yararlanıyorsunuz. Araya Cloudflare gibi bir katman koyduğunuzda bağlantı ikiye çatallanıyor: İstemci ile Cloudflare ve Cloudflare ile origin (Nginx). İki ayrı dünya, iki ayrı ritim. Birinde her şey yolunda olsa bile, diğerinin nabzı düştüğünde kopma hissi oluşuyor.

Cloudflare bu trafiği taşımayı seviyor; fakat kendi limitleri, idle beklentileri ve planlara bağlı davranışları var. O yüzden Nginx tarafındaki timeout ve keep‑alive ayarları, Cloudflare’ın ritmine uymazsa kopmalar sessizce başlıyor. İşin bir güzel yanı var: Birkaç sağlam düzenleme ile bu nazlı üçlü çok tatlı çalışıyor ve dağıtım anlarında bile müşteriden “kopma oldu” mesajı almıyorsunuz.

Nginx’te WebSocket: Upgrade, Timeout ve Keep‑Alive

WebSocket’te kritik nokta, HTTP’den WebSocket’e Upgrade başlıklarını doğru geçirmek. Sonra da bağlantıyı gereksiz yere kısa kesmemek. Benim kafamda şu sıralama oturdu: önce Upgrade başlıkları, sonra proxy_http_version 1.1, ardından proxy_read_timeout ve proxy_send_timeout. Son olarak upstream’te keepalive havuzu ve makul fail ayarları. İş, hem ayarların birlikte çalışmasına hem de değerlerin birbiriyle tutarlı olmasına bakıyor.

Aşağıya pratik bir iskelet bırakıyorum. Rakamları birebir kopyalamak zorunda değilsiniz; sizin trafik deseninize göre yumuşatın. Ama mantık bu akışta kalsın:

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

upstream ws_backend {
    server 127.0.0.1:8080 max_fails=3 fail_timeout=10s;
    keepalive 64;
}

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

    # TLS ayarları (sertifikalar vs.)

    # Genel keep-alive
    keepalive_timeout 65s;
    keepalive_requests 1000;

    location /ws/ {
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $connection_upgrade;

        proxy_read_timeout 3600s;   # Uzun oturumlar için
        proxy_send_timeout 3600s;
        proxy_buffering off;        # WS için tamponlama gereksiz

        proxy_set_header Host $host;
        proxy_pass http://ws_backend;
    }
}

Burada önemli bir püf noktası var: Nginx tarafında bağlantıyı nazikçe uzun tutarken, Cloudflare’ın da kendi tarafında WebSocket trafiğini kabul ettiğinden emin olun. Panelde DNS kaydınızın turuncu bulut ile proxy’lenmiş olması gerekiyor. Cloudflare tarafındaki güncel özellikleri görmek için Cloudflare’ın WebSocket belgelerine bir göz atmanız iyi olur.

Nginx’te gRPC: HTTP/2, Başlıklar ve Stabil Akış

gRPC, HTTP/2’nin üzerine kurulu. Bu yüzden Nginx’te http2 ile dinlemek ve grpc_pass kullanmak gerekiyor. WebSocket’teki gibi “Upgrade” yok, ama uzun yaşayan akışlar var. gRPC’de grpc_read_timeout, grpc_send_timeout ve upstream’te keepalive çok iş görüyor. Bir de servis değişimi sırasında hataya düşmemek için max_fails ve fail_timeout ayarlarıyla nazik davranmak güzel sonuç veriyor.

upstream grpc_backend {
    server 127.0.0.1:50051 max_fails=3 fail_timeout=10s;
    keepalive 64;
}

server {
    listen 443 ssl http2;
    server_name api.example.com;

    # TLS ayarları (sertifikalar vs.)

    # gRPC servis kökü
    location / {
        grpc_pass grpc://grpc_backend;
        grpc_read_timeout 3600s;
        grpc_send_timeout 3600s;
        grpc_set_header Host $host;
    }
}

gRPC tarafında “hangi direktif ne yapar” diye tek tek bakmak isterseniz, resmi referans her zaman yolunuzu aydınlatır. Ben de zaman zaman aklımı tazelemek için Nginx’in gRPC modülü belgelerine dönüp kontrol ediyorum.

Cloudflare Ayarları: HTTP/2, gRPC ve Sessiz Timeouts

Cloudflare, gRPC’yi destekliyor. Panelde ilgili alan adında HTTP/2 açık, gerekli gRPC seçeneği etkin ve kayıt proxy’li olduğunda işler akıyor. Özellikle mobil ağlarda dalgalı bağlantılarda Cloudflare ara katmanının ritmi hayat kurtarıyor. Ama şunu unutmayın: Cloudflare’ın kendi bekleme süreleri ve sınırları var. Bu yüzden Nginx’te gereksiz kısa bir timeout, Cloudflare ile çakıştığında sessiz kesintilere davetiye çıkarıyor.

Benim rutinim şu: Dağıtımdan önce Cloudflare panelinde gRPC’nin açık olduğunu, SSL/TLS modunun Full veya Full (Strict) seviyede olduğunu, HTTP/2’nin aktif olduğunu kontrol ederim. Sonra Nginx tarafında hem okumayı hem yazmayı makul uzun tutar, upstream bağlantı havuzunu ısındırırım. Cloudflare’ın gRPC detaylarına göz atmak isterseniz resmi gRPC dokümantasyonu temiz anlatıyor.

WebSocket cephesinde de benzer bir durum var. Özellikle dayanıksız mobil ağlarda, Cloudflare katmanı kopmaları yumuşatıyor. Ama origin tarafını sabırsız ayarlarsanız, “neden çat diye düştü?” diye log bakarsınız. WebSocket için Cloudflare notlarına tekrar bakmak isterseniz, ilgili başlık burada: Cloudflare WebSocket belgeleri.

Keep‑Alive Mantığı: İki Uçta Aynı Nefes

Keep‑alive’ı “aynı nefesi paylaşmak” gibi düşünün. İstemci Cloudflare ile nefes alıp verirken, Cloudflare da origin’le nefesi senkron tutuyor. Origin tarafında her istekte yeniden TCP/TLS kurulmazsa, gecikme düşer ve dalgalı anlarda daha az kopma yaşarsınız. Nginx’te upstream havuzu için keepalive kullanmak, keepalive_timeout ve keepalive_requests’i mantıklı seviyede tutmak, gidiş‑gelişi rahatlatıyor.

Bir noktayı özellikle seviyorum: Bağlantı havuzunu birkaç dakika önceden ısıtmak. Yeni sürümü ayağa kaldırırken, upstream’e yavaşça trafik verip bağlantıları “uyandırınca” ilk gerçek trafikte o tokat gibi hissedilen gecikmeyi yaşamıyorsunuz. Bu, özellikle gRPC’de akış başlatılırken çok tatlı bir fark yaratıyor.

Kesintisiz Dağıtım: Reload, Drain ve Blue‑Green

Deploy zamanı yaklaşırken ellerin terlediği oldu mu? Özellikle canlı WebSocket bağlantıları varken “nginx -s reload” demek insanın içini hoplatır. Nginx bu işi kibar yapıyor aslında. Yeni konfigürasyonu yüklerken eski işçiler mevcut bağlantıları bitirip kenara çekiliyor. Buna eşlik eden küçük ama etkili ayar: worker_shutdown_timeout. Bu, işçilerin mevcut bağlantıları nazikçe boşaltmasına fırsat veriyor.

events {
    worker_connections 4096;
}

http {
    worker_shutdown_timeout 30s;

    # ... geri kalan ayarlar
}

Blue‑green benzeri bir akış için upstream’i iki gruba ayırıp ağırlıkları yönetebilirsiniz. Şöyle bir iskelet, ağırlığı kademeli değiştirerek sıfıra yakın riskle geçiş yapmanızı sağlar:

upstream grpc_backend {
    zone grpc_backend 64k;
    server 10.0.0.10:50051 weight=1 max_fails=2 fail_timeout=5s;  # Blue
    server 10.0.0.11:50051 weight=0 max_fails=2 fail_timeout=5s;  # Green
    keepalive 64;
}

Yeni sürüm (Green) hazır olunca ağırlığı yavaş yavaş artırırsınız. “Reload” ile konfigürasyonu nazikçe yeniler, gelen akışı yeni sürüme kaydırırsınız. Bir sorun olursa geri dönüş de aynı hızda olur. Ben geçiş sırasında hem origin loglarını hem de Cloudflare analytics ekranını yan yana açmayı alışkanlık edindim. Böylece ufak dalgaları anında görüp frenleyebiliyorum.

Gerçek Bir Senaryo: Sohbet Sunucusunu Geceden Canlıya Almak

Bir gece sohbet sunucusunu yeni sürüme alacağız. Müşteriler uyurken bile içeride sohbet var; yani “trafik yokken alırız” lüksü yok. Önce yeni sürümü ayrı bir upstream’e koyduk. Kendi içinde sağlık kontrollerini geçince, bağlantı havuzunu ısıttık. Ardından ağırlığı yüzdeyle değil, “biraz” ve “biraz daha” gibi küçük adımlarla artırdık. Loglarda garip bir şey görünce ağırlığı geri çektik, küçük bir düzeltme yaptık ve tekrar yükselttik.

WebSocket tarafında proxy tamponlamasını kapatmak ve uzun read timeout vermek güzel sonuç verdi. gRPC tarafında ise akışın başında hafif bir gecikme gördük, bunu da upstream keep‑alive havuzunu büyüterek yumuşattık. En son “reload” ile tüm süreci kalıcı hale getirdik. Kimse kopma hissetmedi, sabah kahvelerimizi rahat içtik.

Sorun Giderme: Loglar, İzler ve Ufak Sinyaller

Doğrusu, sessiz kopmalar en zor olanlar. Loglarda kocaman hata görmezsiniz ama kullanıcı “mesajım niye gitmedi?” der. Böyle anlarda iki araç seti çok yardımcı oldu. İlki, merkezi loglar ve okunabilir seviyede timeout/disk bağlantı mesajları. İkincisi ise isteklerin içinde ufak izler taşımak. İkisinin birleşimi doğru yeri işaret ediyor.

Merkezi loglama tarafını kurmak isterseniz, adım adım notları şu yazıda toplamıştım: Loki ile merkezi loglama kurulumunu buradan inceleyebilirsiniz. İzleri uçtan uca götürmek, özellikle gRPC’de çağrının akışında neler yaşandığını görmek için nefis. Bunun için de OpenTelemetry ile uçtan uca izler yazısındaki örnekler gündelik işte birebir çalışıyor.

Bir pratik ipucu daha: gRPC çağrılarını uçtan uca test ederken canlı trafiği rahatsız etmeden küçük sağlık istekleri kullanın. WebSocket’te ise düşük hacimli ping/pong mekanizması, pasif durumlarda bağlantıların uykuya dalmasını engelliyor. Bu sinyallerin aralığını çok sık ya da çok seyrek tutmadan, “hatlar çalışıyor mu?” diye yoklayan bir ritme oturtmak sorunları daha loga düşmeden yakalıyor.

Güvenlik ve Dengeli Sınırlar

Uzun yaşayan bağlantılarda güvenlik konusu atlanınca, ileride can sıkıcı sürprizlere davetiye çıkıyor. İstemci ile sunucu arasındaki kimlik doğrulama, özellikle iç trafiği korumak istediğinizde, işi bir üst seviyeye taşıyor. Ben bu noktada mTLS’i seviyorum; yönetim arayüzlerinde ve servis‑servis konuşmalarda gerçekten iş görüyor. Detayları adım adım görmek isterseniz, şu rehber epey iştah açıcı: mTLS ile mikroservis doğrulamasını nasıl kurduğumu burada anlattım.

Ağ tarafında da minik dokunuşlar büyük fark yaratıyor. Sadece gereken portları açmak, oran sınırlamayı nazikçe düzenlemek ve beklenmeyen saldırı dalgalarında otomatik frenlemek günlük huzurun gizli sırrı gibi. Adım adım kurmak isterseniz, nftables ile güvenlik duvarı kurallarını anlattığım notlar iyi bir başlangıç oluyor.

Cloudflare Üzerinden gRPC ve WebSocket’te İnce Ayar

Cloudflare panelindeki küçük anahtarlar bazen kader çiziyor. DNS kaydını proxy’li tutmak, HTTP/2’yi açık bırakmak ve gRPC özelliğini etkinleştirmek akışın temelini kuruyor. Bu üçlü var diye her şey sorunsuz mu? Neredeyse. Asıl fark, origin tarafındaki sabırlı davranış. Nginx’te zaman aşımı değerlerini “işinizin doğasına” göre ayarlayın: canlı destek konuşması ile kısa süreli bildirim akışının ritmi aynı değil. Birinde uzun nefes, diğerinde daha hızlı ama yine dengeli nefes gerekiyor.

Cloudflare’ın belgeleri güncel ve pratik. Bir ayar değişti mi, bir limit güncellendi mi, oradan ilk elden görürsünüz. Başlangıç noktası olarak şunu işaretleyeyim; WebSocket için Cloudflare WebSocket belgeleri, gRPC için de Cloudflare gRPC dokümanı işinizi görür.

Nginx Reload’ı Güvenle Almak İçin Küçük Bir Rutin

Ben dağıtım öncesi kısa bir ritüel yapıyorum. Önce yeni upstream’i pasif biçimde ayağa kaldırıyorum. Smoke testleri geçince, birkaç istekle havuzu ısıtıyorum. Ardından ağırlığı küçük adımlarla artırıyorum. Her adımda loglara bakıyorum, Cloudflare analytics’i de yan sekmede açık tutuyorum. İçim rahatsa “nginx -s reload” veya “systemctl reload nginx” diyorum. Eski işçilerin bağlantıları bitirmesine izin veren worker_shutdown_timeout zaten başta ayarlı.

gRPC’de bağlantıların akışını kesmemek için de istemci tarafında kısa bir tekrar deneme mantığı bırakıyorum. Böylece arada tek tük düşen akışlar kullanıcı fark etmeden yeniden bağlanıyor. Bu tekrar deneme işini çok agresif değil, nazik bir aralıkla yapmak iyi sonuç veriyor. Aksi takdirde küçük bir dalga tsunamiye dönüşebiliyor.

İleri Düşünceler: İzlenebilirlik ve Runbook’lar

İşiniz büyüdükçe, “kim neden koptu?” sorusuna cevap bulmak için sadece log yetmiyor. Gözünüzün önünden geçen bir zaman çizgisi lazım. Ben burada izleri ve metrikleri aynı hikayede birleştirmeyi seviyorum. Node ya da PHP fark etmiyor, akışın başından sonuna kadar görünürlük rahatlatıyor. İlham almak isterseniz, OpenTelemetry ile uçtan uca izler yazısı bunu canlı canlı anlatıyor.

Bir de runbook’lar. Gece yarısı kopma olduğunda “hangi sırayla neye bakacağım?” sorusuna cevabınız hazır olmalı. Küçük bir kontrol listesi, Cloudflare paneline nereden bakılacağı, Nginx loglarında hangi anahtar kelimelerin aranacağı ve gerekiyorsa geçici geri dönüş planı… Bunlar konuştuğumuz her şeyi güvenle tekrar edilebilir hale getiriyor.

Hızlı Testler: Küçük Araçlar, Büyük Güven

Sahada şunu fark ettim: Değişiklikten sonra her şeyi uçtan uca test eden ufak komutlar huzur veriyor. WebSocket için basit bir istemci ile bağlanıp birkaç dakika ping/pong yapmak, gRPC için küçük bir test çağrısını peş peşe çalıştırmak ve araya Cloudflare varken davranışı izlemek… Hepsi bir araya gelince “tamam, olabilir” diyorsunuz. Teknik derinlikte boğulmadan, pratik doğrulama adımları işinizi büyütüyor.

gRPC ayarlarını incelerken Nginx’in resmi referansına dönmek iyi bir alışkanlık. Aradığınız bir direktifin ayrıntısı için gRPC modülünün belgeleri hızlıca fikri netleştiriyor. Cloudflare tarafında da değişiklik olduğunda, ilgili sayfalar güncellemeleri açıkça gösteriyor.

Kapanış: Ufak Dokunuşlarla Büyük Huzur

Toparlayalım. Cloudflare ile WebSocket ve gRPC trafiğini Nginx üzerinden yayınlarken asıl mesele, katmanların nefesini uyumlamak. Upgrade başlıkları doğru geçecek, timeout’lar sabırlı olacak, keep‑alive havuzu akışı yumuşatacak. Deploy sırasında reload nazikçe yapılıp eski işçilere veda fırsatı verilecek. Arka planda ise loglar, izler ve minik sağlık sinyalleri işin nabzını tutacak.

Pratik bir tavsiye seti bırakayım: WebSocket’te proxy tamponlamasını kapatın, upgrade başlıklarını unutmayın. gRPC’de HTTP/2’yi dinleyin, read/send timeout’ları işin doğasına göre ayarlayın. Cloudflare panelinde HTTP/2 ve gRPC’nin açık olduğuna eminsiniz. Upstream keep‑alive ile bağlantı havuzunu ısıtın, ağırlıkları küçük adımlarla değiştirin ve reload’ı sakince alın. Güvenlik için mTLS ve temel firewall kurallarıyla akışı sağlamlaştırın. Umarım bu yazı elinizi rahatlattı. Bir dahaki yazıda görüşmek üzere, bol stabil bağlantılar dilerim.

Sıkça Sorulan Sorular

Genelde kısa timeout veya eksik Upgrade başlıkları yüzünden olur. Nginx’te proxy_http_version 1.1, Upgrade/Connection başlıkları ve makul proxy_read_timeout değerlerini kontrol edin. Cloudflare panelinde WebSocket’in aktif ve kaydın proxy’li olduğundan da emin olun.

Sunucuda HTTP/2 ile dinlemek, grpc_pass kullanmak ve grpc_read_timeout/grpc_send_timeout değerlerini akışın süresine göre ayarlamak kritik. Cloudflare tarafında gRPC özelliği ve HTTP/2 açık olmalı, DNS kaydı proxy’lenmiş olmalı.

Nginx’te worker_shutdown_timeout ile eski işçilere nazikçe kapanma süresi verin. Upstream tarafında blue‑green yaklaşımıyla ağırlıkları yavaşça değiştirin, keep‑alive havuzunu önceden ısıtın ve reload’ı adım adım alın. Küçük sağlık kontrolleri ve log takibiyle sorunları anında yakalayın.