Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Kestrel Configuration

Overview Questions

  • Kestrel là gì và tại sao nó quan trọng?
  • Làm sao để cấu hình HTTPS cho Kestrel?
  • Endpoint configuration hoạt động như thế nào?
  • Request limits được cấu hình ra sao?
  • Kestrel vs IIS/Nginx - khi nào dùng reverse proxy?

Kestrel Basics

What is Kestrel?

┌─────────────────────────────────────────────────────────────────┐
│                    KESTREL ARCHITECTURE                           │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  ┌──────────┐    ┌──────────┐    ┌──────────┐                  │
│  │  Client  │───▶│  Kestrel │───▶│  ASP.NET │                  │
│  │  (HTTP)  │    │  Server  │    │  Core    │                  │
│  └──────────┘    └──────────┘    └──────────┘                  │
│                                                                 │
│  - Cross-platform web server                                    │
│  - Default server cho ASP.NET Core                              │
│  - High performance                                             │
│  - Có thể dùng standalone hoặc với reverse proxy                │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

Basic Configuration

// Program.cs
var builder = WebApplication.CreateBuilder(args);

builder.WebHost.ConfigureKestrel(options =>
{
    // Configure Kestrel here
});

var app = builder.Build();
app.Run();

Endpoint Configuration

appsettings.json

{
  "Kestrel": {
    "Endpoints": {
      "Http": {
        "Url": "http://localhost:5000"
      },
      "Https": {
        "Url": "https://localhost:5001"
      }
    }
  }
}

Code Configuration

builder.WebHost.ConfigureKestrel(options =>
{
    // HTTP endpoint
    options.ListenLocalhost(5000);
    
    // HTTPS endpoint
    options.ListenLocalhost(5001, listenOptions =>
    {
        listenOptions.UseHttps();
    });
    
    // Custom IP and port
    options.Listen(IPAddress.Parse("127.0.0.1"), 5002);
    
    // Unix socket (Linux)
    options.ListenUnixSocket("/tmp/kestrel.sock");
});

HTTPS Configuration

Development Certificate

builder.WebHost.ConfigureKestrel(options =>
{
    options.ListenLocalhost(5001, listenOptions =>
    {
        listenOptions.UseHttps(); // Uses development certificate
    });
});

Production Certificate

builder.WebHost.ConfigureKestrel(options =>
{
    options.ListenLocalhost(5001, listenOptions =>
    {
        listenOptions.UseHttps("certificate.pfx", "password");
    });
});

Certificate from Store

builder.WebHost.ConfigureKestrel(options =>
{
    options.ListenLocalhost(5001, listenOptions =>
    {
        using var store = new X509Store(StoreName.My, StoreLocation.CurrentUser);
        store.Open(OpenFlags.ReadOnly);
        
        var cert = store.Certificates
            .Find(X509FindType.FindByThumbprint, "CERT_THUMBPRINT", validOnly: false)
            .OfType<X509Certificate2>()
            .FirstOrDefault();
        
        if (cert != null)
        {
            listenOptions.UseHttps(cert);
        }
    });
});

HTTPS Redirection

// Program.cs
var app = builder.Build();

// Redirect HTTP to HTTPS
app.UseHttpsRedirection();

app.MapGet("/", () => "Hello HTTPS!");

app.Run();

Request Limits

Configure Limits

builder.WebHost.ConfigureKestrel(options =>
{
    // Max request body size (100MB)
    options.Limits.MaxRequestBodySize = 100 * 1024 * 1024;
    
    // Max request header size (32KB)
    options.Limits.MaxRequestHeadersTotalSize = 32 * 1024;
    
    // Max request header count
    options.Limits.MaxRequestHeaderCount = 100;
    
    // Keep-alive timeout
    options.Limits.KeepAliveTimeout = TimeSpan.FromMinutes(2);
    
    // Request headers timeout
    options.Limits.RequestHeadersTimeout = TimeSpan.FromSeconds(30);
    
    // Min response data rate
    options.Limits.MinResponseDataRate = new MinDataRate(
        bytesPerSecond: 100, 
        gracePeriod: TimeSpan.FromSeconds(10));
});

Per-Request Limits

app.MapPost("/upload", async (HttpContext context) =>
{
    // Override limit for this request
    context.Features.Get<IHttpMaxRequestBodySizeFeature>()
        ?.MaxRequestBodySize = 200 * 1024 * 1024; // 200MB
    
    // Process upload
    await context.Request.Body.CopyToAsync(Stream.Null);
    
    return Results.Ok();
});

HTTP/2 and HTTP/3

HTTP/2 Configuration

builder.WebHost.ConfigureKestrel(options =>
{
    options.ListenLocalhost(5001, listenOptions =>
    {
        listenOptions.Protocols = HttpProtocols.Http1AndHttp2;
        listenOptions.UseHttps();
    });
});

HTTP/3 Configuration

builder.WebHost.ConfigureKestrel(options =>
{
    options.ListenLocalhost(5002, listenOptions =>
    {
        listenOptions.Protocols = HttpProtocols.Http3;
    });
});

Protocol Selection

// Check protocol
app.MapGet("/protocol", (HttpContext context) =>
{
    var protocol = context.Request.Protocol;
    return new { Protocol = protocol };
});

Reverse Proxy

When to Use Reverse Proxy

┌─────────────────────────────────────────────────────────────────┐
│                    REVERSE PROXY SETUP                            │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  ┌──────────┐    ┌──────────┐    ┌──────────┐                  │
│  │  Client  │───▶│  Nginx/  │───▶│  Kestrel │                  │
│  │          │    │  IIS     │    │  (App)   │                  │
│  └──────────┘    └──────────┘    └──────────┘                  │
│                                                                 │
│  Use reverse proxy for:                                         │
│  - Multiple apps trên cùng port 80/443                         │
│  - Static file serving                                          │
│  - Response compression                                         │
│  - Additional security layer                                    │
│  - Load balancing                                               │
│                                                                 │
│  Kestrel standalone OK cho:                                     │
│  - Internal services                                            │
│  - Container deployments                                        │
│  - Development                                                  │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

Forwarded Headers

// Khi dùng reverse proxy
app.UseForwardedHeaders(new ForwardedHeadersOptions
{
    ForwardedHeaders = ForwardedHeaders.XForwardedFor | 
                       ForwardedHeaders.XForwardedProto
});

Best Practices

1. Use HTTPS in Production

// ✅ Always use HTTPS in production
builder.WebHost.ConfigureKestrel(options =>
{
    options.ListenLocalhost(5001, o => o.UseHttps("cert.pfx", "password"));
});

// ❌ Never use HTTP only in production
builder.WebHost.ConfigureKestrel(options =>
{
    options.ListenLocalhost(5000); // No HTTPS!
});

2. Set Appropriate Limits

// ✅ Set reasonable limits
options.Limits.MaxRequestBodySize = 50 * 1024 * 1024; // 50MB

// ❌ Don't remove limits entirely
options.Limits.MaxRequestBodySize = null; // Unlimited!

3. Configure for Environment

if (builder.Environment.IsDevelopment())
{
    builder.WebHost.ConfigureKestrel(options =>
    {
        options.ListenLocalhost(5000);
        options.ListenLocalhost(5001, o => o.UseHttps());
    });
}
else
{
    builder.WebHost.ConfigureKestrel(options =>
    {
        options.ListenLocalhost(5001, o => 
            o.UseHttps("prod-cert.pfx", config["CertPassword"]));
    });
}