Introduction to Kestrel web server implementation in ASP.NET Core

By Tom Dykstra, Chris Ross, and Stephen Halter

Kestrel is a cross-platform web server for ASP.NET Core based on libuv, a cross-platform asynchronous I/O library. Kestrel is the web server that is included by default in ASP.NET Core project templates.

Kestrel supports the following features:

  • HTTPS
  • Opaque upgrade used to enable WebSockets
  • Unix sockets for high performance behind Nginx

Kestrel is supported on all platforms and versions that .NET Core supports.

When to use Kestrel with a reverse proxy

If your application accepts requests only from an internal network, you can use Kestrel by itself.

Kestrel communicates directly with your internal network

If you expose your application to the Internet, you must use IIS, Nginx, or Apache as a reverse proxy server. A reverse proxy server receives HTTP requests from the Internet and forwards them to Kestrel after some preliminary handling.

Kestrel communicates indirectly with the Internet through a reverse proxy server, such as IIS, Nginx, or Apache

A reverse proxy is required for edge deployments (exposed to traffic from the Internet) for security reasons. The 1.x versions of Kestrel don't have a full complement of defenses against attacks. This includes but isn't limited to appropriate timeouts, size limits, and concurrent connection limits.

A scenario that requires a reverse proxy is when you have multiple applications that share the same IP and port running on a single server. That doesn't work with Kestrel directly because Kestrel doesn't support sharing the same IP and port between multiple processes. When you configure Kestrel to listen on a port, it handles all traffic for that port regardless of host header. A reverse proxy that can share ports must then forward to Kestrel on a unique IP and port.

Even if a reverse proxy server isn't required, using one might be a good choice for other reasons:

  • It can limit your exposed surface area.
  • It provides an optional additional layer of configuration and defense.
  • It might integrate better with existing infrastructure.
  • It simplifies load balancing and SSL set-up. Only your reverse proxy server requires an SSL certificate, and that server can communicate with your application servers on the internal network using plain HTTP.

How to use Kestrel in ASP.NET Core apps

Install the Microsoft.AspNetCore.Server.Kestrel NuGet package.

Call the UseKestrel extension method on WebHostBuilder in your Main method, specifying any Kestrel options that you need, as shown in the next section.

public static void Main(string[] args)
{
    Console.WriteLine("Running demo with Kestrel.");

    var config = new ConfigurationBuilder()
        .AddCommandLine(args)
        .Build();

    var builder = new WebHostBuilder()
        .UseContentRoot(Directory.GetCurrentDirectory())
        .UseConfiguration(config)
        .UseStartup<Startup>()
        .UseKestrel(options =>
        {
            if (config["threadCount"] != null)
            {
                options.ThreadCount = int.Parse(config["threadCount"]);
            }
        })
        .UseUrls("http://localhost:5000");

    var host = builder.Build();
    host.Run();
}

Kestrel options

For information about Kestrel options, see KestrelServerOptions class.

Endpoint configuration

By default ASP.NET Core binds to http://localhost:5000. You can configure URL prefixes and ports for Kestrel to listen on by using the UseUrls extension method, the urls command-line argument, or the ASP.NET Core configuration system. For more information about these methods, see Hosting. For information about how URL binding works when you use IIS as a reverse proxy, see ASP.NET Core Module.

URL prefixes

If you call UseUrls or use the urls command-line argument or ASPNETCORE_URLS environment variable, the URL prefixes can be in any of the following formats.

  • IPv4 address with port number

    http://65.55.39.10:80/
    https://65.55.39.10:443/
    

    0.0.0.0 is a special case that binds to all IPv4 addresses.

  • IPv6 address with port number

    http://[0:0:0:0:0:ffff:4137:270a]:80/ 
    https://[0:0:0:0:0:ffff:4137:270a]:443/ 
    

    [::] is the IPv6 equivalent of IPv4 0.0.0.0.

  • Host name with port number

    http://contoso.com:80/
    http://*:80/
    https://contoso.com:443/
    https://*:443/
    

    Host names, *, and + aren't special. Anything that isn't a recognized IP address or "localhost" binds to all IPv4 and IPv6 IPs. If you need to bind different host names to different ASP.NET Core applications on the same port, use WebListener or a reverse proxy server such as IIS, Nginx, or Apache.

  • "Localhost" name with port number or loopback IP with port number

    http://localhost:5000/
    http://127.0.0.1:5000/
    http://[::1]:5000/
    

    When localhost is specified, Kestrel tries to bind to both IPv4 and IPv6 loopback interfaces. If the requested port is in use by another service on either loopback interface, Kestrel fails to start. If either loopback interface is unavailable for any other reason (most commonly because IPv6 is not supported), Kestrel logs a warning.

  • Unix socket

    http://unix:/run/dan-live.sock  
    

Port 0

If you specify port number 0, Kestrel dynamically binds to an available port. Binding to port 0 is allowed for any host name or IP except for localhost name.

The following example shows how to determine which port Kestrel actually bound to at runtime:

public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory)
{
    loggerFactory.AddConsole();

    var serverAddressesFeature = app.ServerFeatures.Get<IServerAddressesFeature>();

    app.UseStaticFiles();

    app.Run(async (context) =>
    {
        context.Response.ContentType = "text/html";
        await context.Response
            .WriteAsync("<p>Hosted by Kestrel</p>");

        if (serverAddressesFeature != null)
        {
            await context.Response
                .WriteAsync("<p>Listening on the following addresses: " +
                    string.Join(", ", serverAddressesFeature.Addresses) +
                    "</p>");
        }

        await context.Response.WriteAsync($"<p>Request URL: {context.Request.GetDisplayUrl()}<p>");
    });
}

URL prefixes for SSL

Be sure to include URL prefixes with https: if you call the UseHttps extension method, as shown below.

var host = new WebHostBuilder() 
    .UseKestrel(options => 
    { 
        options.UseHttps("testCert.pfx", "testPassword"); 
    }) 
   .UseUrls("http://localhost:5000", "https://localhost:5001") 
   .UseContentRoot(Directory.GetCurrentDirectory()) 
   .UseStartup<Startup>() 
   .Build(); 
Note

HTTPS and HTTP cannot be hosted on the same port.

For generating self-signed SSL certificates on Windows, you can use the PowerShell cmdlet New-SelfSignedCertificate. There are also third-party tools that make it easier for you to generate self-signed certificates:

On macOS and Linux you can create a self-signed certificate using OpenSSL.

For more information, see Setting up HTTPS for development.

Next steps

For more information, see the following resources: