Servers - HTTP.sys
In this article
Important HTTP.sys isn't compatible with the ASP.NET Core Module and can't be used with IIS or IIS Express.
-
Windows Authentication
-
Port sharing
-
HTTPS with SNI
-
HTTP/2
over TLS (Windows 10 or later) -
Direct file transmission
-
Response caching
-
WebSockets (Windows 8 or later)
-
Windows 7 or later
-
Windows Server 2008 R2 or later
HTTP.sys
When to use - There's a need to expose the server directly to the Internet without using IIS.
- An internal deployment requires a feature not available in Kestrel. For more information, see Kestrel vs.
HTTP.sys
HTTP/2
support
-
Windows Server 2016/Windows 10 or later
-
Application-Layer Protocol Negotiation (ALPN) connection
-
TLS 1.2 or later connection
HTTP/3 support
-
Windows Server 2022/Windows 11 or later
-
An
https
url binding is used. -
The EnableHttp3 registry key is set.
app.Use((context, next) =>
{
context.Response.Headers.AltSvc = "h3=\":443\"";
return next(context);
});
Kernel mode authentication with Kerberos
Support for kernel-mode response buffering
HTTP.sys
How to use HTTP.sys
Configure the ASP.NET Core app to use using Microsoft.AspNetCore.Hosting.Server;
using Microsoft.AspNetCore.Hosting.Server.Features;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Server.HttpSys;
var builder = WebApplication.CreateBuilder(args);
builder.WebHost.UseHttpSys(options =>
{
options.AllowSynchronousIO = false;
options.Authentication.Schemes = AuthenticationSchemes.None;
options.Authentication.AllowAnonymous = true;
options.MaxConnections = null;
options.MaxRequestBodySize = 30_000_000;
options.UrlPrefixes.Add("http://localhost:5005");
});
builder.Services.AddRazorPages();
var app = builder.Build();
[RequestSizeLimit(100000000)]
public IActionResult MyActionMethod()
app.Use((context, next) =>
{
context.Features.GetRequiredFeature<IHttpMaxRequestBodySizeFeature>()
.MaxRequestBodySize = 10 * 1024;
var server = context.RequestServices
.GetRequiredService<IServer>();
var serverAddressesFeature = server.Features
.GetRequiredFeature<IServerAddressesFeature>();
var addresses = string.Join(", ", serverAddressesFeature.Addresses);
var loggerFactory = context.RequestServices
.GetRequiredService<ILoggerFactory>();
var logger = loggerFactory.CreateLogger("Sample");
logger.LogInformation("Addresses: {addresses}", addresses);
return next(context);
});
Configure Windows Server
-
Determine the ports to open for the app and use Windows Firewall or the New-NetFirewallRule PowerShell cmdlet to open firewall ports to allow traffic to reach
HTTP.sys
. In the following commands and app configuration, port 443 is used. -
When deploying to an Azure VM, open the ports in the Network Security Group. In the following commands and app configuration, port 443 is used.
-
Obtain and install X.509 certificates, if required. On Windows, create self-signed certificates using the New-SelfSignedCertificate PowerShell cmdlet. For an unsupported example, see UpdateIISExpressSSLForChrome.ps1. Install either self-signed or CA-signed certificates in the server's Local Machine > Personal store.
-
If the app is a framework-dependent deployment, install .NET Core, .NET Framework, or both (if the app is a .NET Core app targeting the .NET Framework).
If the app is a self-contained deployment, the app includes the runtime in its deployment. No framework installation is required on the server.
-
.NET Core: If the app requires .NET Core, obtain and run the .NET Core Runtime installer from .NET Core Downloads. Don't install the full SDK on the server.
-
.NET Framework: If the app requires .NET Framework, see the .NET Framework installation guide. Install the required .NET Framework. The installer for the latest .NET Framework is available from the .NET Core Downloads page.
-
Configure URLs and ports in the app. By default, ASP.NET Core binds to
http://localhost:5000
. To configure URL prefixes and ports, options include:
The following code example shows how to use UrlPrefixes
with the server's local IP address 10.0.0.4
on port 443:
An advantage of UrlPrefixes
is that an error message is generated immediately for improperly formatted prefixes.
The settings in UrlPrefixes
override UseUrls
/urls/ASPNETCORE_URLS settings. Therefore, an advantage of UseUrls
, urls
, and the ASPNETCORE_URLS
environment variable is that it's easier to switch between Kestrel and HTTP.sys
.
HTTP.sys recognizes two types of wild cards in URL prefixes:
For more information, see UrlPrefix Strings.
Warning
Top-level wildcard bindings (http://*:80/ and http://+:80
) should not be used. Top-level wildcard bindings create app security vulnerabilities. This applies to both strong and weak wildcards. Use explicit host names or IP addresses rather than wildcards. Subdomain wildcard binding (for example, *.mysub.com
) isn't a security risk if you control the entire parent domain (as opposed to *.com
, which is vulnerable). For more information, see RFC 9110: Section 7.2: Host and :authority.
Apps and containers are often given only a port to listen on, like port 80, without additional constraints like host or path. HTTP_PORTS and HTTPS_PORTS are config keys that specify the listening ports for the Kestrel and HTTP.sys
servers. These keys may be specified as environment variables defined with the DOTNET_
or ASPNETCORE_
prefixes, or specified directly through any other config input, such as appsettings.json
. Each is a semicolon-delimited list of port values, as shown in the following example:
ASPNETCORE_HTTP_PORTS=80;8080
ASPNETCORE_HTTPS_PORTS=443;8081
The preceding example is shorthand for the following configuration, which specifies the scheme (HTTP or HTTPS) and any host or IP. ASPNETCORE_URLS=http://:80/;http://:8080/;https://:443/;https://:8081/
The HTTP_PORTS and HTTPS_PORTS configuration keys are lower priority and are overridden by URLS or values provided directly in code. Certificates still need to be configured separately via server-specific mechanics for HTTPS. These configuration keys are equivalent to top-level wildcard bindings. They're convenient for development and container scenarios, but avoid wildcards when running on a machine that may also host other services.
-
UseUrls
-
urls
command-line argument -
ASPNETCORE_URLS
environment variable -
UrlPrefixes
var builder = WebApplication.CreateBuilder(args);
builder.WebHost.UseHttpSys(options =>
{
options.UrlPrefixes.Add("https://10.0.0.4:443");
});
builder.Services.AddRazorPages();
var app = builder.Build();
-
- is a weak binding, also known as a fallback binding. If the URL prefix is
http://*:5000
, and something else is bound to port 5000, this binding won't be used.
- is a weak binding, also known as a fallback binding. If the URL prefix is
-
- is a strong binding. If the URL prefix is
http://+:5000
, this binding will be used before other port 5000 bindings.
- is a strong binding. If the URL prefix is
Warning Top-level wildcard bindings (http://*:80/ and
http://+:80
) should not be used. Top-level wildcard bindings create app security vulnerabilities. This applies to both strong and weak wildcards. Use explicit host names or IP addresses rather than wildcards. Subdomain wildcard binding (for example,*.mysub.com
) isn't a security risk if you control the entire parent domain (as opposed to*.com
, which is vulnerable). For more information, see RFC 9110: Section 7.2: Host and :authority.
- Preregister URL prefixes on the server.
The built-in tool for configuring
HTTP.sys
is netsh.exe. netsh.exe is used to reserve URL prefixes and assign X.509 certificates. The tool requires administrator privileges. Use the netsh.exe tool to register URLs for the app:
netsh http add urlacl url=<URL> user=<USER>
In the following example, the local IP address of the server is 10.0.0.4
:
netsh http add urlacl url=https://10.0.0.4:443/ user=Users
When a URL is registered, the tool responds with URL reservation successfully added
.
To delete a registered URL, use the delete urlacl
command:
netsh http delete urlacl url=<URL>
-
: The fully qualified Uniform Resource Locator (URL). Don't use a wildcard binding. Use a valid hostname or local IP address. The URL must include a trailing slash. -
: Specifies the user or user-group name. -
Register X.509 certificates on the server. Use the netsh.exe tool to register certificates for the app:
netsh http add sslcert
ipport=10.0.0.4:443
certhash=b66ee04419d4ee37464ab8785ff02449980eae10
appid="{9412ee86-c21b-4eb8-bd89-f650fbf44931}"
For reference purposes, store the GUID in the app as a package tag:
In the following example:
When a certificate is registered, the tool responds with SSL Certificate successfully added
.
To delete a certificate registration, use the delete sslcert
command:
netsh http delete sslcert ipport=<IP>:<PORT>
Reference documentation for netsh.exe:
netsh http add sslcert ipport=<IP>:<PORT> certhash=<THUMBPRINT> appid="{<GUID>}"
-
: Specifies the local IP address for the binding. Don't use a wildcard binding. Use a valid IP address. -
: Specifies the port for the binding. -
: The X.509 certificate thumbprint. -
: A developer-generated GUID to represent the app for informational purposes. -
In Visual Studio:
-
Open the app's project properties by right-clicking on the app in Solution Explorer and selecting Properties.
-
Select the Package tab.
-
Enter the GUID that you created in the Tags field.
-
-
When not using Visual Studio:
-
Open the app's project file.
-
Add a
property to a new or existing with the GUID that you created:
-
<PropertyGroup>
<PackageTags>9412ee86-c21b-4eb8-bd89-f650fbf44931</PackageTags>
</PropertyGroup>
-
The local IP address of the server is
10.0.0.4
. -
An online random GUID generator provides the
appid
value. -
Netsh Commands for Hypertext Transfer Protocol (HTTP)
-
UrlPrefix Strings
-
Run the app. Administrator privileges aren't required to run the app when binding to localhost using HTTP (not HTTPS) with a port number greater than 1024. For other configurations (for example, using a local IP address or binding to port 443), run the app with administrator privileges. The app responds at the server's public IP address. In this example, the server is reached from the Internet at its public IP address of
104.214.79.47
. A development certificate is used in this example. The page loads securely after bypassing the browser's untrusted certificate warning.
Proxy server and load balancer scenarios
Get detailed timing information with IHttpSysRequestTimingFeature
-
Timestamps are obtained using QueryPerformanceCounter.
-
The timestamp frequency can be obtained via QueryPerformanceFrequency.
-
The index of the timing can be cast to HttpSysRequestTimingType to know what the timing represents.
-
The value may be 0 if the timing isn't available for the current request.
-
Requires Windows 10 version 2004, Windows Server 2022, or later.
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Server.HttpSys;
var builder = WebApplication.CreateBuilder(args);
builder.WebHost.UseHttpSys();
var app = builder.Build();
app.Use((context, next) =>
{
var feature = context.Features.GetRequiredFeature<IHttpSysRequestTimingFeature>();
var loggerFactory = context.RequestServices.GetRequiredService<ILoggerFactory>();
var logger = loggerFactory.CreateLogger("Sample");
var timestamps = feature.Timestamps;
for (var i = 0; i < timestamps.Length; i++)
{
var timestamp = timestamps[i];
var timingType = (HttpSysRequestTimingType)i;
logger.LogInformation("Timestamp {timingType}: {timestamp}",
timingType, timestamp);
}
return next(context);
});
app.MapGet("/", () => Results.Ok());
app.Run();
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Server.HttpSys;
var builder = WebApplication.CreateBuilder(args);
builder.WebHost.UseHttpSys();
var app = builder.Build();
app.Use((context, next) =>
{
var feature = context.Features.GetRequiredFeature<IHttpSysRequestTimingFeature>();
var loggerFactory = context.RequestServices.GetRequiredService<ILoggerFactory>();
var logger = loggerFactory.CreateLogger("Sample");
var timingType = HttpSysRequestTimingType.RequestRoutingEnd;
if (feature.TryGetTimestamp(timingType, out var timestamp))
{
logger.LogInformation("Timestamp {timingType}: {timestamp}",
timingType, timestamp);
}
else
{
logger.LogInformation("Timestamp {timingType}: not available for the "
+ "current request", timingType);
}
return next(context);
});
app.MapGet("/", () => Results.Ok());
app.Run();
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Server.HttpSys;
var builder = WebApplication.CreateBuilder(args);
builder.WebHost.UseHttpSys();
var app = builder.Build();
app.Use((context, next) =>
{
var feature = context.Features.GetRequiredFeature<IHttpSysRequestTimingFeature>();
var loggerFactory = context.RequestServices.GetRequiredService<ILoggerFactory>();
var logger = loggerFactory.CreateLogger("Sample");
var startingTimingType = HttpSysRequestTimingType.RequestRoutingStart;
var endingTimingType = HttpSysRequestTimingType.RequestRoutingEnd;
if (feature.TryGetElapsedTime(startingTimingType, endingTimingType, out var elapsed))
{
logger.LogInformation(
"Elapsed time {startingTimingType} to {endingTimingType}: {elapsed}",
startingTimingType,
endingTimingType,
elapsed);
}
else
{
logger.LogInformation(
"Elapsed time {startingTimingType} to {endingTimingType}:"
+ " not available for the current request.",
startingTimingType,
endingTimingType);
}
return next(context);
});
app.MapGet("/", () => Results.Ok());
app.Run();
HTTP/2
features to support gRPC
Advanced -
Windows 11 Build 22000 or later, Windows Server 2022 Build 20348 or later.
-
TLS 1.2 or later connection.
Trailers
if (httpContext.Response.SupportsTrailers())
{
httpContext.Response.DeclareTrailer("trailername");
// Write body
httpContext.Response.WriteAsync("Hello world");
httpContext.Response.AppendTrailer("trailername", "TrailerValue");
}
-
SupportsTrailers
ensures that trailers are supported for the response. -
DeclareTrailer
adds the given trailer name to theTrailer
response header. Declaring a response's trailers is optional, but recommended. IfDeclareTrailer
is called, it must be before the response headers are sent. -
AppendTrailer
appends the trailer.
Reset
var resetFeature = httpContext.Features.Get<IHttpResetFeature>();
resetFeature.Reset(errorCode: 2);
Tracing
Additional resources
-
Enable Windows Authentication with
HTTP.sys
-
HTTP Server API
-
aspnet/HttpSysServer GitHub repository (source code)
-
The host
-
Troubleshoot and debug ASP.NET Core projects