====== Kestrel ====== **Kestrel** je multiplatformní webový server vyvinutý společností Microsoft pro [[ASP.NET]] Core aplikace. Jedná se o lehký, vysokovýkonný server napsaný v [[CSharp|C#]], který je výchozím webovým serverem pro ASP.NET Core. ===== Základní charakteristika ===== Kestrel je postaven na asynchronním I/O a poskytuje moderní přístup k hostování webových aplikací: * **Cross-platform** – běží na Windows, Linux a macOS * **Vysoký výkon** – jeden z nejrychlejších webových serverů * **Lightweight** – minimální paměťová náročnost * **Asynchronní** – založen na async/await vzoru * **Open-source** – vyvíjen na [[https://github.com/dotnet/aspnetcore|GitHubu]] * **Self-contained** – zabudován přímo v aplikaci ===== Historie ===== Kestrel byl vyvinut jako součást revoluce [[.NET Core]]: * **2016** – první verze s ASP.NET Core 1.0 * **2017** – ASP.NET Core 2.0, výrazné zlepšení výkonu * **2018** – ASP.NET Core 2.1, HTTP/2 podpora * **2019** – ASP.NET Core 3.0, gRPC podpora * **2020** – .NET 5, Kestrel jako součást unified .NET * **2021+** – kontinuální vylepšování výkonu a funkcí ===== Architektura ===== Kestrel využívá moderní technologie: ==== Libuv vs Socket Transport ==== Kestrel podporuje dva transportní vrstvy: * **Libuv** – asynchronní I/O knihovna (původně z Node.js) * **Socket Transport** – nativní .NET Sockets API (výchozí od .NET Core 2.1) Socket Transport je rychlejší a lépe integrovaný s .NET ekosystémem. ==== HTTP Pipeline ==== Zpracování požadavku v Kestrelu: - **Transport layer** přijme TCP/IP spojení - **Connection middleware** zpracuje spojení - **Protocol layer** parsuje HTTP protokol - **Application middleware** zpracuje požadavek - Odpověď je vrácena klientovi ===== Použití Kestrel ===== ==== Standalone server ==== Kestrel může běžet samostatně jako webový server: // Program.cs var builder = WebApplication.CreateBuilder(args); var app = builder.Build(); app.MapGet("/", () => "Hello from Kestrel!"); // Kestrel naslouchá na portu 5000 (HTTP) a 5001 (HTTPS) app.Run(); Spuštění: dotnet run Aplikace je dostupná na: * `http://localhost:5000` * `https://localhost:5001` ==== S reverzní proxy ==== V produkčním prostředí se Kestrel obvykle používá za reverzní proxy: Internet → Reverzní Proxy (Nginx/IIS/Apache) → Kestrel → ASP.NET Core App Důvody pro reverzní proxy: * **SSL/TLS terminace** – offloading šifrování * **Load balancing** – distribuce zátěže mezi servery * **Caching** – cache statického obsahu * **Compression** – komprese odpovědí * **Security** – firewall, rate limiting * **Static files** – efektivnější obsluha statických souborů ===== Konfigurace Kestrel ===== ==== Základní konfigurace ==== var builder = WebApplication.CreateBuilder(args); // Konfigurace Kestrel builder.WebHost.ConfigureKestrel(serverOptions => { // Nastavení limitů serverOptions.Limits.MaxConcurrentConnections = 100; serverOptions.Limits.MaxRequestBodySize = 10 * 1024 * 1024; // 10 MB serverOptions.Limits.KeepAliveTimeout = TimeSpan.FromMinutes(2); serverOptions.Limits.RequestHeadersTimeout = TimeSpan.FromSeconds(30); // HTTP/2 limity serverOptions.Limits.Http2.MaxStreamsPerConnection = 100; }); var app = builder.Build(); app.Run(); ==== Endpoints konfigurace ==== builder.WebHost.ConfigureKestrel(options => { // HTTP na portu 5000 options.ListenAnyIP(5000); // HTTPS na portu 5001 options.ListenAnyIP(5001, listenOptions => { listenOptions.UseHttps("certificate.pfx", "password"); }); // Localhost pouze options.ListenLocalhost(5002); // Konkrétní IP adresa options.Listen(IPAddress.Parse("192.168.1.100"), 5003); // Unix socket (Linux/macOS) options.ListenUnixSocket("/tmp/kestrel.sock"); }); ==== appsettings.json konfigurace ==== { "Kestrel": { "Endpoints": { "Http": { "Url": "http://localhost:5000" }, "Https": { "Url": "https://localhost:5001", "Certificate": { "Path": "certificate.pfx", "Password": "password" } } }, "Limits": { "MaxConcurrentConnections": 100, "MaxRequestBodySize": 10485760, "KeepAliveTimeout": "00:02:00" } } } ===== SSL/TLS certifikáty ===== Kestrel podporuje několik způsobů konfigurace SSL: ==== PFX soubor ==== options.ListenAnyIP(5001, listenOptions => { listenOptions.UseHttps("certificate.pfx", "password"); }); ==== Development certifikát ==== # Vytvoření development certifikátu dotnet dev-certs https --trust // Automaticky použije development certifikát options.ListenAnyIP(5001, listenOptions => { listenOptions.UseHttps(); }); ==== Let's Encrypt ==== Pro produkční použití s automatickými certifikáty: // Použití LettuceEncrypt package services.AddLettuceEncrypt() .PersistDataToDirectory(new DirectoryInfo("LettuceEncrypt"), "password"); ==== SNI (Server Name Indication) ==== Více certifikátů na jednom portu: options.ListenAnyIP(443, listenOptions => { listenOptions.UseHttps(httpsOptions => { httpsOptions.ServerCertificateSelector = (context, domain) => { if (domain == "example.com") return LoadCertificate("example.pfx"); if (domain == "another.com") return LoadCertificate("another.pfx"); return null; }; }); }); ===== HTTP/2 podpora ===== Kestrel plně podporuje HTTP/2: builder.WebHost.ConfigureKestrel(options => { options.ConfigureEndpointDefaults(listenOptions => { // HTTP/1.1 a HTTP/2 listenOptions.Protocols = HttpProtocols.Http1AndHttp2; // Pouze HTTP/2 // listenOptions.Protocols = HttpProtocols.Http2; }); }); HTTP/2 vlastnosti: * **Multiplexing** – více požadavků přes jedno spojení * **Server Push** – proaktivní posílání zdrojů * **Header Compression** – HPACK algoritmus * **Stream Prioritization** – prioritizace požadavků ===== HTTP/3 podpora ===== Kestrel podporuje HTTP/3 (QUIC protokol) od .NET 6: builder.WebHost.ConfigureKestrel(options => { options.ListenAnyIP(5001, listenOptions => { listenOptions.Protocols = HttpProtocols.Http1AndHttp2AndHttp3; listenOptions.UseHttps(); }); }); HTTP/3 výhody: * **QUIC transport** – postavený na UDP místo TCP * **Nižší latence** – rychlejší navázání spojení * **Connection migration** – odolnost proti změnám sítě * **Built-in encryption** – vždy šifrované Poznámka: HTTP/3 je experimentální a vyžaduje podporu na straně klienta. ===== gRPC podpora ===== Kestrel je výchozí server pro gRPC v .NET: var builder = WebApplication.CreateBuilder(args); // Přidání gRPC služeb builder.Services.AddGrpc(); builder.WebHost.ConfigureKestrel(options => { // HTTP/2 je vyžadován pro gRPC options.ConfigureEndpointDefaults(listenOptions => { listenOptions.Protocols = HttpProtocols.Http2; }); }); var app = builder.Build(); // Mapování gRPC služby app.MapGrpcService(); app.Run(); ===== WebSockets ===== Plná podpora pro WebSocket protokol: var builder = WebApplication.CreateBuilder(args); var app = builder.Build(); app.UseWebSockets(); app.Use(async (context, next) => { if (context.WebSockets.IsWebSocketRequest) { using var webSocket = await context.WebSockets.AcceptWebSocketAsync(); await HandleWebSocket(webSocket); } else { await next(); } }); app.Run(); ===== Výkon a optimalizace ===== Kestrel je navržen pro vysoký výkon: ==== Benchmarky ==== V TechEmpower benchmarcích patří Kestrel mezi nejrychlejší: * **Plaintext** – více než 7 milionů req/sec * **JSON serialization** – přes 500 000 req/sec * Top 10 ve většině kategorií ==== Optimalizace tipy ==== builder.WebHost.ConfigureKestrel(options => { // Response buffering options.AddServerHeader = false; // Odstranění Server header // Connection pooling options.Limits.MaxConcurrentConnections = 100; options.Limits.MaxConcurrentUpgradedConnections = 100; // Request size limits options.Limits.MaxRequestBodySize = 10 * 1024 * 1024; options.Limits.MaxRequestLineSize = 8 * 1024; options.Limits.MaxRequestHeadersTotalSize = 32 * 1024; // Timeouts options.Limits.KeepAliveTimeout = TimeSpan.FromMinutes(2); options.Limits.RequestHeadersTimeout = TimeSpan.FromSeconds(30); // HTTP/2 options.Limits.Http2.MaxStreamsPerConnection = 100; options.Limits.Http2.HeaderTableSize = 4096; options.Limits.Http2.MaxFrameSize = 16384; options.Limits.Http2.InitialConnectionWindowSize = 128 * 1024; }); ==== Response Compression ==== builder.Services.AddResponseCompression(options => { options.EnableForHttps = true; options.Providers.Add(); options.Providers.Add(); }); var app = builder.Build(); app.UseResponseCompression(); ===== Limity a kvóty ===== Konfigurace limitů pro zabezpečení a stabilitu: builder.WebHost.ConfigureKestrel(options => { var limits = options.Limits; // Connection limits limits.MaxConcurrentConnections = 100; limits.MaxConcurrentUpgradedConnections = 100; // Request limits limits.MaxRequestBodySize = 10 * 1024 * 1024; // 10 MB limits.MaxRequestBufferSize = 1024 * 1024; // 1 MB limits.MaxRequestLineSize = 8 * 1024; // 8 KB limits.MaxRequestHeadersTotalSize = 32 * 1024; // 32 KB limits.MaxRequestHeaderCount = 100; // Timeouts limits.KeepAliveTimeout = TimeSpan.FromMinutes(2); limits.RequestHeadersTimeout = TimeSpan.FromSeconds(30); // Response limits limits.MaxResponseBufferSize = 64 * 1024; // 64 KB limits.MinRequestBodyDataRate = new MinDataRate( bytesPerSecond: 100, gracePeriod: TimeSpan.FromSeconds(10) ); limits.MinResponseDataRate = new MinDataRate( bytesPerSecond: 100, gracePeriod: TimeSpan.FromSeconds(10) ); }); ===== Integrace s reverzní proxy ===== ==== Nginx ==== server { listen 80; server_name example.com; location / { proxy_pass http://localhost:5000; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection keep-alive; proxy_set_header Host $host; proxy_cache_bypass $http_upgrade; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } } Konfigurace Kestrel s Nginx: builder.Services.Configure(options => { options.ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto; options.KnownNetworks.Clear(); options.KnownProxies.Clear(); }); var app = builder.Build(); app.UseForwardedHeaders(); ==== IIS ==== Kestrel s [[IIS]] pomocí ASP.NET Core Module: Hosting modely v IIS: * **InProcess** – aplikace běží v IIS worker procesu (w3wp.exe) * **OutOfProcess** – IIS forwarduje na Kestrel ==== Apache ==== ServerName example.com ProxyPreserveHost On ProxyPass / http://127.0.0.1:5000/ ProxyPassReverse / http://127.0.0.1:5000/ RequestHeader set X-Forwarded-Proto "http" ===== Unix sockets ===== Na Linuxu a macOS lze použít Unix sockets místo TCP: builder.WebHost.ConfigureKestrel(options => { options.ListenUnixSocket("/tmp/kestrel.sock"); }); Nginx konfigurace: server { listen 80; location / { proxy_pass http://unix:/tmp/kestrel.sock; } } Výhody Unix sockets: * **Vyšší výkon** – nižší overhead než TCP * **Bezpečnost** – file system permissions * **Jednoduchost** – žádné port konflikty ===== Logging a diagnostika ===== ==== Základní logging ==== var builder = WebApplication.CreateBuilder(args); // Konfigurace loggingu builder.Logging.AddConsole(); builder.Logging.AddDebug(); builder.Logging.SetMinimumLevel(LogLevel.Information); // Kestrel logging builder.WebHost.ConfigureKestrel((context, options) => { options.ConfigureEndpointDefaults(listenOptions => { // Logování spojení listenOptions.UseConnectionLogging(); }); }); ==== Request logging ==== var app = builder.Build(); // HTTP logging middleware app.UseHttpLogging(); // Vlastní logging middleware app.Use(async (context, next) => { var logger = context.RequestServices .GetRequiredService>(); logger.LogInformation( "Request: {Method} {Path} from {IP}", context.Request.Method, context.Request.Path, context.Connection.RemoteIpAddress ); await next(); logger.LogInformation( "Response: {StatusCode}", context.Response.StatusCode ); }); ==== Diagnostika výkonu ==== // EventSource monitoring dotnet-trace collect --process-id // Metrics builder.Services.AddSingleton(); ===== Deployment ===== ==== Standalone executable ==== # Publikace jako self-contained dotnet publish -c Release -r linux-x64 --self-contained # Spuštění ./MyApp ==== Systemd služba (Linux) ==== # /etc/systemd/system/myapp.service [Unit] Description=My ASP.NET Core App After=network.target [Service] Type=notify WorkingDirectory=/var/www/myapp ExecStart=/var/www/myapp/MyApp Restart=always RestartSec=10 KillSignal=SIGINT SyslogIdentifier=myapp User=www-data Environment=ASPNETCORE_ENVIRONMENT=Production Environment=DOTNET_PRINT_TELEMETRY_MESSAGE=false [Install] WantedBy=multi-user.target Spuštění služby: sudo systemctl enable myapp sudo systemctl start myapp sudo systemctl status myapp ==== Docker ==== FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base WORKDIR /app EXPOSE 80 EXPOSE 443 FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build WORKDIR /src COPY ["MyApp.csproj", "./"] RUN dotnet restore "MyApp.csproj" COPY . . RUN dotnet build "MyApp.csproj" -c Release -o /app/build FROM build AS publish RUN dotnet publish "MyApp.csproj" -c Release -o /app/publish FROM base AS final WORKDIR /app COPY --from=publish /app/publish . ENTRYPOINT ["dotnet", "MyApp.dll"] Spuštění kontejneru: docker build -t myapp . docker run -d -p 8080:80 --name myapp myapp ===== Bezpečnost ===== Bezpečnostní doporučení pro Kestrel: * **HTTPS vždy** – použít SSL/TLS v produkci * **Za proxy** – nikdy nevystavovat Kestrel přímo na internet * **Request limits** – nastavit rozumné limity * **CORS** – správně nakonfigurovat Cross-Origin požadavky * **Rate limiting** – omezit počet požadavků * **Security headers** – přidat bezpečnostní HTTP hlavičky * **Input validation** – validovat všechny vstupy * **Secrets** – neukládat hesla v kódu // Security headers app.Use(async (context, next) => { context.Response.Headers.Add("X-Content-Type-Options", "nosniff"); context.Response.Headers.Add("X-Frame-Options", "DENY"); context.Response.Headers.Add("X-XSS-Protection", "1; mode=block"); context.Response.Headers.Add( "Content-Security-Policy", "default-src 'self'" ); context.Response.Headers.Add( "Strict-Transport-Security", "max-age=31536000; includeSubDomains" ); await next(); }); // Rate limiting builder.Services.AddRateLimiter(options => { options.GlobalLimiter = PartitionedRateLimiter.Create( context => RateLimitPartition.GetFixedWindowLimiter( partitionKey: context.Connection.RemoteIpAddress?.ToString() ?? "unknown", factory: _ => new FixedWindowRateLimiterOptions { PermitLimit = 100, Window = TimeSpan.FromMinutes(1) } ) ); }); var app = builder.Build(); app.UseRateLimiter(); ===== Monitoring a metriky ===== // Prometheus metrics builder.Services.AddSingleton(); // Health checks builder.Services.AddHealthChecks() .AddCheck("Kestrel", () => HealthCheckResult.Healthy()); var app = builder.Build(); app.MapHealthChecks("/health"); app.MapHealthChecks("/health/ready"); app.MapHealthChecks("/health/live"); ===== Porovnání s jinými webovými servery ===== ^ Vlastnost ^ Kestrel ^ [[IIS]] ^ Nginx ^ Node.js ^ | Platforma | Multi-platform | Windows | Multi-platform | Multi-platform | | Jazyk | C# | C/C++ | C | JavaScript | | Async I/O | Ano | Ano | Ano | Ano | | HTTP/2 | Ano | Ano | Ano | Ano | | HTTP/3 | Ano (exp.) | Ano | Ano (exp.) | Ne | | Výkon | Vynikající | Velmi dobrý | Vynikající | Dobrý | | Standalone | Ano | Ne | Ano | Ano | | Load balancing | Ne (proxy) | Ano (ARR) | Ano | Ne (cluster) | | Použití | ASP.NET Core | Windows apps | Reverse proxy | Node.js apps | ===== Výhody a nevýhody ===== ==== Výhody ==== * **Multiplatformní** – Windows, Linux, macOS * **Vysoký výkon** – top tier v benchmarcích * **Moderní protokoly** – HTTP/2, HTTP/3, WebSockets, gRPC * **Lehký** – minimální paměťová náročnost * **Jednoduchost** – snadná konfigurace a použití * **Async** – plně asynchronní zpracování * **Open-source** – transparentní vývoj * **Integrace** – perfektní integrace s ASP.NET Core ==== Nevýhody ==== * **Vyžaduje proxy** – pro produkci doporučena reverzní proxy * **Omezené funkce** – méně funkcí než plnohodnotné servery (IIS, Apache) * **Závislost na .NET** – vyžaduje .NET runtime * **Mladší** – méně historie než Apache nebo IIS ===== Kdy použít Kestrel ===== **Ideální pro:** * ASP.NET Core aplikace (jakékoliv) * Mikroservisy a API * Cloud-native aplikace * Kontejnerizované aplikace * gRPC služby * Real-time aplikace (SignalR, WebSockets) **Méně vhodné pro:** * Statické webové stránky (lepší Nginx) * Pokud již máte komplexní IIS infrastrukturu * Non-.NET aplikace ===== Související pojmy ===== * [[ASP.NET]] – webový framework * [[.NET Core]] – runtime platforma * [[IIS]] – Windows webový server * [[Nginx]] – reverzní proxy * [[Docker]] – kontejnerizace * [[gRPC]] – RPC framework * [[SignalR]] – real-time komunikace * [[HTTP/2]] – moderní HTTP protokol ===== Externí odkazy ===== * [[https://github.com/dotnet/aspnetcore|Kestrel na GitHubu]] * [[https://learn.microsoft.com/cs-cz/aspnet/core/fundamentals/servers/kestrel|Microsoft dokumentace]] * [[https://www.techempower.com/benchmarks/|TechEmpower Benchmarks]] * [[https://devblogs.microsoft.com/dotnet/|.NET Blog]]