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 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 │
│ │
└─────────────────────────────────────────────────────────────────┘
// Program.cs
var builder = WebApplication.CreateBuilder(args);
builder.WebHost.ConfigureKestrel(options =>
{
// Configure Kestrel here
});
var app = builder.Build();
app.Run();
{
"Kestrel": {
"Endpoints": {
"Http": {
"Url": "http://localhost:5000"
},
"Https": {
"Url": "https://localhost:5001"
}
}
}
}
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");
});
builder.WebHost.ConfigureKestrel(options =>
{
options.ListenLocalhost(5001, listenOptions =>
{
listenOptions.UseHttps(); // Uses development certificate
});
});
builder.WebHost.ConfigureKestrel(options =>
{
options.ListenLocalhost(5001, listenOptions =>
{
listenOptions.UseHttps("certificate.pfx", "password");
});
});
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);
}
});
});
// Program.cs
var app = builder.Build();
// Redirect HTTP to HTTPS
app.UseHttpsRedirection();
app.MapGet("/", () => "Hello HTTPS!");
app.Run();
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));
});
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();
});
builder.WebHost.ConfigureKestrel(options =>
{
options.ListenLocalhost(5001, listenOptions =>
{
listenOptions.Protocols = HttpProtocols.Http1AndHttp2;
listenOptions.UseHttps();
});
});
builder.WebHost.ConfigureKestrel(options =>
{
options.ListenLocalhost(5002, listenOptions =>
{
listenOptions.Protocols = HttpProtocols.Http3;
});
});
// Check protocol
app.MapGet("/protocol", (HttpContext context) =>
{
var protocol = context.Request.Protocol;
return new { Protocol = protocol };
});
┌─────────────────────────────────────────────────────────────────┐
│ 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 │
│ │
└─────────────────────────────────────────────────────────────────┘
// Khi dùng reverse proxy
app.UseForwardedHeaders(new ForwardedHeadersOptions
{
ForwardedHeaders = ForwardedHeaders.XForwardedFor |
ForwardedHeaders.XForwardedProto
});
// ✅ 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!
});
// ✅ Set reasonable limits
options.Limits.MaxRequestBodySize = 50 * 1024 * 1024; // 50MB
// ❌ Don't remove limits entirely
options.Limits.MaxRequestBodySize = null; // Unlimited!
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"]));
});
}