Nginx’te HTTP/2 ve HTTP/3 QUIC Protokollerini Aktifleştirme

Modern web uygulamalarında hız artık bir lüks değil, zorunluluk. Kullanıcılar sayfaların anında yüklenmesini bekliyor, Google ise Core Web Vitals metrikleriyle performansı doğrudan sıralama faktörü olarak değerlendiriyor. İşte bu noktada HTTP/2 ve HTTP/3 QUIC devreye giriyor. Nginx üzerinde bu protokolleri aktifleştirmek, mevcut altyapınızı köklü biçimde değiştirmeden ciddi performans kazanımları elde etmenizi sağlıyor. Bu yazıda sıfırdan başlayarak production ortamında güvenle uygulayabileceğiniz adımları ele alacağız.

HTTP/2 ve HTTP/3 Nedir, Neden Önemlidir?

HTTP/1.1 yıllarca web’in omurgasını oluşturdu ama çok sayıda kısıtlamayla birlikte geldi. Her istek için ayrı TCP bağlantısı açma zorunluluğu, head-of-line blocking sorunu ve başlıkların sıkıştırılmaması, modern web sitelerinin karmaşıklığıyla boğuşurken ciddi darboğazlar yaratıyordu.

HTTP/2 bu sorunların büyük bölümünü çözdü:

  • Tek TCP bağlantısı üzerinden çoklu istek gönderme (multiplexing)
  • HPACK algoritmasıyla başlık sıkıştırma
  • Server push desteği
  • Binary framing katmanı ile daha verimli veri iletimi

HTTP/3 QUIC ise daha ileriye gidiyor. TCP’yi tamamen bırakıp UDP üzerine inşa edilmiş QUIC protokolünü kullanıyor. Bunun pratik anlamı şu: TCP’nin üç yönlü el sıkışması (three-way handshake) yerine sıfır RTT bağlantı kurulumu mümkün hale geliyor. Özellikle mobil ağlarda paket kaybı yaşandığında HTTP/2’nin TCP katmanındaki tıkanmadan etkilendiği head-of-line blocking sorunu HTTP/3’te ortadan kalkıyor.

Ön Gereksinimler ve Sistem Kontrolü

Nginx Sürüm Kontrolü

HTTP/2 desteği Nginx 1.9.5 sürümüyle geldi. HTTP/3 desteği ise 1.25.0 sürümüyle kararlı ana dalda yerini aldı. Önce mevcut sürümünüzü kontrol edin:

nginx -v
nginx -V 2>&1 | grep -o with-http_v2_module
nginx -V 2>&1 | grep -o with-http_v3_module

Eğer with-http_v2_module çıktısını görüyorsanız HTTP/2 için hazırsınız demektir. HTTP/3 için with-http_v3_module çıktısı şart. Paket yöneticinizden kurulu Nginx bu modüllere sahip olmayabilir. Özellikle HTTP/3 için büyük ihtimalle Nginx’i kaynak koddan derlemeniz veya resmi Nginx repo’sundan güncel sürümü kurmanız gerekecek.

Resmi Nginx Deposundan Kurulum

Ubuntu/Debian için:

curl https://nginx.org/keys/nginx_signing.key | gpg --dearmor 
    | sudo tee /usr/share/keyrings/nginx-archive-keyring.gpg >/dev/null

echo "deb [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg] 
http://nginx.org/packages/mainline/ubuntu $(lsb_release -cs) nginx" 
    | sudo tee /etc/apt/sources.list.d/nginx.list

sudo apt update
sudo apt install nginx
nginx -V 2>&1 | grep -E "http_v2|http_v3"

CentOS/RHEL için:

sudo tee /etc/yum.repos.d/nginx.repo <<EOF
[nginx-mainline]
name=nginx mainline repo
baseurl=http://nginx.org/packages/mainline/centos/$releasever/$basearch/
gpgcheck=1
enabled=1
gpgkey=https://nginx.org/keys/nginx_signing.key
module_hotfixes=true
EOF

sudo yum install nginx
nginx -V 2>&1 | grep -E "http_v2|http_v3"

SSL Sertifikası Gerekliliği

HTTP/2 ve HTTP/3 protokolleri tarayıcılar tarafından yalnızca HTTPS bağlantıları üzerinde destekleniyor. Bu nedenle geçerli bir SSL sertifikasına ihtiyacınız var. Let’s Encrypt ile ücretsiz sertifika almak için:

sudo apt install certbot python3-certbot-nginx
sudo certbot --nginx -d sizindomain.com -d www.sizindomain.com

HTTP/2 Aktifleştirme

Temel HTTP/2 Konfigürasyonu

HTTP/2 aktifleştirmek son derece basit. Nginx 1.25.1 ve sonrasında listen direktifine http2 parametresi ekliyorsunuz:

server {
    listen 443 ssl;
    http2 on;
    
    server_name sizindomain.com www.sizindomain.com;
    
    ssl_certificate /etc/letsencrypt/live/sizindomain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/sizindomain.com/privkey.pem;
    
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256;
    ssl_prefer_server_ciphers off;
    
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 1d;
    ssl_session_tickets off;
    
    add_header Strict-Transport-Security "max-age=63072000" always;
    
    location / {
        root /var/www/sizindomain;
        index index.html index.htm;
    }
}

# HTTP'yi HTTPS'e yönlendir
server {
    listen 80;
    server_name sizindomain.com www.sizindomain.com;
    return 301 https://$host$request_uri;
}

Eski Nginx sürümlerinde (1.25.1 öncesi) listen satırına http2 eklemeniz gerekiyordu:

listen 443 ssl http2;

Konfigürasyonu test edip Nginx’i yeniden yükleyin:

sudo nginx -t
sudo systemctl reload nginx

HTTP/2 Performans Parametreleri

HTTP/2 aktif olduğunda bazı ek parametreleri de ayarlamak faydalı:

http {
    # HTTP/2 için bağlantı başına maksimum eşzamanlı push sayısı
    http2_max_concurrent_pushes 10;
    
    # İstek body boyutu sınırı
    client_max_body_size 50M;
    
    # Keepalive bağlantıları için timeout
    keepalive_timeout 65;
    
    # Gzip sıkıştırma - HTTP/2 ile birlikte kullanmak verimlidir
    gzip on;
    gzip_vary on;
    gzip_proxied any;
    gzip_comp_level 6;
    gzip_types text/plain text/css text/xml application/json application/javascript application/xml+rss application/atom+xml image/svg+xml;
    
    server {
        listen 443 ssl;
        http2 on;
        # ... diğer direktifler
    }
}

HTTP/3 QUIC Aktifleştirme

HTTP/3 konfigürasyonu HTTP/2’ye kıyasla biraz daha karmaşık. QUIC’in UDP üzerinde çalıştığını ve bazı ek başlıklar gerektirdiğini göz önünde bulundurmanız gerekiyor.

Temel HTTP/3 Konfigürasyonu

server {
    # HTTP/2 için TCP 443
    listen 443 ssl;
    http2 on;
    
    # HTTP/3 için UDP 443
    listen 443 quic reuseport;
    
    server_name sizindomain.com www.sizindomain.com;
    
    ssl_certificate /etc/letsencrypt/live/sizindomain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/sizindomain.com/privkey.pem;
    
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305;
    ssl_prefer_server_ciphers off;
    
    # HTTP/3 için gerekli başlık
    add_header Alt-Svc 'h3=":443"; ma=86400';
    
    # QUIC early data için 0-RTT
    ssl_early_data on;
    
    location / {
        root /var/www/sizindomain;
        index index.html;
    }
}

Alt-Svc Başlığı Neden Kritik?

Alt-Svc (Alternative Service) başlığı, tarayıcıya HTTP/3’ün mevcut olduğunu bildiriyor. Tarayıcı ilk bağlantıyı TCP üzerinden kuruyor, bu başlığı görüyor ve sonraki isteklerde UDP/QUIC üzerinden bağlanmaya çalışıyor. ma=86400 parametresi bu bilginin 24 saat önbelleğe alınacağını belirtiyor.

Güvenlik Duvarı Ayarları

HTTP/3 UDP 443 portunu kullandığından güvenlik duvarınızda bu porta izin vermeniz gerekiyor:

# UFW kullananlar için
sudo ufw allow 443/udp
sudo ufw status

# firewalld kullananlar için
sudo firewall-cmd --permanent --add-port=443/udp
sudo firewall-cmd --reload

# iptables kullananlar için
sudo iptables -A INPUT -p udp --dport 443 -j ACCEPT
sudo iptables-save > /etc/iptables/rules.v4

0-RTT Early Data Güvenlik Notu

ssl_early_data on ayarı bağlantı kurulumunu hızlandırıyor ancak replay saldırılarına karşı dikkatli olunması gerekiyor. Özellikle POST isteklerinde bu riski yönetmek için şu önlemi alın:

location /api/ {
    # Early data ile gelen POST isteklerini reddet
    if ($ssl_early_data) {
        return 425;
    }
    proxy_pass http://backend;
}

Gerçek Dünya Senaryosu: E-Ticaret Sitesi

Diyelim ki bir e-ticaret platformu yönetiyorsunuz. Birden fazla alt alan adı var, backend bir PHP-FPM uygulaması, statik dosyalar ayrı bir dizinden servis ediliyor. İşte production’a yakın tam bir konfigürasyon:

# /etc/nginx/conf.d/eticaret.conf

upstream php_backend {
    server 127.0.0.1:9000;
    keepalive 32;
}

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

server {
    listen 443 ssl;
    listen 443 quic reuseport;
    http2 on;
    
    server_name eticaret.com www.eticaret.com;
    root /var/www/eticaret/public;
    index index.php index.html;
    
    # SSL Sertifikaları
    ssl_certificate /etc/letsencrypt/live/eticaret.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/eticaret.com/privkey.pem;
    ssl_trusted_certificate /etc/letsencrypt/live/eticaret.com/chain.pem;
    
    # SSL Güvenlik Ayarları
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305;
    ssl_prefer_server_ciphers off;
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 1d;
    ssl_session_tickets off;
    ssl_stapling on;
    ssl_stapling_verify on;
    resolver 8.8.8.8 8.8.4.4 valid=300s;
    
    # HTTP/3 bildirimi
    add_header Alt-Svc 'h3=":443"; ma=86400' always;
    
    # Güvenlik başlıkları
    add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
    add_header X-Frame-Options DENY always;
    add_header X-Content-Type-Options nosniff always;
    add_header X-XSS-Protection "1; mode=block" always;
    
    # Sıkıştırma
    gzip on;
    gzip_vary on;
    gzip_comp_level 5;
    gzip_min_length 1000;
    gzip_types application/json application/javascript text/css text/plain application/xml;
    
    # Statik dosyalar için agresif önbellekleme
    location ~* .(jpg|jpeg|png|gif|ico|css|js|woff2|woff|ttf|svg|webp|avif)$ {
        expires 1y;
        add_header Cache-Control "public, immutable";
        add_header Alt-Svc 'h3=":443"; ma=86400' always;
        access_log off;
    }
    
    # PHP işleme
    location ~ .php$ {
        try_files $uri =404;
        fastcgi_split_path_info ^(.+.php)(/.+)$;
        fastcgi_pass php_backend;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
        include fastcgi_params;
        fastcgi_hide_header X-Powered-By;
    }
    
    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }
}

Protokol Doğrulama ve Test

Konfigürasyonu uyguladıktan sonra her şeyin düzgün çalışıp çalışmadığını doğrulamanız gerekiyor.

Komut Satırından Test

# HTTP/2 testi - curl ile
curl -I --http2 https://sizindomain.com

# HTTP/3 testi - curl 7.66+ gerektirir
curl -I --http3 https://sizindomain.com

# Nginx access log üzerinden protokol kontrolü
# log_format'a $server_protocol ekleyin
tail -f /var/log/nginx/access.log | grep -E "HTTP/2|HTTP/3"

# OpenSSL ile TLS doğrulama
openssl s_client -connect sizindomain.com:443 -alpn h2

# SSL Labs API ile detaylı rapor
curl "https://api.ssllabs.com/api/v3/analyze?host=sizindomain.com&all=done" | python3 -m json.tool

Log Formatına Protokol Bilgisi Ekleme

http {
    log_format main_extended '$remote_addr - $remote_user [$time_local] '
                              '"$request" $status $body_bytes_sent '
                              '"$http_referer" "$http_user_agent" '
                              '$server_protocol '
                              '$ssl_protocol $ssl_cipher '
                              'rt=$request_time';
    
    access_log /var/log/nginx/access.log main_extended;
}

Bu format sayesinde log dosyanızda HTTP/2 ve HTTP/3 isteklerini net biçimde ayırt edebilirsiniz. Bir süre çalıştırdıktan sonra şunu çalıştırın:

awk '{print $14}' /var/log/nginx/access.log | sort | uniq -c | sort -rn

Çıktıda HTTP/2.0 ve HTTP/3.0 satırlarını görmek başarıyla aktifleştirildiğini kanıtlıyor.

Yaygın Sorunlar ve Çözümleri

“reuseport” Parametresi Birden Fazla Kez Kullanımı

Birden fazla sanal host tanımladığınızda reuseport parametresini yalnızca bir kez kullanın. Aksi halde Nginx başlamayı reddeder:

# Hatalı durum - iki server block'ta reuseport var
# nginx: [emerg] bind() to 0.0.0.0:443 failed (98: Address already in use)

# Çözüm: reuseport sadece ilk server block'ta ya da ayrı bir listen direktifinde

Çoklu domain kullanıyorsanız şu yaklaşım daha temiz:

# İlk server block'ta reuseport
server {
    listen 443 quic reuseport;
    listen 443 ssl;
    http2 on;
    server_name birinci.com;
    # ...
}

# Sonraki server block'larda reuseport yok
server {
    listen 443 quic;
    listen 443 ssl;
    http2 on;
    server_name ikinci.com;
    # ...
}

QUIC Destekli OpenSSL Gereksinimi

HTTP/3 için Nginx’in BoringSSL veya özel yamalı bir OpenSSL ile derlenmiş olması gerekiyor. Mevcut kurulumunuzun bunu destekleyip desteklemediğini kontrol edin:

nginx -V 2>&1 | grep -i "openssl|boringssl|quic"

Eğer HTTP/3 modülü yoksa ve kaynak koddan derleme yapmak istiyorsanız temel adımlar şu şekilde:

# Bağımlılıkları kur
sudo apt install build-essential libpcre3-dev zlib1g-dev libssl-dev

# nginx-quic deposunu klonla (HTTP/3 destekli)
git clone https://github.com/nicowillis/nginx-quic-build.git
# veya resmi nginx kaynak kodunu indir
wget https://nginx.org/download/nginx-1.25.3.tar.gz
tar -xzvf nginx-1.25.3.tar.gz

Production ortamında kaynak koddan derleme yapmak yerine Nginx’in resmi mainline paketini kullanmanızı öneririm. Bakım yükünü azaltır ve güvenlik güncellemelerini paket yöneticiniz aracılığıyla otomatik alırsınız.

Performans İyileştirme İpuçları

Worker Sayısı ve Bağlantı Limiti

HTTP/2 multiplexing sayesinde daha az bağlantıyla daha fazla iş yapılıyor. Buna göre worker ayarlarınızı optimize edin:

worker_processes auto;
worker_rlimit_nofile 65536;

events {
    worker_connections 4096;
    use epoll;
    multi_accept on;
}

OCSP Stapling

HTTP/2 ve HTTP/3 kullanırken bağlantı kurulum süresini kısaltmak için OCSP stapling kritik önem taşıyor:

ssl_stapling on;
ssl_stapling_verify on;
ssl_trusted_certificate /etc/letsencrypt/live/sizindomain.com/chain.pem;
resolver 1.1.1.1 8.8.8.8 valid=300s;
resolver_timeout 5s;

Sonuç

HTTP/2 aktifleştirmek artık standart bir gereksinim haline geldi, HTTP/3 ise hızla olgunlaşan ve production kullanımına hazır bir protokol. Nginx 1.25.x ile her iki protokolü de minimal konfigürasyon değişiklikleriyle devreye alabilirsiniz.

Pratik adımlara bakıldığında süreç şu şekilde özetlenebilir: Önce Nginx sürümünüzün gerekli modülleri içerdiğini doğrulayın, SSL/TLS yapılandırmanızı sağlamlaştırın, http2 on direktifini ve listen 443 quic satırını ekleyin, UDP 443 portunu güvenlik duvarınızda açın ve Alt-Svc başlığını eklemeyi unutmayın.

Testlerinizde tarayıcı geliştirici araçlarının Network sekmesindeki Protocol sütununu ve curl --http3 komutunu kullanın. Log formatınıza $server_protocol değişkenini ekleyerek gerçek trafik dağılımını izleyin. Zamanla HTTP/3 kullanan istemci oranının arttığını, özellikle mobil kullanıcılarda gecikme sürelerinin düştüğünü gözlemleyeceksiniz.

Bir uyarı olarak belirtmek gerekir: Bazı kurumsal ağlar ve CDN’ler UDP trafiğini bloke edebilir. Bu nedenle HTTP/3 hiçbir zaman HTTP/2’nin yerini almak üzere tasarlanmadı, tamamlayıcı olarak çalışıyor. Tarayıcı her zaman TCP fallback’e geri dönebiliyor ve bu sayede geri uyumluluk garanti altına alınıyor.

Yorum yapın