{"id":13065,"date":"2018-04-12T17:42:44","date_gmt":"2018-04-13T00:42:44","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/webdev\/?p=13065"},"modified":"2018-04-12T17:42:44","modified_gmt":"2018-04-13T00:42:44","slug":"asp-net-core-2-1-0-preview2-improvements-to-the-kestrel-http-server","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/dotnet\/asp-net-core-2-1-0-preview2-improvements-to-the-kestrel-http-server\/","title":{"rendered":"ASP.NET Core 2.1.0-preview2: Improvements to the Kestrel HTTP server"},"content":{"rendered":"<h2>Change default transport to Sockets<\/h2>\n<p>Building off the improvements to the managed sockets implementation in .NET Core we have changed the default transport in Kestrel from libuv to sockets. As a consequence, the<span>\u00a0<\/span><code>Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv<\/code><span>\u00a0<\/span>package is no longer part of the<span>\u00a0<\/span><code>Microsoft.AspNetCore.App<\/code><span>\u00a0<\/span>metapackage.<\/p>\n<h3>How to switch back to libuv<\/h3>\n<p>To continue using libuv as your transport, you will need to add reference to the libuv package and modify your application to use libuv as it&#8217;s transport. Alternatively, you can reference the<span>\u00a0<\/span><code>Microsoft.AspNetCore.All<\/code><span>\u00a0<\/span>metapackage which includes a transitive dependency on the libuv package.<\/p>\n<div class=\"highlight highlight-source-shell\">\n<pre>dotnet add package Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv -v 2.1.0-preview2-final<\/pre>\n<\/div>\n<div class=\"highlight highlight-source-cs\">\n<pre><span class=\"pl-k\">public<\/span> <span class=\"pl-k\">static<\/span> <span class=\"pl-en\">IWebHostBuilder<\/span> <span class=\"pl-en\">CreateWebHostBuilder<\/span>(<span class=\"pl-k\">string<\/span>[] <span class=\"pl-smi\">args<\/span>) =&gt;\n    WebHost.CreateDefaultBuilder(args)\n        .UseLibuv()\n        .UseStartup&lt;Startup&gt;();<\/pre>\n<\/div>\n<h2>SNI support<\/h2>\n<p>Server Name Indication (SNI) is extension to the TLS protocol that allows clients to send the desired hostname unencrypted as part of the TLS handshake. As a consequence, you can host multiple domains on the same IP\/Port and use the hostname to respond with the correct certificate. In 2.1.0-preview2, Kestrel has added a<span>\u00a0<\/span><code>ServerCertificateSelector<\/code><span>\u00a0<\/span>callback which is invoked once per connection to allow you select the right certificate. If you specify a<span>\u00a0<\/span><code>ServerCertificateSelector<\/code>, the selector will always take precedence over any specified server certificate.<\/p>\n<p>SNI support requires running on netcoreapp2.1. On netcoreapp2.0 and net461 the callback will be invoked but the name will always be null. The name will also be null if the client did not provide this optional parameter.<\/p>\n<div class=\"highlight highlight-source-cs\">\n<pre><span class=\"pl-k\">public<\/span> <span class=\"pl-k\">static<\/span> <span class=\"pl-en\">IWebHostBuilder<\/span> <span class=\"pl-en\">CreateWebHostBuilder<\/span>(<span class=\"pl-k\">string<\/span>[] <span class=\"pl-smi\">args<\/span>) =&gt;\n    WebHost.CreateDefaultBuilder(args)\n        .UseKestrel((context, options) =&gt;\n        {\n            options.ListenAnyIP(<span class=\"pl-c1\">5005<\/span>, listenOptions =&gt;\n            {\n                listenOptions.UseHttps(httpsOptions =&gt;\n                {\n                    <span class=\"pl-k\">var<\/span> <span class=\"pl-en\">localhostCert <\/span>= CertificateLoader.LoadFromStoreCert(<span class=\"pl-s\"><span class=\"pl-pds\">\"<\/span>localhost<span class=\"pl-pds\">\"<\/span><\/span>, <span class=\"pl-s\"><span class=\"pl-pds\">\"<\/span>My<span class=\"pl-pds\">\"<\/span><\/span>, StoreLocation.CurrentUser, allowInvalid: <span class=\"pl-c1\">true<\/span>);\n                    <span class=\"pl-k\">var<\/span> <span class=\"pl-en\">exampleCert <\/span>= CertificateLoader.LoadFromStoreCert(<span class=\"pl-s\"><span class=\"pl-pds\">\"<\/span>example.com<span class=\"pl-pds\">\"<\/span><\/span>, <span class=\"pl-s\"><span class=\"pl-pds\">\"<\/span>My<span class=\"pl-pds\">\"<\/span><\/span>, StoreLocation.CurrentUser, allowInvalid: <span class=\"pl-c1\">true<\/span>);\n                    <span class=\"pl-k\">var<\/span> <span class=\"pl-en\">subExampleCert <\/span>= CertificateLoader.LoadFromStoreCert(<span class=\"pl-s\"><span class=\"pl-pds\">\"<\/span>sub.example.com<span class=\"pl-pds\">\"<\/span><\/span>, <span class=\"pl-s\"><span class=\"pl-pds\">\"<\/span>My<span class=\"pl-pds\">\"<\/span><\/span>, StoreLocation.CurrentUser, allowInvalid: <span class=\"pl-c1\">true<\/span>);\n                    <span class=\"pl-k\">var<\/span> <span class=\"pl-en\">certs <\/span>= <span class=\"pl-k\">new<\/span> <span class=\"pl-en\">Dictionary<\/span>&lt;<span class=\"pl-k\">string<\/span>, X509Certificate2&gt;(StringComparer.OrdinalIgnoreCase);\n                    certs[<span class=\"pl-s\"><span class=\"pl-pds\">\"<\/span>localhost<span class=\"pl-pds\">\"<\/span><\/span>] = localhostCert;\n                    certs[<span class=\"pl-s\"><span class=\"pl-pds\">\"<\/span>example.com<span class=\"pl-pds\">\"<\/span><\/span>] = exampleCert;\n                    certs[<span class=\"pl-s\"><span class=\"pl-pds\">\"<\/span>sub.example.com<span class=\"pl-pds\">\"<\/span><\/span>] = subExampleCert;\n\n                    httpsOptions.ServerCertificateSelector = (features, name) =&gt;\n                    {\n                        <span class=\"pl-k\">if<\/span> (name != <span class=\"pl-c1\">null<\/span> &amp;&amp; certs.TryGetValue(name, <span class=\"pl-k\">out<\/span> var cert))\n                        {\n                            <span class=\"pl-k\">return<\/span> cert;\n                        }\n\n                       <span class=\"pl-k\">return<\/span> exampleCert;\n                    };\n                });\n           });\n        })\n        .UseStartup&lt;Startup&gt;();<\/pre>\n<\/div>\n<h2>Host filtering middleware<\/h2>\n<p>While Kestrel supports configuration based on prefixes such as<span>\u00a0<\/span><code>https:\/\/contoso.com:5000<\/code>, it largely ignores the host name. Localhost is a special case used for binding to loopback addresses. Any host other than an explicit IP address binds to all public IP addresses. None of this information is used to validate request Host headers. In 2.1.0-preview2, we introduced a new HostFiltering middleware(<code>Microsoft.AspNetCore.HostFiltering<\/code>) that we recommend you use in conjunction with Kestrel to validate Host headers. The host filtering middleware is already included as part of the default WebHost. To configure the middleware, use a semicolon separated list of hostnames in your<span>\u00a0<\/span><code>appSettings.json<\/code><span>\u00a0<\/span>file.<\/p>\n<div class=\"highlight highlight-source-json\">\n<pre>{\n    <span class=\"pl-s\"><span class=\"pl-pds\">\"<\/span>AllowedHosts<span class=\"pl-pds\">\"<\/span><\/span>: <span class=\"pl-s\"><span class=\"pl-pds\">\"<\/span>localhost;127.0.0.1;[::1]<span class=\"pl-pds\">\"<\/span><\/span>\n}<\/pre>\n<\/div>\n<p>Alternatively, you can configure it directly from code.<\/p>\n<div class=\"highlight highlight-source-cs\">\n<pre><span class=\"pl-en\">services.AddHostFiltering<\/span>(options =&gt;\n{\n    <span class=\"pl-k\">var<\/span> <span class=\"pl-en\">allowedHosts <\/span>= <span class=\"pl-k\">new<\/span> <span class=\"pl-en\">List<\/span>&lt;String&gt;{\n        <span class=\"pl-s\"><span class=\"pl-pds\">\"<\/span>localhost<span class=\"pl-pds\">\"<\/span><\/span>,\n        <span class=\"pl-s\"><span class=\"pl-pds\">\"<\/span>127.0.0.1<span class=\"pl-pds\">\"<\/span><\/span>,\n        <span class=\"pl-s\"><span class=\"pl-pds\">\"<\/span>[::1]<span class=\"pl-pds\">\"<\/span><\/span>\n    };\n    options.AllowedHosts = allowedHosts;\n});<\/pre>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>Change default transport to Sockets Building off the improvements to the managed sockets implementation in .NET Core we have changed the default transport in Kestrel from libuv to sockets. As a consequence, the\u00a0Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv\u00a0package is no longer part of the\u00a0Microsoft.AspNetCore.App\u00a0metapackage. How to switch back to libuv To continue using libuv as your transport, you will need [&hellip;]<\/p>\n","protected":false},"author":1233,"featured_media":21380,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[197,7509],"tags":[7556,7557],"class_list":["post-13065","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-aspnet","category-aspnetcore","tag-asp-net-core-2-1-0-preview2","tag-kestrel-http-server"],"acf":[],"blog_post_summary":"<p>Change default transport to Sockets Building off the improvements to the managed sockets implementation in .NET Core we have changed the default transport in Kestrel from libuv to sockets. As a consequence, the\u00a0Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv\u00a0package is no longer part of the\u00a0Microsoft.AspNetCore.App\u00a0metapackage. How to switch back to libuv To continue using libuv as your transport, you will need [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/13065","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/users\/1233"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/comments?post=13065"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/13065\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/media\/21380"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/media?parent=13065"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/categories?post=13065"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/tags?post=13065"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}