Nginx HTTP/3 QUIC Yapılandırma Rehberi
HTTP/2 yayına alındığında "TCP head-of-line blocking" sorunu ortaya çıktı. Tek bir TCP bağlantısı üzerinden çok sayıda eşzamanlı istek taşıyan HTTP/2, bir paket kaybolduğunda bütün stream'lerin beklemesine neden oluyor. Kayıp paket, ona ait olmayan istekleri de blokluyor. QUIC bu sorunu TCP'yi tamamen bırakarak çözüyor. HTTP/3, QUIC üzerine oturuyor. QUIC kendi başına UDP tabanlı bir taşıma protokolü. TLS 1.3'ü protokolün kendisine gömüyor, el sıkışmayı hızlandırıyor ve connection ID tabanlı bağlantı göçüne izin veriyor. Kullanıcı Wi-Fi'dan mobil veriye geçtiğinde bağlantı kopmuyor, sadece yeni yola taşınıyor.
Nginx tarafında HTTP/3 desteği 1.25.0 sürümüyle geldi. Hâlâ deneysel etiketi taşıyor ama üretimde çalışan kurulumlar artık yaygın. 1.25.0'dan beri Linux ikili paketlerinde modül gömülü olarak geliyor, kaynaktan derlemek isteyenler için --with-http_v3_module parametresi işe yarıyor. Derleme yaparken SSL kütüphanesi seçimi kritik. OpenSSL 3.5.1 ve üzeri öneriliyor, yoksa OpenSSL uyumluluk katmanı devreye giriyor ve 0-RTT desteklenmiyor. BoringSSL, LibreSSL veya QuicTLS de kullanılabilir. nginx -V çıktısında --with-http_v3_module görünmüyorsa hiçbir konfigürasyon HTTP/3'ü açamaz.
Binari kontrolü ve derleme
Önce mevcut kurulumun ne olduğuna bak:
nginx -V 2>&1 | grep -o 'http_v3_module' Boş dönüyorsa ya distribüsyon paketinden çıkan sürüm yetersizdir ya da modül derlenmemiştir. Kaynaktan derlerken OpenSSL 3.5.1+ varsa doğrudan kullan:
./configure \
--with-http_v3_module \
--with-http_ssl_module \
--with-http_v2_module \
--with-cc-opt="-I/usr/local/openssl-3.5/include" \
--with-ld-opt="-L/usr/local/openssl-3.5/lib"
make -j"$(nproc)"
sudo make install BoringSSL ile derleyeceksen include ve lib yollarını ona göre ayarla:
./configure \
--with-http_v3_module \
--with-cc-opt="-I../boringssl/include" \
--with-ld-opt="-L../boringssl/build -lstdc++" Çalışan konfigürasyon
Tek bir sanal host için minimal çalışan blok şöyle görünüyor:
server {
listen 443 ssl;
listen 443 quic reuseport;
listen [::]:443 ssl;
listen [::]:443 quic reuseport;
server_name ornek.com;
ssl_certificate /etc/letsencrypt/live/ornek.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/ornek.com/privkey.pem;
ssl_protocols TLSv1.3;
http2 on;
http3 on;
add_header Alt-Svc 'h3=":443"; ma=86400';
root /var/www/ornek.com;
index index.html;
} Tek satırlık kritik detay: reuseport flag'i her port için yalnızca bir listener'da bulunabilir. Varsayılan sunucu olarak işaretlediğin blokta tut, diğer server bloklarında sadece listen 443 quic; kullan. Yoksa nginx start sırasında "duplicate listen" hatası verir.
Alt-Svc header'ı zorunlu. Tarayıcı ilk isteği her zaman TCP üzerinden HTTP/2 ile gönderir. Sunucu bu header ile "aynı portta HTTP/3 de var" bilgisini döner. Tarayıcı sonraki istekleri UDP üzerinden dener. ma=86400 değeri tarayıcının bu bilgiyi 24 saat hatırlamasını sağlar.
Firewall ve kernel tarafı
UDP 443 açık değilse hiçbir şey çalışmaz. Nginx sessizce HTTP/2'ye düşer, hata da vermez. UFW kullanıyorsan:
sudo ufw allow 443/udp firewalld tarafında:
sudo firewall-cmd --permanent --add-port=443/udp
sudo firewall-cmd --reload Bulutta sunucu çalışıyorsa security group içinden de UDP 443'e izin vermek gerekir. Yüksek trafikte UDP buffer boyutlarını büyütmek performansı belirgin şekilde etkiliyor:
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
net.ipv4.udp_rmem_min = 8192
net.ipv4.udp_wmem_min = 8192
net.ipv4.udp_no_check6_tx = 1 udp_no_check6_tx sadece IPv6 için checksum hesaplamasını devre dışı bırakıyor, CPU yükünü azaltıyor. IPv4'te etkisi yok.
QUIC'in kendi ayarları
Modül dışı parametreler Nginx config içinde quic_ prefixiyle ayarlanıyor. Yaygın kullanılanlar:
quic_retry on;
quic_gso on;
quic_host_key /etc/nginx/quic_host.key; quic_retry on amplification saldırılarına karşı koruma sağlıyor. İstemciye önce UDP alabildiğini kanıtlamasını istiyor, sonra tam bağlantı kuruluyor. Public internete açık her sunucuda açık tutulmalı.
quic_gso on Generic Segmentation Offloading'i etkinleştiriyor. NIC GSO destekliyorsa paket gönderme performansı artıyor. Aksi halde zararsız.
quic_host_key bağlantı ID'lerini şifrelemek için kalıcı anahtar tutuyor. Belirtilmezse her restartta yenisi üretilir ve restart öncesi kurulan bağlantılar anında ölür. Üretim ortamında mutlaka sabit bir dosya gösterin.
0-RTT aktif etmek için ek olarak ssl_early_data on; gerekli. OpenSSL 3.5.1 öncesi sürümlerde bu direktif ne olursa olsun 0-RTT çalışmıyor, modül OpenSSL 3.5.1+ ile QUIC-aware hale geliyor. 0-RTT açmak "replay attack" yüzeyini genişlettiği için dikkatli değerlendirilmeli, idempotent GET isteklerinde anlamlı.
Log ve doğrulama
HTTP/3 trafiğini normal access log'dan ayırmak için ayrı format tanımla:
log_format quic '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent" "$http3"';
access_log /var/log/nginx/access_quic.log quic; $http3 değişkeni bağlantının h3 ile kurulduğunda "h3", h3 olmayanlarda boş döner. QUIC'in gerçekten çalıştığını buradan teyit et.
Tarayıcıdan bakarken DevTools Network sekmesinde protokol sütununda "h3" görünmeli. curl ile test etmek için HTTP/3 destekli sürüm gerekiyor:
curl --http3 -I https://ornek.com Çıktıda HTTP/3 200 dönüyorsa her şey yerinde. Tarayıcılar başlangıçta şüpheci davranır, sertifika zincirinde eksik varsa QUIC'e hiç geçmez. Bu yüzden Let's Encrypt gibi tam zincir sağlayan bir CA kullan, intermediateları eksik bırakma.
Üretimde gözlemlediğim birkaç tuhaflık
Birincisi reload davranışı. TCP listener'lar nginx -s reload sırasında kesintisiz devam eder ama QUIC listener'ların yeniden bind edilmesi bazı kernel yapılandırmalarında kısa süreli kesinti yaratıyor. Kernel 5.x ve üzeri, tek worker yapılandırmasında bu sorun neredeyse görünmüyor ama multi-worker kurulumlarda reload sırasında birkaç saniyelik QUIC kesintisi yaşanabilir. Kritik servislerde restart penceresini planlı tut.
İkincisi CDN arkasında çalışma. Cloudflare gibi bir CDN kullanıyorsan HTTP/3'ü origin'de açmak anlamlı değil, çünkü istemci ile CDN arasında zaten h3 kullanılıyor. Origin'de HTTP/3 açmanın faydası, istemcinin doğrudan sunucuna bağlandığı durumda ortaya çıkıyor.
Üçüncüsü quic_session_migration. Varsayılan olarak açık. Yük dengeleyici arkasındaki backend'lere yönlendirme yapıyorsan ve connection ID tabanlı takip kullanmıyorsan kapatmak isteyebilirsin, aksi halde istemcinin IP'si değiştiğinde bağlantı backend'de asılı kalıyor.
HTTP/3 kurulumu gerçekten çalıştığında hissedilir fark yaratıyor. Özellikle mobil ağlarda ve paket kaybının yaygın olduğu uzak bölgelerde sayfa yüklenme süreleri belirgin düşüyor. TCP'in bıraktığı yerden QUIC devralıyor, Nginx tarafında da konfigürasyonu artık birkaç satır.