ASP.NET Core 託管和部署(一)【Kestrel】

風靈使發表於2019-02-20

ASP.NET Core 中的 Kestrel Web 伺服器實現

ASP.NET Core 中的 Kestrel Web 伺服器實現
Kestrel 是一個跨平臺的適用於 ASP.NET Core 的 Web 伺服器。 Kestrel 是 Web 伺服器,預設包括在 ASP.NET Core 專案模板中。

Kestrel 支援以下方案:

  • HTTPS
  • 用於啟用 WebSocket 的不透明升級
  • 用於獲得 Nginx 高效能的 Unix 套接字
  • HTTP/2(除 macOS以外)

macOS 的未來版本將支援HTTP/2。

.NET Core 支援的所有平臺和版本均支援 Kestrel

HTTP/2 支援

如果滿足以下基本要求,將為 ASP.NET Core 應用提供 HTTP/2

  • 作業系統
    • Windows Server 2016/Windows 10 或更高版本
    • 具有 OpenSSL 1.0.2 或更高版本的 Linux(例如,Ubuntu 16.04 或更高版本)
  • 目標框架:.NET Core 2.2 或更高版本
  • 應用程式層協議協商 (ALPN) 連線
  • TLS 1.2 或更高版本的連線

macOS 的未來版本將支援HTTP/2KestrelWindows Server 2012 R2Windows 8.1 上對 HTTP/2 的支援有限。支援受限是因為可在這些作業系統上使用的受支援 TLS 密碼套件列表有限。 可能需要使用橢圓曲線數字簽名演算法 (ECDSA) 生成的證書來保護 TLS 連線。

如果已建立 HTTP/2 連線,HttpRequest.Protocol 會報告 HTTP/2

預設情況下,禁用 HTTP/2。 有關配置的詳細資訊,請參閱 Kestrel 選項和 ListenOptions.Protocols 部分。

何時結合使用 Kestrel 和反向代理

可以單獨使用 Kestrel,也可以將其與反向代理伺服器(如 Internet Information Services (IIS)、NginxApache)結合使用。 反向代理伺服器接收來自網路的 HTTP 請求,並將這些請求轉發到 Kestrel

Kestrel 用作邊緣(面向 Internet)Web 伺服器:
Kestrel 直接與 Internet 通訊,不使用反向代理伺服器
Kestrel 用於反向代理配置:
Kestrel 通過反向代理伺服器(如 IIS、Nginx 或 Apache)間接與 Internet 進行通訊
無論配置是否使用反向代理伺服器——,都是從 Internet 接收請求的 ASP.NET Core 2.1 或更高版本應用的支援託管配置。

在沒有反向代理伺服器的情況下用作邊緣伺服器的 Kestrel 不支援在多個程式間共享相同的 IP 和埠。 如果將 Kestrel 配置為偵聽某個埠,Kestrel 會處理該埠的所有流量(無視請求的 Host 標頭)。 可以共享埠的反向代理能在唯一的 IP 和埠上將請求轉發至 Kestrel

即使不需要反向代理伺服器,使用反向代理伺服器可能也是個不錯的選擇。

反向代理:

  • 可以限制所承載的應用中的公開的公共外圍應用。
  • 提供額外的配置和防護層。
  • 可以更好地與現有基礎結構整合。
  • 簡化了負載均和和安全通訊 (HTTPS) 配置。 僅反向代理伺服器需要 X.509 證書,並且該伺服器可使用普通 HTTP在內部網路上與應用伺服器通訊。

警告

採用反向代理配置進行託管需要主機篩選。

如何在 ASP.NET Core 應用中使用Kestrel

Microsoft.AspNetCore.App 元包中包括 Microsoft.AspNetCore.Server.Kestrel 包(ASP.NET Core 2.1 或更高版本)。

預設情況下,ASP.NET Core 專案模板使用 Kestrel。 在 Program.cs 中,模板程式碼呼叫 CreateDefaultBuilder,後者在後臺呼叫 UseKestrel

public static void Main(string[] args)
{
    CreateWebHostBuilder(args).Build().Run();
}

public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
    WebHost.CreateDefaultBuilder(args)
        .UseStartup<Startup>();

若要在呼叫 CreateDefaultBuilder 後提供其他配置,請使用 ConfigureKestrel

public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
    WebHost.CreateDefaultBuilder(args)
        .UseStartup<Startup>()
        .ConfigureKestrel((context, options) =>
        {
            // Set properties and call methods on options
        });

如果應用未呼叫 CreateDefaultBuilder 來設定主機,請在呼叫 ConfigureKestrel 之前先呼叫 UseKestrel

public static void Main(string[] args)
{
    var host = new WebHostBuilder()
        .UseContentRoot(Directory.GetCurrentDirectory())
        .UseKestrel()
        .UseIISIntegration()
        .UseStartup<Startup>()
        .ConfigureKestrel((context, options) =>
        {
            // Set properties and call methods on options
        })
        .Build();

    host.Run();
}

Kestrel 選項

Kestrel Web 伺服器具有約束配置選項,這些選項在面向 Internet 的部署中尤其有用。

可在 KestrelServerOptions 類的 Limits 屬性上設定約束。 Limits 屬性包含 KestrelServerLimits 類的例項。

客戶端最大連線數

MaxConcurrentConnections
MaxConcurrentUpgradedConnections

可使用以下程式碼為整個應用設定併發開啟的最大 TCP 連線數:

.ConfigureKestrel((context, options) =>
{
    options.Limits.MaxConcurrentConnections = 100;
    options.Limits.MaxConcurrentUpgradedConnections = 100;
    options.Limits.MaxRequestBodySize = 10 * 1024;
    options.Limits.MinRequestBodyDataRate =
        new MinDataRate(bytesPerSecond: 100, gracePeriod: TimeSpan.FromSeconds(10));
    options.Limits.MinResponseDataRate =
        new MinDataRate(bytesPerSecond: 100, gracePeriod: TimeSpan.FromSeconds(10));
    options.Listen(IPAddress.Loopback, 5000);
    options.Listen(IPAddress.Loopback, 5001, listenOptions =>
    {
        listenOptions.UseHttps("testCert.pfx", "testPassword");
    });
});

對於已從 HTTPHTTPS 升級到另一個協議(例如,Websocket 請求)的連線,有一個單獨的限制。 連線升級後,不會計入 MaxConcurrentConnections 限制。

.ConfigureKestrel((context, options) =>
{
    options.Limits.MaxConcurrentConnections = 100;
    options.Limits.MaxConcurrentUpgradedConnections = 100;
    options.Limits.MaxRequestBodySize = 10 * 1024;
    options.Limits.MinRequestBodyDataRate =
        new MinDataRate(bytesPerSecond: 100, gracePeriod: TimeSpan.FromSeconds(10));
    options.Limits.MinResponseDataRate =
        new MinDataRate(bytesPerSecond: 100, gracePeriod: TimeSpan.FromSeconds(10));
    options.Listen(IPAddress.Loopback, 5000);
    options.Listen(IPAddress.Loopback, 5001, listenOptions =>
    {
        listenOptions.UseHttps("testCert.pfx", "testPassword");
    });
});

預設情況下,最大連線數不受限制 (NULL)。

請求正文最大大小

MaxRequestBodySize

預設的請求正文最大大小為 30,000,000 位元組,大約 28.6 MB。

ASP.NET Core MVC 應用中替代限制的推薦方法是在操作方法上使用 RequestSizeLimit 屬性:

[RequestSizeLimit(100000000)]
public IActionResult MyActionMethod()

以下示例演示如何為每個請求上的應用配置約束:

.ConfigureKestrel((context, options) =>
{
    options.Limits.MaxConcurrentConnections = 100;
    options.Limits.MaxConcurrentUpgradedConnections = 100;
    options.Limits.MaxRequestBodySize = 10 * 1024;
    options.Limits.MinRequestBodyDataRate =
        new MinDataRate(bytesPerSecond: 100, gracePeriod: TimeSpan.FromSeconds(10));
    options.Limits.MinResponseDataRate =
        new MinDataRate(bytesPerSecond: 100, gracePeriod: TimeSpan.FromSeconds(10));
    options.Listen(IPAddress.Loopback, 5000);
    options.Listen(IPAddress.Loopback, 5001, listenOptions =>
    {
        listenOptions.UseHttps("testCert.pfx", "testPassword");
    });
});

如果在應用開始讀取請求後嘗試配置請求限制,則會引發異常。 IsReadOnly 屬性指示 MaxRequestBodySize 屬性處於只讀狀態,意味已經無法再配置限制。

請求正文最小資料速率

MinRequestBodyDataRate
MinResponseDataRate

Kestrel 每秒檢查一次資料是否以指定的速率(位元組/秒)傳入。 如果速率低於最小值,則連線超時。寬限期是 Kestrel 提供給客戶端用於將其傳送速率提升到最小值的時間量;在此期間不會檢查速率。 寬限期有助於避免最初由於 TCP 慢啟動而以較慢速率傳送資料的連線中斷。

預設的最小速率為 240 位元組/秒,包含 5 秒的寬限期。

最小速率也適用於響應。 除了屬性和介面名稱中具有 RequestBodyResponse 以外,用於設定請求限制和響應限制的程式碼相同。

以下示例演示如何在 Program.cs 中配置最小資料速率:

.ConfigureKestrel((context, options) =>
{
    options.Limits.MaxConcurrentConnections = 100;
    options.Limits.MaxConcurrentUpgradedConnections = 100;
    options.Limits.MaxRequestBodySize = 10 * 1024;
    options.Limits.MinRequestBodyDataRate =
        new MinDataRate(bytesPerSecond: 100, gracePeriod: TimeSpan.FromSeconds(10));
    options.Limits.MinResponseDataRate =
        new MinDataRate(bytesPerSecond: 100, gracePeriod: TimeSpan.FromSeconds(10));
    options.Listen(IPAddress.Loopback, 5000);
    options.Listen(IPAddress.Loopback, 5001, listenOptions =>
    {
        listenOptions.UseHttps("testCert.pfx", "testPassword");
    });
});

可以在中介軟體中替代每個請求的最低速率限制:

app.Run(async (context) =>
{
    context.Features.Get<IHttpMaxRequestBodySizeFeature>()
        .MaxRequestBodySize = 10 * 1024;

    var minRequestRateFeature = 
        context.Features.Get<IHttpMinRequestBodyDataRateFeature>();
    var minResponseRateFeature = 
        context.Features.Get<IHttpMinResponseDataRateFeature>();

    if (minRequestRateFeature != null)
    {
        minRequestRateFeature.MinDataRate = new MinDataRate(
            bytesPerSecond: 100, gracePeriod: TimeSpan.FromSeconds(10));
    }

    if (minResponseRateFeature != null)
    {
        minResponseRateFeature.MinDataRate = new MinDataRate(
            bytesPerSecond: 100, gracePeriod: TimeSpan.FromSeconds(10));
    }

由於協議支援請求多路複用,HTTP/2 不支援基於每個請求修改速率限制,因此 HTTP/2 請求的 HttpContext.Features 中不存在前面示例中引用的速率特性。 通過 KestrelServerOptions.Limits 配置的伺服器範圍的速率限制仍適用於 HTTP/1.xHTTP/2 連線。

每個連線的最大流

Http2.MaxStreamsPerConnection 限制每個 HTTP/2 連線的併發請求流的數量。 拒絕過多的流。

public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
    WebHost.CreateDefaultBuilder(args)
        .UseStartup<Startup>()
        .ConfigureKestrel((context, options) =>
        {
            options.Limits.Http2.MaxStreamsPerConnection = 100;
        });

預設值為 100。

標題表大小

HPACK 解碼器解壓縮 HTTP/2 連線的 HTTP 標頭。 Http2.HeaderTableSize 限制 HPACK 解碼器使用的標頭壓縮表的大小。 該值以八位位元組提供,且必須大於零 (0)。

public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
    WebHost.CreateDefaultBuilder(args)
        .UseStartup<Startup>()
        .ConfigureKestrel((context, options) =>
        {
            options.Limits.Http2.HeaderTableSize = 4096;
        });

預設值為 4096。

最大幀大小

Http2.MaxFrameSize 指示要接收的 HTTP/2 連線幀有效負載的最大大小。 該值以八位位元組提供,必須介於 2^14 (16,384)2^24-1 (16,777,215) 之間。

public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
    WebHost.CreateDefaultBuilder(args)
        .UseStartup<Startup>()
        .ConfigureKestrel((context, options) =>
        {
            options.Limits.Http2.MaxFrameSize = 16384;
        });

預設值為 2^14 (16,384)

最大請求標頭大小

Http2.MaxRequestHeaderFieldSize 表示請求標頭值的允許的最大大小(用八進位制表示)。 此限制同時適用於壓縮和未壓縮表示形式中的名稱和值。 該值必須大於零 (0)。

public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
    WebHost.CreateDefaultBuilder(args)
        .UseStartup<Startup>()
        .ConfigureKestrel((context, options) =>
        {
            options.Limits.Http2.MaxRequestHeaderFieldSize = 8192;
        });

預設值為 8,192。

初始連線視窗大小

Http2.InitialConnectionWindowSize 表示伺服器一次性快取的最大請求主體資料大小(每次連線時在所有請求(流)中彙總,以位元組為單位)。 請求也受 Http2.InitialStreamWindowSize 限制。 該值必須大於或等於 65,535,並小於 2^31 (2,147,483,648)。

public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
    WebHost.CreateDefaultBuilder(args)
        .UseStartup<Startup>()
        .ConfigureKestrel((context, options) =>
        {
            options.Limits.Http2.InitialConnectionWindowSize = 131072;
        });

預設值為 128 KB (131,072)。

初始流視窗大小

Http2.InitialStreamWindowSize 表示伺服器針對每個請求(流)的一次性快取的最大請求主體資料大小(以位元組為單位)。 請求也受 Http2.InitialStreamWindowSize 限制。 該值必須大於或等於 65,535,並小於 2^31 (2,147,483,648)。

public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
    WebHost.CreateDefaultBuilder(args)
        .UseStartup<Startup>()
        .ConfigureKestrel((context, options) =>
        {
            options.Limits.Http2.InitialStreamWindowSize = 98304;
        });

預設值為 96 KB (98,304)。

有關其他 Kestrel 選項和限制的資訊,請參閱:

  • KestrelServerOptions
  • KestrelServerLimits
  • ListenOptions

終結點配置

預設情況下,ASP.NET Core 繫結到:

開發證書會建立於以下情況:

  • 安裝了 .NET Core SDK 時。
  • dev-certs tool 用於建立證書。

部分瀏覽器需要獲取信任本地開發證書的顯示許可權。

ASP.NET Core 2.1 及更高版本的專案模板將應用配置為預設情況下在 HTTPS 上執行,幷包括 HTTPS 重定向和 HSTS 支援。

KestrelServerOptions 上呼叫 ListenListenUnixSocket 方法,從而配置 KestrelURL 字首和埠。

UseUrls--urls 命令列引數、urls 主機配置鍵以及 ASPNETCORE_URLS 環境變數也有用,但具有本節後面註明的限制(必須要有可用於 HTTPS 終結點配置的預設證書)。

ASP.NET Core 2.1 KestrelServerOptions 配置:

ConfigureEndpointDefaults(Action<ListenOptions>)

指定一個為每個指定的終結點執行的配置 Action。 多次呼叫 ConfigureEndpointDefaults,用最新指定的 Action 替換之前的 Action

ConfigureHttpsDefaults(Action<HttpsConnectionAdapterOptions>)

指定一個為每個 HTTPS 終結點執行的配置 Action。 多次呼叫 ConfigureHttpsDefaults,用最新指定的 Action 替換之前的 Action

Configure(IConfiguration)

建立配置載入程式,用於設定將 IConfiguration 作為輸入的 Kestrel。 配置必須針對 Kestrel 的配置節。

ListenOptions.UseHttps

Kestrel 配置為使用 HTTPS

ListenOptions.UseHttps 擴充套件:

  • UseHttps – 將 Kestrel 配置為使用 HTTPS,採用預設證書。 如果沒有配置預設證書,則會引發異常。
  • UseHttps(string fileName)
  • UseHttps(string fileName, string password)
  • UseHttps(string fileName, string password,Action configureOptions)
  • UseHttps(StoreName storeName, string subject)
  • UseHttps(StoreName storeName, string subject, bool allowInvalid)
  • UseHttps(StoreName storeName, string subject, bool allowInvalid,StoreLocation location)
  • UseHttps(StoreName storeName, string subject, bool allowInvalid,StoreLocation location, Action configureOptions)
  • UseHttps(X509Certificate2 serverCertificate)
  • UseHttps(X509Certificate2 serverCertificate, Action<HttpsConnectionAdapterOptions> configureOptions)
  • UseHttps(Action<HttpsConnectionAdapterOptions> configureOptions)

ListenOptions.UseHttps 引數:

  • filename 是證書檔案的路徑和檔名,關聯包含應用內容檔案的目錄。
  • password 是訪問 X.509 證書資料所需的密碼。
  • configureOptions 是配置 HttpsConnectionAdapterOptions 的 Action。 返回
    ListenOptions。
  • storeName 是從中載入證書的證書儲存。
  • subject 是證書的主題名稱。
  • allowInvalid 指示是否存在需要留意的無效證書,例如自簽名證書。
  • location 是從中載入證書的儲存位置。
  • serverCertificate 是 X.509 證書。

在生產中,必須顯式配置 HTTPS。 至少必須提供預設證書。

下面要描述的支援的配置:

  • 無配置
  • 從配置中替換預設證書
  • 更改程式碼中的預設值

無配置

Kestrelhttp://localhost:5000https://localhost:5001 上進行偵聽(如果預設證書可用)。

使用以下內容指定 URL:

ASPNETCORE_URLS 環境變數。
--urls 命令列引數。
urls 主機配置鍵。
UseUrls 擴充套件方法。

有關詳細資訊,請參閱伺服器 URL 和重寫配置。

採用這些方法提供的值可以是一個或多個 HTTP 和 HTTPS 終結點(如果預設證書可用,則為 HTTPS)。 將值配置為以分號分隔的列表(例如 “Urls”: “http://localhost:8000;http://localhost:8001”)。

從配置中替換預設證書

WebHost.CreateDefaultBuilder 在預設情況下呼叫 serverOptions.Configure(context.Configuration.GetSection("Kestrel")) 來載入 Kestrel 配置。 Kestrel 可以使用預設 HTTPS 應用設定配置架構。 從磁碟上的檔案或從證書儲存中配置多個終結點,包括要使用的 URL 和證書。

在以下 appsettings.json 示例中:

將 AllowInvalid 設定為 true,從而允許使用無效證書(例如自簽名證書)。
任何未指定證書的 HTTPS 終結點(下例中的 HttpsDefaultCert)會回退至在 Certificates > Default 下定義的證書或開發證書。
{
"Kestrel": {
  "EndPoints": {
    "Http": {
      "Url": "http://localhost:5000"
    },

    "HttpsInlineCertFile": {
      "Url": "https://localhost:5001",
      "Certificate": {
        "Path": "<path to .pfx file>",
        "Password": "<certificate password>"
      }
    },

    "HttpsInlineCertStore": {
      "Url": "https://localhost:5002",
      "Certificate": {
        "Subject": "<subject; required>",
        "Store": "<certificate store; defaults to My>",
        "Location": "<location; defaults to CurrentUser>",
        "AllowInvalid": "<true or false; defaults to false>"
      }
    },

    "HttpsDefaultCert": {
      "Url": "https://localhost:5003"
    },

    "Https": {
      "Url": "https://*:5004",
      "Certificate": {
      "Path": "<path to .pfx file>",
      "Password": "<certificate password>"
      }
    }
    },
    "Certificates": {
      "Default": {
        "Path": "<path to .pfx file>",
        "Password": "<certificate password>"
      }
    }
  }
}

此外還可以使用任何證書節點的 Path 和 Password,採用證書儲存欄位指定證書。 例如,可將 Certificates > Default 證書指定為:

"Default": {
  "Subject": "<subject; required>",
  "Store": "<cert store; defaults to My>",
  "Location": "<location; defaults to CurrentUser>",
  "AllowInvalid": "<true or false; defaults to false>"
}

架構的注意事項:

終結點的名稱不區分大小寫。 例如,HTTPS 和 Https 都是有效的。

每個終結點都要具備 Url 引數。 此引數的格式和頂層 Urls 配置引數一樣,只不過它只能有單個值。

這些終結點不會新增進頂層 Urls 配置中定義的終結點,而是替換它們。 通過 Listen 在程式碼中定義的終結點與在配置節中定義的終結點相累積。

Certificate 部分是可選的。 如果為指定 Certificate 部分,則使用在之前的方案中定義的預設值。 如果沒有可用的預設值,伺服器會引發異常且無法啟動。

Certificate 支援 Path–Password 和 Subject–Store 證書。

只要不會導致埠衝突,就能以這種方式定義任何數量的終結點。

options.Configure(context.Configuration.GetSection("Kestrel")) 通過 .Endpoint(string name, options => { }) 方法返回 KestrelConfigurationLoader,可以用於補充已配置的終結點設定:
C# 

options.Configure(context.Configuration.GetSection("Kestrel"))
    .Endpoint("HTTPS", opt =>
    {
        opt.HttpsOptions.SslProtocols = SslProtocols.Tls12;
    });

也可以直接訪問 KestrelServerOptions.ConfigurationLoader 在現有載入程式上保持迭代,例如由 WebHost.CreateDefaultBuilder 提供的載入程式。

每個終結點的配置節都可用於 Endpoint 方法中的選項,以便讀取自定義設定。

通過另一節再次呼叫 options.Configure(context.Configuration.GetSection("Kestrel")) 可能載入多個配置。 只使用最新配置,除非之前的例項上顯式呼叫了 Load。 元包不會呼叫 Load,所以可能會替換它的預設配置節。

KestrelConfigurationLoader 從 KestrelServerOptions 將 API 的 Listen 簇反射為 Endpoint 過載,因此可在同樣的位置配置程式碼和配置終結點。 這些過載不使用名稱,且只使用配置中的預設設定。

更改程式碼中的預設值

可以使用 ConfigureEndpointDefaultsConfigureHttpsDefaults 更改 ListenOptionsHttpsConnectionAdapterOptions 的預設設定,包括重寫之前的方案指定的預設證書。 需要在配置任何終結點之前呼叫 ConfigureEndpointDefaultsConfigureHttpsDefaults

options.ConfigureEndpointDefaults(opt =>
{
    opt.NoDelay = true;
});

options.ConfigureHttpsDefaults(httpsOptions =>
{
    httpsOptions.SslProtocols = SslProtocols.Tls12;
});

SNIKestrel 支援

伺服器名稱指示 (SNI) 可用於承載相同 IP 地址和埠上的多個域。 為了執行 SNI,客戶端在 TLS 握手過程中將進行安全會話的主機名傳送至伺服器,從而讓伺服器可以提供正確的證書。 在 TLS 握手後的安全會話期間,客戶端將伺服器提供的證書用於與伺服器進行加密通訊。

Kestrel 通過 ServerCertificateSelector 回撥支援 SNI。 每次連線呼叫一次回撥,從而允許應用檢查主機名並選擇合適的證書。

SNI 支援要求:

  • 在目標框架 netcoreapp2.1 上執行。 在 netcoreapp2.0net461 上,回撥也會呼叫,但是 name
    始終為 null。 如果客戶端未在 TLS 握手過程中提供主機名引數,則 name 也為 null
  • 所有網站在相同的 Kestrel 例項上執行。 Kestrel 在無反向代理時不支援跨多個例項共享一個 IP 地址和埠。
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
    WebHost.CreateDefaultBuilder(args)
        .UseStartup<Startup>()
        .ConfigureKestrel((context, options) =>
        {
            options.ListenAnyIP(5005, listenOptions =>
            {
                listenOptions.UseHttps(httpsOptions =>
                {
                    var localhostCert = CertificateLoader.LoadFromStoreCert(
                        "localhost", "My", StoreLocation.CurrentUser, 
                        allowInvalid: true);
                    var exampleCert = CertificateLoader.LoadFromStoreCert(
                        "example.com", "My", StoreLocation.CurrentUser, 
                        allowInvalid: true);
                    var subExampleCert = CertificateLoader.LoadFromStoreCert(
                        "sub.example.com", "My", StoreLocation.CurrentUser, 
                        allowInvalid: true);
                    var certs = new Dictionary<string, X509Certificate2>(
                        StringComparer.OrdinalIgnoreCase);
                    certs["localhost"] = localhostCert;
                    certs["example.com"] = exampleCert;
                    certs["sub.example.com"] = subExampleCert;

                    httpsOptions.ServerCertificateSelector = (connectionContext, name) =>
                    {
                        if (name != null && certs.TryGetValue(name, out var cert))
                        {
                            return cert;
                        }

                        return exampleCert;
                    };
                });
            });
        });

繫結到 TCP 套接字

Listen 方法繫結至 TCP 套接字,且 options lambda 允許 X.509 證書配置:
C#

public static void Main(string[] args)
{
CreateWebHostBuilder(args).Build().Run();
}

public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup()
.ConfigureKestrel((context, options) =>
{
options.Listen(IPAddress.Loopback, 5000);
options.Listen(IPAddress.Loopback, 5001, listenOptions =>
{
listenOptions.UseHttps(“testCert.pfx”, “testPassword”);
});
});

示例程式碼使用 ListenOptions 為終結點配置 HTTPS。 可使用相同 API 為特定終結點配置其他 Kestrel 設定。

在 Windows 上,可以使用 New-SelfSignedCertificate PowerShell cmdlet 建立自簽名證書。 有關不支援的示例,請參閱 UpdateIISExpressSSLForChrome.ps1。

在 macOS、Linux 和 Windows 上,可以使用 OpenSSL 建立證書。
繫結到 Unix 套接字

可通過 ListenUnixSocket 偵聽 Unix 套接字以提高 Nginx 的效能,如以下示例所示:
C#

.ConfigureKestrel((context, options) =>
{
options.ListenUnixSocket("/tmp/kestrel-test.sock");
options.ListenUnixSocket("/tmp/kestrel-test.sock", listenOptions =>
{
listenOptions.UseHttps(“testCert.pfx”, “testpassword”);
});
});

埠 0

如果指定埠號 0,Kestrel 將動態繫結到可用埠。 以下示例演示如何確定 Kestrel 在執行時實際繫結到的埠:
C#

public void Configure(IApplicationBuilder app)
{
var serverAddressesFeature =
app.ServerFeatures.Get();

app.UseStaticFiles();

app.Run(async (context) =>
{
    context.Response.ContentType = "text/html";
    await context.Response
        .WriteAsync("<!DOCTYPE html><html lang=\"en\"><head>" +
            "<title></title></head><body><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>");
});

}

在應用執行時,控制檯視窗輸出指示可用於訪問應用的動態埠:
console

Listening on the following addresses: http://127.0.0.1:48508

限制

使用以下方法配置終結點:

UseUrls
--urls 命令列引數
urls 主機配置鍵
ASPNETCORE_URLS 環境變數

若要將程式碼用於 Kestrel 以外的伺服器,這些方法非常有用。 不過,請注意以下限制:

HTTPS 無法與這些方法結合使用,除非在 HTTPS 終結點配置中提供了預設證書(例如,使用 KestrelServerOptions 配置或配置檔案,如本主題前面的部分所示)。
如果同時使用 Listen 和 UseUrls 方法,Listen 終結點將覆蓋 UseUrls 終結點。

IIS 終結點配置

使用 IIS 時,由 Listen 或 UseUrls 設定用於 IIS 覆蓋繫結的 URL 繫結。 有關詳細資訊,請參閱 ASP.NET Core 模組主題。
ListenOptions.Protocols

Protocols 屬性建立在連線終結點上或為伺服器啟用的 HTTP 協議(HttpProtocols)。 從 HttpProtocols 列舉向 Protocols 屬性賦值。
HttpProtocols 列舉值 允許的連線協議
Http1 僅 HTTP/1.1。 可以在具有 TLS 或沒有 TLS 的情況下使用。
Http2 僅 HTTP/2。 主要在具有 TLS 的情況下使用。 僅當客戶端支援先驗知識模式時,才可以在沒有 TLS 的情況下使用。
Http1AndHttp2 HTTP/1.1 和 HTTP/2。 需要 TLS 和應用程式層協議協商 (ALPN) 連線來協商 HTTP/2;否則,連線預設為 HTTP/1.1。

預設協議是 HTTP/1.1。

HTTP/2 的 TLS 限制:

TLS 版本 1.2 或更高版本
重新協商已禁用
壓縮已禁用
最小的臨時金鑰交換大小:
    橢圓曲線 Diffie-Hellman (ECDHE) [RFC4492] –最小 224 位
    有限欄位 Diffie-Hellman (DHE) [TLS12] – 最小 2048 位
密碼套件未列入阻止列表

預設情況下,支援具有 P-256 橢圓曲線 [FIPS186] 的 TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 [TLS-ECDHE]。

以下示例允許埠 8000 上的 HTTP/1.1 和 HTTP/2 連線。 TLS 使用提供的證書來保護連線:
C#

public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup()
.ConfigureKestrel((context, options) =>
{
options.Listen(IPAddress.Any, 8000, listenOptions =>
{
listenOptions.Protocols = HttpProtocols.Http1AndHttp2;
listenOptions.UseHttps(“testCert.pfx”, “testPassword”);
});
});

(可選)建立 IConnectionAdapter 實現,以針對特定密碼的每個連線篩選 TLS 握手:
C#

public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup()
.ConfigureKestrel((context, options) =>
{
options.Listen(IPAddress.Any, 8000, listenOptions =>
{
listenOptions.Protocols = HttpProtocols.Http1AndHttp2;
listenOptions.UseHttps(“testCert.pfx”, “testPassword”);
listenOptions.ConnectionAdapters.Add(new TlsFilterAdapter());
});
});

C#

private class TlsFilterAdapter : IConnectionAdapter
{
public bool IsHttps => false;

public Task<IAdaptedConnection> OnConnectionAsync(ConnectionAdapterContext context)
{
    var tlsFeature = context.Features.Get<ITlsHandshakeFeature>();

    // Throw NotSupportedException for any cipher algorithm that you don't 
    // wish to support. Alternatively, define and compare 
    // ITlsHandshakeFeature.CipherAlgorithm to a list of acceptable cipher 
    // suites.
    //
    // A ITlsHandshakeFeature.CipherAlgorithm of CipherAlgorithmType.Null 
    // indicates that no cipher algorithm supported by Kestrel matches the 
    // requested algorithm(s).
    if (tlsFeature.CipherAlgorithm == CipherAlgorithmType.Null)
    {
        throw new NotSupportedException("Prohibited cipher: " + tlsFeature.CipherAlgorithm);
    }

    return Task.FromResult<IAdaptedConnection>(new AdaptedConnection(context.ConnectionStream));
}

private class AdaptedConnection : IAdaptedConnection
{
    public AdaptedConnection(Stream adaptedStream)
    {
        ConnectionStream = adaptedStream;
    }

    public Stream ConnectionStream { get; }

    public void Dispose()
    {
    }
}

}

從配置中設定協議

WebHost.CreateDefaultBuilder 在預設情況下呼叫 serverOptions.Configure(context.Configuration.GetSection(“Kestrel”)) 來載入 Kestrel 配置。

在以下 appsettings.json 示例中,為 Kestrel 的所有終結點建立預設的連線協議(HTTP/1.1 和 HTTP/2):
JSON

{
“Kestrel”: {
“EndPointDefaults”: {
“Protocols”: “Http1AndHttp2”
}
}
}

以下配置檔案示例為特定終結點建立了連線協議:
JSON

{
“Kestrel”: {
“EndPoints”: {
“HttpsDefaultCert”: {
“Url”: “https://localhost:5001”,
“Protocols”: “Http1AndHttp2”
}
}
}
}

程式碼中指定的協議覆蓋了由配置設定的值。
傳輸配置

對於 ASP.NET Core 2.1 版,Kestrel 預設傳輸不再基於 Libuv,而是基於託管的套接字。 這是 ASP.NET Core 2.0 應用升級到 2.1 時的一個重大更改,它呼叫 WebHostBuilderLibuvExtensions.UseLibuv 並依賴於以下包中的一個:

Microsoft.AspNetCore.Server.Kestrel(直接包引用)
Microsoft.AspNetCore.App

對於使用 Microsoft.AspNetCore.App 元包且需要使用 Libuv 的 ASP.NET Core 2.1 或更高版本的專案:

將用於 Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv 包的依賴項新增到應用的專案檔案:
XML 

呼叫 WebHostBuilderLibuvExtensions.UseLibuv:
C#

public class Program
{
    public static void Main(string[] args)
    {
        CreateWebHostBuilder(args).Build().Run();
    }

    public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
        WebHost.CreateDefaultBuilder(args)
            .UseLibuv()
            .UseStartup<Startup>();
}

URL 字首

如果使用 UseUrls、–urls 命令列引數、urls 主機配置鍵或 ASPNETCORE_URLS 環境變數,URL 字首可採用以下任意格式。

僅 HTTP URL 字首是有效的。 使用 UseUrls 配置 URL 繫結時,Kestrel 不支援 HTTPS。

包含埠號的 IPv4 地址

http://65.55.39.10:80/

0.0.0.0 是一種繫結到所有 IPv4 地址的特殊情況。

包含埠號的 IPv6 地址

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

[::] 是 IPv4 0.0.0.0 的 IPv6 等效項。

包含埠號的主機名

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

主機名、*和 + 並不特殊。 沒有識別為有效 IP 地址或 localhost 的任何內容都將繫結到所有 IPv4 和 IPv6 IP。 若要將不同主機名繫結到相同埠上的不同 ASP.NET Core 應用,請使用 HTTP.sys 或 IIS、Nginx 或 Apache 等反向代理伺服器。

警告

採用反向代理配置進行託管需要主機篩選。

包含埠號的主機 localhost 名稱或包含埠號的環回 IP

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

指定 localhost 後,Kestrel 將嘗試繫結到 IPv4 和 IPv6 環回介面。 如果其他服務正在任一環回介面上使用請求的埠,則 Kestrel 將無法啟動。 如果任一環回介面出於任何其他原因(通常是因為 IPv6 不受支援)而不可用,則 Kestrel 將記錄一個警告。

主機篩選

儘管 Kestrel 支援基於字首的配置(例如 http://example.com:5000),但 Kestrel 在很大程度上會忽略主機名。 主機 localhost 是一個特殊情況,用於繫結至環回地址。 除了顯式 IP 地址以外的所有主機都繫結至所有公共 IP 地址。 不驗證 Host 標頭。

解決方法是,使用主機篩選中介軟體。 主機篩選中介軟體由 Microsoft.AspNetCore.HostFiltering 包提供,此包包含在 Microsoft.AspNetCore.App 元包中(ASP.NET Core 2.1 或更高版本)。 該中介軟體由 CreateDefaultBuilder 新增,可呼叫 AddHostFiltering:
C#

public class Program
{
public static void Main(string[] args)
{
CreateWebHostBuilder(args).Build().Run();
}

public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
    WebHost.CreateDefaultBuilder(args)
        .UseStartup<Startup>();

}

預設情況下,主機篩選中介軟體處於禁用狀態。 要啟用該中介軟體,請在 appsettings.json/appsettings..json 中定義一個 AllowedHosts 鍵。 此值是以分號分隔的不帶埠號的主機名列表:

appsettings.json:
JSON

{
“AllowedHosts”: “example.com;localhost”
}

備註

轉接頭中介軟體同樣提供 ForwardedHeadersOptions.AllowedHosts 選項。 轉接頭中介軟體和主機篩選中介軟體具有適合不同方案的相似功能。 如果未保留 Host 標頭,並且使用反向代理伺服器或負載均衡器轉接請求,則使用轉接頭中介軟體設定 AllowedHosts 比較合適。 將 Kestrel 用作面向公眾的邊緣伺服器或直接轉接 Host 標頭時,使用主機篩選中介軟體設定 AllowedHosts 比較合適。

有關轉接頭中介軟體的詳細資訊,請參閱 配置 ASP.NET Core 以使用代理伺服器和負載均衡器。

相關文章