Blog
Mert Özen'in yazılım geliştirme, backend, frontend ve DevOps üzerine blog yazıları.
Web Server, Application Server ve Reverse Proxy: Bir HTTP İsteği Uygulamana Nasıl Ulaşır?
Kestrel hem web server hem application server; reverse proxy ise isteği karşılayıp arkadaki uygulamaya ileten, TLS termination, statik dosya, compression, buffering ve load balancing'i üstlenen katman. Aynı isteği önce doğrudan Kestrel'e, sonra Nginx üzerinden gönderip uygulamanın gördüğü IP'yi, header'ları ve Angular deep link davranışını karşılaştırıyor, beş hosting topolojisini yan yana koyuyoruz.
Kestrel'i Tanımak: Endpoint'ler, ASPNETCORE_HTTP_PORTS, Limit'ler ve HTTP/2–HTTP/3
Kestrel'in dinlediği adresi kodda Listen, Kestrel:Endpoints, --urls/ASPNETCORE_URLS ve ASPNETCORE_HTTP_PORTS belirler; öncelik bu sırayla ve ezilen her ayar log'a uyarı olarak düşer. Dokuz koşuyla önceliği ölçüyor, PEM certificate ve SNI'yi, restart'sız certificate yenilemeyi, varsayılan limit'leri, libmsquic ile HTTP/3'ü, Nginx'e Unix socket ile bağlanmayı ve container'da localhost tuzağını görüyoruz.
Reverse Proxy Arkasında ASP.NET Core: Forwarded Headers, KnownIPNetworks ve Doğru Client IP
Proxy arkasındaki uygulama client'ın IP'sini ve HTTPS'i ancak UseForwardedHeaders doğru kurulursa görür: hangi header'ların işleneceğini söylemek ve proxy'nin adresini KnownProxies ya da .NET 10'daki KnownIPNetworks'e eklemek gerekir. HTTPS redirection döngüsünü, ASPDEPR005 uyarısını, ForwardLimit ile sahte X-Forwarded-For'u, X-Forwarded-Prefix ile PathBase'i ve birden fazla instance'ta Data Protection key'lerini gerçek koşularla görüyoruz.
Nginx Temelleri: Kurulum, nginx.conf Yapısı, server ve location Block'ları
Nginx'i nginx.org deposundan kurmak güncel stable dalı (1.30) verir; Ubuntu 24.04'ün paketi 1.24'te kalıyor. Master ve worker process'leri, nginx.conf context'lerini, default_server ile bilinmeyen host'u reddetmeyi, location eşleşme algoritmasını (=, en uzun prefix, ^~, regex), root ile alias farkını, proxy_pass'teki sondaki slash'i ve bozuk config ile reload ve restart'ın farklı sonuçlarını gerçek koşularla görüyoruz.
Nginx ile ASP.NET Core Reverse Proxy: proxy_pass, Header'lar, WebSocket/SignalR ve Timeout'lar
Nginx 1.29.7'den beri upstream keepalive ve HTTP/1.1 varsayılan, ama yalnız upstream block'u kullanırsan: doğrudan adrese giden proxy_pass her istekte yeni bağlantı açıyor. Microsoft'un referans config'ini satır satır açıyor, WebSocket upgrade map'i olmadan SignalR'ın sessizce long polling'e düştüğünü, SSE'de buffering'i, Nginx ile Kestrel'in body ve header limit'lerini hizalamayı ve 502 ile 504'ü log'dan ayırt etmeyi ölçüyoruz.
Nginx ile Angular Yayınlamak: SPA Fallback, Cache Header'ları, Compression ve /api Proxy
Angular'ı Nginx ile yayınlarken try_files ile SPA fallback, hash'li bundle'lara immutable ve index.html'e no-cache şart; aksi hâlde deploy sonrası eski chunk'ı isteyen tarayıcı 200 ile HTML alıyor. gzip_static, runtime config.json, aynı origin'de /api proxy ile CORS'suz kurulum, base href ile alt yolda yayın ve Angular SSR'ı Node ile Nginx arkasına koyarken allowedHosts tuzağı gerçek koşularla.
Nginx'te HTTPS, Security Header'ları, Rate Limiting ve Load Balancing
Nginx'te TLS termination, http2 on ve listen quic ile HTTP/3, add_header_inherit merge ile kaybolmayan security header'ları, tek yerden HSTS, limit_req ile 429 ve upstream zone'u olmadan round robin'in dengesiz dağıldığı gerçek koşularla. ip_hash, 1.29.6 ile gelen sticky cookie ve max_fails ile passive health check: bir instance ölünce client tek hata görmüyor, ama idempotent olmayan istekler ve sağlıksız ama ayakta process'ler ayrı ele alınmalı.
Linux'ta .NET Uygulamasını systemd Service Olarak Çalıştırmak
Kestrel'i systemd altında ayrı bir kullanıcıyla, Type=notify ve AddSystemd ile, KillSignal=SIGTERM ve hardening ayarlarıyla çalıştır; KillSignal=SIGINT açık istekleri keser ve systemd bunu yine success olarak raporlar. Publish seçeneklerinin boyutlarını, Ubuntu 24.04'te runtime'ın dağıtım deposundan gelmesini, journald çıktısını, çökme sonrası restart'ı, exposure skorunun 9.2'den 3.8'e inmesini ve releases/current symlink'iyle 0,2 saniyelik deploy ve geri dönüşü ölçüyoruz.
IIS'te ASP.NET Core: Hosting Bundle, ASP.NET Core Module, In-Process ve Out-of-Process
IIS'te ASP.NET Core'u ASP.NET Core Module çalıştırır; Hosting Bundle IIS'ten önce kurulursa onarılmalıdır, yoksa 500.19 alırsın ve uygulama tek satır çalışmaz. Publish'in ürettiği web.config'i, in-process ile out-of-process farkını, app pool ve ApplicationPoolIdentity izinlerini ve 500.30, 500.31, 500.38, 502.5 gibi hataların nereye baktırdığını anlatıyoruz; IIS bu Mac'te çalıştırılmadı, web.config çıktıları gerçek publish'lerden.
IIS'te Production: Deploy, app_offline.htm, Kilitli Dosyalar, Application Initialization ve Angular
IIS'te çalışan uygulamanın DLL'leri kilitli; deploy'u app_offline.htm ile ya da .NET 7'den beri desteklenen enableShadowCopy ile yap ve bu ayarları sunucuda değil projedeki web.config'te tut, publish onları koruyor. Recycle ve overlapped recycle, Application Initialization ve idle timeout, IIS'te Data Protection, sub-application, URL Rewrite ile Angular ve IIS yerine AddWindowsService; IIS bu Mac'te çalıştırılmadı, web.config ve build çıktıları gerçek.
Hosting Seçimi ve Production Checklist'i: Nginx, IIS, Caddy, Container ve PaaS
Hosting seçimini önce ekibin neyi işletebildiği, sonra servis sayısı, deploy sıklığı ve maliyet belirler; Linux VM ve Nginx, IIS, Caddy, Traefik, YARP, PaaS ve container aynı soruların farklı cevapları. Caddy'yi yedi satırlık config ve active health check ile deniyor, go-live öncesi on maddelik bir kontrol script'iyle yedinci yazının config'inde dışarıdan görünmeyen health endpoint'i ve 443'te eksik default server'ı yakalıyoruz.
.NET 6'dan .NET 10'a Hosting'de Ne Değişti: Port 8080, HTTP_PORTS, KnownIPNetworks ve Diğerleri
.NET 8'den beri ASP.NET Core image'ları 80 yerine 8080'i dinliyor ve hazır bir app kullanıcısı getiriyor, ama varsayılan kullanıcı hâlâ root; .NET 10'da image'lar Ubuntu tabanlı ve KnownNetworks ile WebHost obsolete. Eski -p 8000:80 komutunun connection reset vermesini, Docker'da root olmayan 80'in neden çalışıp başka runtime'da çalışmayabileceğini, eski tutorial'lardaki tuzakları ve .NET 11'in hosting'e dokunan breaking change'lerini gerçek koşularla görüyoruz.