ASP.NET Core에서 HTTP.sys 웹 서버 구현

작성자: Tom DykstraChris Ross

HTTP.sys는 Windows에서만 실행되는 ASP.NET Core에 대한 웹 서버입니다. HTTP.sys는 Kestrel 서버에 대한 대안이며 Kestrel이 제공하지 않는 일부 기능을 제공합니다.

Important

HTTP.sys는 ASP.NET Core 모듈과 호환되지 않으므로 IIS 또는 IIS Express와 함께 사용될 수 없습니다.

HTTP.sys는 다음과 같은 기능을 지원합니다.

  • Windows 인증
  • 포트 공유
  • SNI를 사용하는 HTTPS
  • TLS를 통한 HTTP/2(Windows 10 이상)
  • 직접 파일 전송
  • 응답 캐싱
  • WebSockets(Windows 8 이상)

지원되는 Windows 버전:

  • Windows 7 이상
  • Windows Server 2008 R2 이상

샘플 코드 보기 및 다운로드(다운로드 방법)

HTTP.sys를 사용하는 경우

HTTP.sys는 다음과 같은 배포에 유용합니다.

  • IIS를 사용하지 않고 인터넷에 서버를 직접 노출해야 하는 경우

    HTTP.sys communicates directly with the Internet

  • 내부 배포에는 Kestrel에서 사용할 수 없는 기능이 필요합니다. 자세한 내용은 Kestrel 및 HTTP.sys를 참조하세요.

    HTTP.sys communicates directly with the internal network

HTTP.sys는 많은 유형의 공격으로부터 보호하고 모든 기능을 갖춘 웹 서버의 견고성, 보안 및 확장성을 제공하는 완성도 높은 기술입니다. IIS 자체는 HTTP.sys 위에 HTTP 수신기로 실행됩니다.

HTTP/2 지원

다음 기본 요구 사항이 충족되는 경우 ASP.NET Core 앱에 대해HTTP/2가 사용 설정됩니다.

HTTP/2 연결이 설정된 경우 HttpRequest.Protocol에서 HTTP/2을 보고합니다.

HTTP/2는 기본적으로 사용됩니다. HTTP/2 연결이 설정되지 않는 경우 연결이 HTTP/1.1로 대체됩니다. Windows의 이후 릴리스에서는 HTTP.sys를 사용하여 HTTP/2를 사용하지 않도록 하는 기능을 포함하여 HTTP/2 구성 플래그를 사용할 수 있습니다.

HTTP/3 지원

다음 기본 요구 사항이 충족되는 경우 ASP.NET Core 앱에 대해HTTP/3가 사용 설정됩니다.

이전 Windows 11 빌드 버전을 사용하려면 Windows 참가자 빌드를 사용해야 할 수 있습니다.

HTTP/3은 alt-svc 헤더를 통해 HTTP/1.1 또는 HTTP/2에서 업그레이드로 검색됩니다. 즉, 첫 번째 요청에서 일반적으로 HTTP/1.1 또는 HTTP/2를 사용한 후에 HTTP/3으로 전환합니다. Http.Sys는 alt-svc 헤더를 자동으로 추가하지 않으며 애플리케이션에서 추가해야 합니다. 다음 코드는 alt-svc 응답 헤더를 추가하는 미들웨어 예제입니다.

app.Use((context, next) =>
{
    context.Response.Headers.AltSvc = "h3=\":443\"";
    return next(context);
});

이전 코드를 요청 파이프라인의 초기에 배치합니다.

또한 Http.Sys는 응답 헤더 대신 AltSvc HTTP/2 프로토콜 메시지 전송을 지원하여 HTTP/3을 사용할 수 있음을 클라이언트에 알립니다. EnableAltSvc 레지스트리 키를 참조하세요. 이렇게 하려면 IP 주소 대신 호스트 이름을 사용하는 netsh sslcert 바인딩이 필요합니다.

Kerberos를 사용하여 커널 모드 인증

HTTP.sys는 Kerberos 인증 프로토콜을 사용하여 커널 모드 인증에 위임합니다. 사용자 모드 인증은 Kerberos 및 HTTP.sys로 지원되지 않습니다. 머신 계정은 Active Directory에서 가져온 Kerberos 토큰/티켓의 암호를 해독하는 데 사용되고 사용자를 인증하는 서버에 클라이언트에 의해 전달되어야 합니다. 앱의 사용자가 아닌 호스트에 대해 SPN(서비스 사용자 이름)을 등록합니다.

커널 모드 응답 버퍼링 지원

일부 시나리오에서는 대기 시간이 긴 작은 쓰기의 양이 많으면 성능에 상당한 영향을 줄 HTTP.sys수 있습니다. 이 영향은 구현에 버퍼가 Pipe 없기 때문입니다 HTTP.sys . 이러한 시나리오에서 성능을 향상시키기 위해 응답 버퍼링에 대한 지원이 포함됩니다 HTTP.sys. HttpSysOptions.EnableKernelResponseBuffering을 .로 설정하여 버퍼링을true사용하도록 설정합니다.

응답 버퍼링은 동기 I/O를 수행하는 앱 또는 한 번에 둘 이상의 미해결 쓰기가 없는 비동기 I/O에서 사용하도록 설정해야 합니다. 이러한 시나리오에서 응답 버퍼링은 대기 시간이 긴 연결에 대한 처리량을 크게 향상시킬 수 있습니다.

비동기 I/O를 사용하고 한 번에 둘 이상의 쓰기가 처리 중인 앱은 이 플래그를 사용하지 않아야 합니다. 이 플래그를 사용하도록 설정하면 HTTP.Sys에서 CPU 및 메모리 사용량이 높아질 수 있습니다.

HTTP.sys 사용 방법

HTTP.sys를 사용하도록 ASP.NET Core 앱 구성

호스트를 빌드할 때 UseHttpSys 확장 메서드를 호출하여 필요한 HttpSysOptions를 지정합니다. 다음 예제에서는 옵션을 기본값으로 설정합니다.

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();

추가 HTTP.sys 구성은 레지스트리 설정을 통해 처리됩니다.

HTTP.sys 옵션에 대한 자세한 내용은 HttpSysOptions를 참조하세요.

MaxRequestBodySize

요청 본문에 대해 허용되는 최대 크기(바이트)입니다. null로 설정하면 최대 요청 본문 크기는 무제한입니다. 항상 무제한인 업그레이드된 연결에는 이 제한이 영향을 미치지 않습니다.

단일 IActionResult에 대해 ASP.NET Core MVC 앱에서 제한을 재정의할 때는 작업 메서드에서 RequestSizeLimitAttribute 특성을 사용하는 방법이 좋습니다.

[RequestSizeLimit(100000000)]
public IActionResult MyActionMethod()

앱에서 요청을 읽기 시작한 후 요청에 대한 제한을 구성하려고 하면 예외가 throw됩니다. IsReadOnly 속성을 사용하여 MaxRequestBodySize 속성이 제한을 구성하기에 너무 늦은, 읽기 전용 상태인지를 나타낼 수 있습니다.

앱에서 요청별로 MaxRequestBodySize를 재정의해야 하는 경우 IHttpMaxRequestBodySizeFeature를 사용합니다.

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);
});

Visual Studio를 사용하는 경우 앱이 IIS 또는 IIS Express를 실행하도록 구성되지 않았는지 확인합니다.

Visual Studio에서 기본 실행 프로필은 IIS Express용입니다. 프로젝트를 콘솔 앱으로 실행하려면 다음 스크린샷에 표시된 것처럼 선택한 프로필을 수동으로 변경합니다.

Select console app profile

Windows Server 구성

  1. 앱용으로 열 포트를 결정하고 Windows 방화벽 또는 New-NetFirewallRule PowerShell cmdlet을 통해 방화벽 포트를 열어 HTTP.sys에 도달하는 트래픽을 허용합니다. 다음 명령 및 앱 구성에서는 포트 443이 사용됩니다.

  2. Azure VM에 배포할 경우 네트워크 보안 그룹에서 포트를 엽니다. 다음 명령 및 앱 구성에서는 포트 443이 사용됩니다.

  3. 필요한 경우 X.509 인증서를 구하여 설치합니다.

    Windows에서 New-SelfSignedCertificate PowerShell cmdlet을 사용하여 자체 서명된 인증서를 만듭니다. 지원되지 않는 예는 UpdateIISExpressSSLForChrome.ps1을 참조하세요.

    서버의 로컬 머신>개인 저장소에 자체 서명 또는 CA 서명 인증서를 설치합니다.

  4. 앱이 프레임워크 종속 배포인 경우 .NET Core, .NET Framework 또는 둘 다(앱이 NET Framework를 대상으로 하는 .NET Core 앱인 경우)를 설치합니다.

    앱이 자체 포함 배포인 경우 앱의 배포에 런타임이 포함됩니다. 서버에 프레임워크를 설치할 필요가 없습니다.

  5. 앱에서 URL 및 포트를 구성합니다.

    기본적으로 ASP.NET Core는 http://localhost:5000으로 바인딩합니다. URL 접두사 및 포트를 구성하려면 다음 옵션을 사용합니다.

    다음 코드 예제는 포트 443에서 서버의 로컬 IP 주소 10.0.0.4와 함께 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();
    

    UrlPrefixes의 장점은 형식이 잘못된 접두사에 대해 오류 메시지가 즉시 생성된다는 점입니다.

    UrlPrefixes의 설정은 UseUrls/urls/ASPNETCORE_URLS 설정을 재정의합니다. 따라서 UseUrls, urlsASPNETCORE_URLS 환경 변수의 장점은 Kestrel과 HTTP.sys 간에 전환하기가 쉽다는 것입니다.

    HTTP.sys는 HTTP Server API UrlPrefix 문자열 형식을 사용합니다.

    Warning

    최상위 와일드카드 바인딩(http://*:80/http://+:80)을 사용하지 않아야 합니다. 최상위 와일드카드 바인딩으로 인해 앱 보안 취약성이 생길 수 있습니다. 강력한 와일드카드와 약한 와일드카드 모두에 적용됩니다. 와일드카드보다는 명시적 호스트 이름 또는 IP 주소를 사용합니다. 전체 부모 도메인을 제어하는 경우 하위 도메인 와일드카드 바인딩(예: *.mysub.com)은 보안 위험이 아닙니다(취약한 *.com과 반대임). 자세한 내용은 RFC 9110: 섹션 7.2: 호스트 및 :authority를 참조하세요.

    앱 및 컨테이너에는 종종 호스트 또는 경로와 같은 추가 제약 조건 없이 포트 80과 같이 수신 대기할 포트만 제공됩니다. HTTP_PORTS 및 HTTPS_PORTS 및 HTTP.sys 서버에 대한 Kestrel 수신 대기 포트를 지정하는 구성 키입니다. 이러한 키는 접두사 또는 접두사로 DOTNET_ 정의된 환경 변수로 지정되거나 ASPNETCORE_ 같은 다른 구성 입력 appsettings.json을 통해 직접 지정될 수 있습니다. 각각은 다음 예제와 같이 포트 값의 세미콜론으로 구분된 목록입니다.

    ASPNETCORE_HTTP_PORTS=80;8080
    ASPNETCORE_HTTPS_PORTS=443;8081
    

    앞의 예제는 구성표(HTTP 또는 HTTPS) 및 호스트 또는 IP를 지정하는 다음 구성의 약식입니다.

    ASPNETCORE_URLS=http://*:80/;http://*:8080/;https://*:443/;https://*:8081/
    

    HTTP_PORTS 및 HTTPS_PORTS 구성 키는 우선 순위가 낮으며 코드에 직접 제공된 URLS 또는 값으로 재정의됩니다. HTTPS에 대한 서버별 메커니즘을 통해 인증서를 별도로 구성해야 합니다.

    이러한 구성 키는 최상위 와일드 카드 바인딩과 동일합니다. 개발 및 컨테이너 시나리오에는 편리하지만 다른 서비스를 호스트할 수 있는 컴퓨터에서 실행할 때는 카드 방지합니다.

  6. 서버에 URL 접두사를 미리 등록합니다.

    HTTP.sys 구성에 대한 기본 제공 도구는 netsh.exe입니다. netsh.exe는 URL 접두사를 예약하고 X.509 인증서를 할당하는 데 사용됩니다. 도구를 사용하려면 관리자 권한이 필요합니다.

    netsh.exe 도구를 사용하여 앱의 URL을 등록합니다.

    netsh http add urlacl url=<URL> user=<USER>
    
    • <URL>: 정규화된 URL(Uniform Resource Locator)입니다. 와일드카드 바인딩을 사용하지 마세요. 유효한 호스트 이름 또는 로컬 IP 주소를 사용합니다. ‘URL에는 후행 슬래시가 포함되어야 합니다.’
    • <USER>: 사용자 또는 사용자 그룹 이름을 지정합니다.

    다음 예제에서 서버의 로컬 IP 주소는 10.0.0.4입니다.

    netsh http add urlacl url=https://10.0.0.4:443/ user=Users
    

    URL이 등록되면 도구가 URL reservation successfully added로 응답합니다.

    등록된 URL을 삭제하려면 delete urlacl 명령을 사용합니다.

    netsh http delete urlacl url=<URL>
    
  7. 서버에 X.509 인증서를 등록합니다.

    netsh.exe 도구를 사용하여 앱의 인증서를 등록합니다.

    netsh http add sslcert ipport=<IP>:<PORT> certhash=<THUMBPRINT> appid="{<GUID>}"
    
    • <IP>: 바인딩의 로컬 IP 주소를 지정합니다. 와일드카드 바인딩을 사용하지 마세요. 유효한 IP 주소를 사용합니다.
    • <PORT>: 바인딩의 포트를 지정합니다.
    • <THUMBPRINT>: X.509 인증서 지문입니다.
    • <GUID>: 정보를 위해 앱을 나타내는 개발자 생성 GUID입니다.

    참조용으로 GUID를 패키지 태그로 앱에 저장합니다.

    • Visual Studio에서:
      • 솔루션 탐색기에서 앱을 마우스 오른쪽 단추로 클릭하고 속성을 선택하여 앱의 프로젝트 속성을 엽니다.
      • 패키지 탭을 선택합니다.
      • 태그 필드에 직접 만든 GUID를 입력합니다.
    • Visual Studio를 사용하지 않는 경우:
      • 앱의 프로젝트 파일을 엽니다.

      • 직접 만든 GUID를 사용하여 <PackageTags> 속성을 새로운 또는 기존 <PropertyGroup>에 추가합니다.

        <PropertyGroup>
          <PackageTags>9412ee86-c21b-4eb8-bd89-f650fbf44931</PackageTags>
        </PropertyGroup>
        

    다음 예제에서

    • 서버의 로컬 IP 주소는 10.0.0.4입니다.
    • 온라인 임의 GUID 생성기는 appid 값을 제공합니다.
    netsh http add sslcert 
        ipport=10.0.0.4:443 
        certhash=b66ee04419d4ee37464ab8785ff02449980eae10 
        appid="{9412ee86-c21b-4eb8-bd89-f650fbf44931}"
    

    인증서가 등록되면 도구가 SSL Certificate successfully added로 응답합니다.

    인증서 등록을 삭제하려면 delete sslcert 명령을 사용합니다.

    netsh http delete sslcert ipport=<IP>:<PORT>
    

    netsh.exe에 대한 참조 문서입니다.

  8. 앱을 실행합니다.

    1024보다 큰 포트 번호로 HTTP(HTTPS 아님)를 사용하여 localhost에 바인딩하는 경우에는 앱을 실행하는 데 관리자 권한이 필요하지 않습니다. 다른 구성(예: 로컬 IP 주소 사용 또는 포트 443에 바인딩)의 경우 관리자 권한으로 앱을 실행합니다.

    이 앱은 서버의 공용 IP 주소에서 응답합니다. 이 예제에서는 서버가 104.214.79.47의 공용 IP 주소에 있는 인터넷에서 연결됩니다.

    이 예제에는 개발 인증서가 사용됩니다. 브라우저의 신뢰할 수 없는 인증서 경고를 무시한 후 페이지가 안전하게 로드됩니다.

    Browser window showing the app's Index page loaded

프록시 서버 및 부하 분산 장치 시나리오

인터넷 또는 회사 네트워크의 요청과 상호 작용하는 HTTP.sys에서 호스팅하는 앱의 경우, 프록시 서버 및 부하 분산 장치 뒤에서 호스팅할 때 추가 구성이 필요할 수 있습니다. 자세한 내용은 프록시 서버 및 부하 분산 장치를 사용하도록 ASP.NET Core 구성을 참조하세요.

IHttpSysRequestTimingFeature를 사용하여 자세한 타이밍 정보 가져오기

IHttpSysRequestTimingFeature 는 요청에 대한 자세한 타이밍 정보를 제공합니다.

  • 타임스탬프는 QueryPerformanceCounter를 사용하여 가져옵니다.
  • 타임스탬프 빈도는 QueryPerformanceFrequency를 통해 가져올 수 있습니다.
  • 타이밍의 인덱스를 HttpSysRequestTimingType으로 캐스팅하여 타이밍이 나타내는 것을 알 수 있습니다.
  • 현재 요청에 타이밍을 사용할 수 없는 경우 값은 0일 수 있습니다.
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();

IHttpSysRequestTimingFeature.TryGetTimestamp 는 제공된 타이밍 형식에 대한 타임스탬프를 검색합니다.

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();

IHttpSysRequestTimingFeature.TryGetElapsedTime 은 지정된 두 타이밍 사이의 경과 시간을 제공합니다.

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();

gRPC를 지원하기 위한 고급 HTTP/2 기능

HTTP.sys의 추가 HTTP/2 기능은 응답 트레일러 및 초기화 프레임 전송을 위한 지원을 포함하여 gRPC를 지원합니다.

HTTP.sys를 사용하여 gRPC를 실행하기 위한 요구 사항:

  • Windows 11 Build 22000 이상, Windows Server 2022 Build 20348 이상.
  • TLS 1.2 이상 연결

트레일러

HTTP 트레일러는 응답 본문이 전송된 후에 전송된다는 점을 제외하고 HTTP 헤더와 유사합니다. IIS 및 HTTP.sys의 경우 HTTP/2 응답 트레일러만 지원됩니다.

if (httpContext.Response.SupportsTrailers())
{
    httpContext.Response.DeclareTrailer("trailername");	

    // Write body
    httpContext.Response.WriteAsync("Hello world");

    httpContext.Response.AppendTrailer("trailername", "TrailerValue");
}

앞의 예제 코드에서:

  • SupportsTrailers는 응답을 위해 트레일러가 지원되는지 확인합니다.
  • DeclareTrailerTrailer 응답 헤더에 지정된 트레일러 이름을 추가합니다. 응답 트레일러 선언은 선택 사항이지만 권장됩니다. DeclareTrailer가 호출되는 경우 해당 트레일러는 응답 헤더가 전송되기 전에 있어야 합니다.
  • AppendTrailer는 트레일러를 추가합니다.

Reset

초기화를 사용하면 서버에서 지정된 오류 코드를 사용하여 HTTP/2 요청을 초기화할 수 있습니다. 초기화 요청은 중단된 것으로 간주합니다.

var resetFeature = httpContext.Features.Get<IHttpResetFeature>();
resetFeature.Reset(errorCode: 2);

이전 코드 예제의 ResetINTERNAL_ERROR 오류 코드를 지정합니다. HTTP/2 오류 코드에 관한 자세한 내용은 HTTP/2 사양 오류 코드 섹션을 참조하세요.

추가 리소스

HTTP.sys는 Windows에서만 실행되는 ASP.NET Core에 대한 웹 서버입니다. HTTP.sys는 Kestrel 서버에 대한 대안이며 Kestrel이 제공하지 않는 일부 기능을 제공합니다.

Important

HTTP.sys는 ASP.NET Core 모듈과 호환되지 않으므로 IIS 또는 IIS Express와 함께 사용될 수 없습니다.

HTTP.sys는 다음과 같은 기능을 지원합니다.

  • Windows 인증
  • 포트 공유
  • SNI를 사용하는 HTTPS
  • TLS를 통한 HTTP/2(Windows 10 이상)
  • 직접 파일 전송
  • 응답 캐싱
  • WebSockets(Windows 8 이상)

지원되는 Windows 버전:

  • Windows 7 이상
  • Windows Server 2008 R2 이상

샘플 코드 보기 및 다운로드(다운로드 방법)

HTTP.sys를 사용하는 경우

HTTP.sys는 다음과 같은 배포에 유용합니다.

  • IIS를 사용하지 않고 인터넷에 서버를 직접 노출해야 하는 경우

    HTTP.sys communicates directly with the Internet

  • 내부 배포에는 Kestrel에서 사용할 수 없는 기능이 필요합니다. 자세한 내용은 Kestrel 및 HTTP.sys를 참조하세요.

    HTTP.sys communicates directly with the internal network

HTTP.sys는 많은 유형의 공격으로부터 보호하고 모든 기능을 갖춘 웹 서버의 견고성, 보안 및 확장성을 제공하는 완성도 높은 기술입니다. IIS 자체는 HTTP.sys 위에 HTTP 수신기로 실행됩니다.

HTTP/2 지원

다음 기본 요구 사항이 충족되는 경우 ASP.NET Core 앱에 대해HTTP/2가 사용 설정됩니다.

HTTP/2 연결이 설정된 경우 HttpRequest.Protocol에서 HTTP/2을 보고합니다.

HTTP/2는 기본적으로 사용됩니다. HTTP/2 연결이 설정되지 않는 경우 연결이 HTTP/1.1로 대체됩니다. Windows의 이후 릴리스에서는 HTTP.sys를 사용하여 HTTP/2를 사용하지 않도록 하는 기능을 포함하여 HTTP/2 구성 플래그를 사용할 수 있습니다.

HTTP/3 지원

다음 기본 요구 사항이 충족되는 경우 ASP.NET Core 앱에 대해HTTP/3가 사용 설정됩니다.

이전 Windows 11 빌드 버전을 사용하려면 Windows 참가자 빌드를 사용해야 할 수 있습니다.

HTTP/3은 alt-svc 헤더를 통해 HTTP/1.1 또는 HTTP/2에서 업그레이드로 검색됩니다. 즉, 첫 번째 요청에서 일반적으로 HTTP/1.1 또는 HTTP/2를 사용한 후에 HTTP/3으로 전환합니다. Http.Sys는 alt-svc 헤더를 자동으로 추가하지 않으며 애플리케이션에서 추가해야 합니다. 다음 코드는 alt-svc 응답 헤더를 추가하는 미들웨어 예제입니다.

app.Use((context, next) =>
{
    context.Response.Headers.AltSvc = "h3=\":443\"";
    return next(context);
});

이전 코드를 요청 파이프라인의 초기에 배치합니다.

또한 Http.Sys는 응답 헤더 대신 AltSvc HTTP/2 프로토콜 메시지 전송을 지원하여 HTTP/3을 사용할 수 있음을 클라이언트에 알립니다. EnableAltSvc 레지스트리 키를 참조하세요. 이렇게 하려면 IP 주소 대신 호스트 이름을 사용하는 netsh sslcert 바인딩이 필요합니다.

Kerberos를 사용하여 커널 모드 인증

HTTP.sys는 Kerberos 인증 프로토콜을 사용하여 커널 모드 인증에 위임합니다. 사용자 모드 인증은 Kerberos 및 HTTP.sys로 지원되지 않습니다. 머신 계정은 Active Directory에서 가져온 Kerberos 토큰/티켓의 암호를 해독하는 데 사용되고 사용자를 인증하는 서버에 클라이언트에 의해 전달되어야 합니다. 앱의 사용자가 아닌 호스트에 대해 SPN(서비스 사용자 이름)을 등록합니다.

HTTP.sys 사용 방법

HTTP.sys를 사용하도록 ASP.NET Core 앱 구성

호스트를 빌드할 때 UseHttpSys 확장 메서드를 호출하여 필요한 HttpSysOptions를 지정합니다. 다음 예제에서는 옵션을 기본값으로 설정합니다.

public static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
        .ConfigureWebHostDefaults(webBuilder =>
        {
            webBuilder.UseHttpSys(options =>
            {
                options.AllowSynchronousIO = false;
                options.Authentication.Schemes = AuthenticationSchemes.None;
                options.Authentication.AllowAnonymous = true;
                options.MaxConnections = null;
                options.MaxRequestBodySize = 30000000;
                options.UrlPrefixes.Add("http://localhost:5005");
            });
            webBuilder.UseStartup<Startup>();
        });

추가 HTTP.sys 구성은 레지스트리 설정을 통해 처리됩니다.

HTTP.sys 옵션에 대한 자세한 내용은 HttpSysOptions를 참조하세요.

MaxRequestBodySize

요청 본문에 대해 허용되는 최대 크기(바이트)입니다. null로 설정하면 최대 요청 본문 크기는 무제한입니다. 항상 무제한인 업그레이드된 연결에는 이 제한이 영향을 미치지 않습니다.

단일 IActionResult에 대해 ASP.NET Core MVC 앱에서 제한을 재정의할 때는 작업 메서드에서 RequestSizeLimitAttribute 특성을 사용하는 방법이 좋습니다.

[RequestSizeLimit(100000000)]
public IActionResult MyActionMethod()

앱에서 요청을 읽기 시작한 후 요청에 대한 제한을 구성하려고 하면 예외가 throw됩니다. IsReadOnly 속성을 사용하여 MaxRequestBodySize 속성이 제한을 구성하기에 너무 늦은, 읽기 전용 상태인지를 나타낼 수 있습니다.

앱에서 요청별로 MaxRequestBodySize를 재정의해야 하는 경우 IHttpMaxRequestBodySizeFeature를 사용합니다.

public void Configure(IApplicationBuilder app, IWebHostEnvironment env, 
    ILogger<Startup> logger, IServer server)
{
    app.Use(async (context, next) =>
    {
        context.Features.Get<IHttpMaxRequestBodySizeFeature>()
            .MaxRequestBodySize = 10 * 1024;

        var serverAddressesFeature = 
            app.ServerFeatures.Get<IServerAddressesFeature>();
        var addresses = string.Join(", ", serverAddressesFeature?.Addresses);

        logger.LogInformation("Addresses: {Addresses}", addresses);

        await next.Invoke();
    });

    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Error");
    }

    app.UseStaticFiles();
    app.UseRouting();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapRazorPages();
    });
}

Visual Studio를 사용하는 경우 앱이 IIS 또는 IIS Express를 실행하도록 구성되지 않았는지 확인합니다.

Visual Studio에서 기본 실행 프로필은 IIS Express용입니다. 프로젝트를 콘솔 앱으로 실행하려면 다음 스크린샷에 표시된 것처럼 선택한 프로필을 수동으로 변경합니다.

Select console app profile

Windows Server 구성

  1. 앱용으로 열 포트를 결정하고 Windows 방화벽 또는 New-NetFirewallRule PowerShell cmdlet을 통해 방화벽 포트를 열어 HTTP.sys에 도달하는 트래픽을 허용합니다. 다음 명령 및 앱 구성에서는 포트 443이 사용됩니다.

  2. Azure VM에 배포할 경우 네트워크 보안 그룹에서 포트를 엽니다. 다음 명령 및 앱 구성에서는 포트 443이 사용됩니다.

  3. 필요한 경우 X.509 인증서를 구하여 설치합니다.

    Windows에서 New-SelfSignedCertificate PowerShell cmdlet을 사용하여 자체 서명된 인증서를 만듭니다. 지원되지 않는 예는 UpdateIISExpressSSLForChrome.ps1을 참조하세요.

    서버의 로컬 머신>개인 저장소에 자체 서명 또는 CA 서명 인증서를 설치합니다.

  4. 앱이 프레임워크 종속 배포인 경우 .NET Core, .NET Framework 또는 둘 다(앱이 NET Framework를 대상으로 하는 .NET Core 앱인 경우)를 설치합니다.

    앱이 자체 포함 배포인 경우 앱의 배포에 런타임이 포함됩니다. 서버에 프레임워크를 설치할 필요가 없습니다.

  5. 앱에서 URL 및 포트를 구성합니다.

    기본적으로 ASP.NET Core는 http://localhost:5000으로 바인딩합니다. URL 접두사 및 포트를 구성하려면 다음 옵션을 사용합니다.

    다음 코드 예제는 포트 443에서 서버의 로컬 IP 주소 10.0.0.4와 함께 UrlPrefixes를 사용하는 방법을 보여 줍니다.

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseHttpSys(options =>
                {
                    options.UrlPrefixes.Add("https://10.0.0.4:443");
                });
                webBuilder.UseStartup<Startup>();
            });
    

    UrlPrefixes의 장점은 형식이 잘못된 접두사에 대해 오류 메시지가 즉시 생성된다는 점입니다.

    UrlPrefixes의 설정은 UseUrls/urls/ASPNETCORE_URLS 설정을 재정의합니다. 따라서 UseUrls, urlsASPNETCORE_URLS 환경 변수의 장점은 Kestrel과 HTTP.sys 간에 전환하기가 쉽다는 것입니다.

    HTTP.sys는 HTTP Server API UrlPrefix 문자열 형식을 사용합니다.

    Warning

    최상위 와일드카드 바인딩(http://*:80/http://+:80)을 사용하지 않아야 합니다. 최상위 와일드카드 바인딩으로 인해 앱 보안 취약성이 생길 수 있습니다. 강력한 와일드카드와 약한 와일드카드 모두에 적용됩니다. 와일드카드보다는 명시적 호스트 이름 또는 IP 주소를 사용합니다. 전체 부모 도메인을 제어하는 경우 하위 도메인 와일드카드 바인딩(예: *.mysub.com)은 보안 위험이 아닙니다(취약한 *.com과 반대임). 자세한 내용은 RFC 9110: 섹션 7.2: 호스트 및 :authority를 참조하세요.

  6. 서버에 URL 접두사를 미리 등록합니다.

    HTTP.sys 구성에 대한 기본 제공 도구는 netsh.exe입니다. netsh.exe는 URL 접두사를 예약하고 X.509 인증서를 할당하는 데 사용됩니다. 도구를 사용하려면 관리자 권한이 필요합니다.

    netsh.exe 도구를 사용하여 앱의 URL을 등록합니다.

    netsh http add urlacl url=<URL> user=<USER>
    
    • <URL>: 정규화된 URL(Uniform Resource Locator)입니다. 와일드카드 바인딩을 사용하지 마세요. 유효한 호스트 이름 또는 로컬 IP 주소를 사용합니다. ‘URL에는 후행 슬래시가 포함되어야 합니다.’
    • <USER>: 사용자 또는 사용자 그룹 이름을 지정합니다.

    다음 예제에서 서버의 로컬 IP 주소는 10.0.0.4입니다.

    netsh http add urlacl url=https://10.0.0.4:443/ user=Users
    

    URL이 등록되면 도구가 URL reservation successfully added로 응답합니다.

    등록된 URL을 삭제하려면 delete urlacl 명령을 사용합니다.

    netsh http delete urlacl url=<URL>
    
  7. 서버에 X.509 인증서를 등록합니다.

    netsh.exe 도구를 사용하여 앱의 인증서를 등록합니다.

    netsh http add sslcert ipport=<IP>:<PORT> certhash=<THUMBPRINT> appid="{<GUID>}"
    
    • <IP>: 바인딩의 로컬 IP 주소를 지정합니다. 와일드카드 바인딩을 사용하지 마세요. 유효한 IP 주소를 사용합니다.
    • <PORT>: 바인딩의 포트를 지정합니다.
    • <THUMBPRINT>: X.509 인증서 지문입니다.
    • <GUID>: 정보를 위해 앱을 나타내는 개발자 생성 GUID입니다.

    참조용으로 GUID를 패키지 태그로 앱에 저장합니다.

    • Visual Studio에서:
      • 솔루션 탐색기에서 앱을 마우스 오른쪽 단추로 클릭하고 속성을 선택하여 앱의 프로젝트 속성을 엽니다.
      • 패키지 탭을 선택합니다.
      • 태그 필드에 직접 만든 GUID를 입력합니다.
    • Visual Studio를 사용하지 않는 경우:
      • 앱의 프로젝트 파일을 엽니다.

      • 직접 만든 GUID를 사용하여 <PackageTags> 속성을 새로운 또는 기존 <PropertyGroup>에 추가합니다.

        <PropertyGroup>
          <PackageTags>9412ee86-c21b-4eb8-bd89-f650fbf44931</PackageTags>
        </PropertyGroup>
        

    다음 예제에서

    • 서버의 로컬 IP 주소는 10.0.0.4입니다.
    • 온라인 임의 GUID 생성기는 appid 값을 제공합니다.
    netsh http add sslcert 
        ipport=10.0.0.4:443 
        certhash=b66ee04419d4ee37464ab8785ff02449980eae10 
        appid="{9412ee86-c21b-4eb8-bd89-f650fbf44931}"
    

    인증서가 등록되면 도구가 SSL Certificate successfully added로 응답합니다.

    인증서 등록을 삭제하려면 delete sslcert 명령을 사용합니다.

    netsh http delete sslcert ipport=<IP>:<PORT>
    

    netsh.exe에 대한 참조 문서입니다.

  8. 앱을 실행합니다.

    1024보다 큰 포트 번호로 HTTP(HTTPS 아님)를 사용하여 localhost에 바인딩하는 경우에는 앱을 실행하는 데 관리자 권한이 필요하지 않습니다. 다른 구성(예: 로컬 IP 주소 사용 또는 포트 443에 바인딩)의 경우 관리자 권한으로 앱을 실행합니다.

    이 앱은 서버의 공용 IP 주소에서 응답합니다. 이 예제에서는 서버가 104.214.79.47의 공용 IP 주소에 있는 인터넷에서 연결됩니다.

    이 예제에는 개발 인증서가 사용됩니다. 브라우저의 신뢰할 수 없는 인증서 경고를 무시한 후 페이지가 안전하게 로드됩니다.

    Browser window showing the app's Index page loaded

프록시 서버 및 부하 분산 장치 시나리오

인터넷 또는 회사 네트워크의 요청과 상호 작용하는 HTTP.sys에서 호스팅하는 앱의 경우, 프록시 서버 및 부하 분산 장치 뒤에서 호스팅할 때 추가 구성이 필요할 수 있습니다. 자세한 내용은 프록시 서버 및 부하 분산 장치를 사용하도록 ASP.NET Core 구성을 참조하세요.

gRPC를 지원하기 위한 고급 HTTP/2 기능

HTTP.sys의 추가 HTTP/2 기능은 응답 트레일러 및 초기화 프레임 전송을 위한 지원을 포함하여 gRPC를 지원합니다.

HTTP.sys를 사용하여 gRPC를 실행하기 위한 요구 사항:

  • Windows 11 Build 22000 이상, Windows Server 2022 Build 20348 이상.
  • TLS 1.2 이상 연결

트레일러

HTTP 트레일러는 응답 본문이 전송된 후에 전송된다는 점을 제외하고 HTTP 헤더와 유사합니다. IIS 및 HTTP.sys의 경우 HTTP/2 응답 트레일러만 지원됩니다.

if (httpContext.Response.SupportsTrailers())
{
    httpContext.Response.DeclareTrailer("trailername");	

    // Write body
    httpContext.Response.WriteAsync("Hello world");

    httpContext.Response.AppendTrailer("trailername", "TrailerValue");
}

앞의 예제 코드에서:

  • SupportsTrailers는 응답을 위해 트레일러가 지원되는지 확인합니다.
  • DeclareTrailerTrailer 응답 헤더에 지정된 트레일러 이름을 추가합니다. 응답 트레일러 선언은 선택 사항이지만 권장됩니다. DeclareTrailer가 호출되는 경우 해당 트레일러는 응답 헤더가 전송되기 전에 있어야 합니다.
  • AppendTrailer는 트레일러를 추가합니다.

Reset

초기화를 사용하면 서버에서 지정된 오류 코드를 사용하여 HTTP/2 요청을 초기화할 수 있습니다. 초기화 요청은 중단된 것으로 간주합니다.

var resetFeature = httpContext.Features.Get<IHttpResetFeature>();
resetFeature.Reset(errorCode: 2);

이전 코드 예제의 ResetINTERNAL_ERROR 오류 코드를 지정합니다. HTTP/2 오류 코드에 관한 자세한 내용은 HTTP/2 사양 오류 코드 섹션을 참조하세요.

추가 리소스

HTTP.sys는 Windows에서만 실행되는 ASP.NET Core에 대한 웹 서버입니다. HTTP.sys는 Kestrel 서버에 대한 대안이며 Kestrel이 제공하지 않는 일부 기능을 제공합니다.

Important

HTTP.sys는 ASP.NET Core 모듈과 호환되지 않으므로 IIS 또는 IIS Express와 함께 사용될 수 없습니다.

HTTP.sys는 다음과 같은 기능을 지원합니다.

  • Windows 인증
  • 포트 공유
  • SNI를 사용하는 HTTPS
  • TLS를 통한 HTTP/2(Windows 10 이상)
  • 직접 파일 전송
  • 응답 캐싱
  • WebSockets(Windows 8 이상)

지원되는 Windows 버전:

  • Windows 7 이상
  • Windows Server 2008 R2 이상

샘플 코드 보기 및 다운로드(다운로드 방법)

HTTP.sys를 사용하는 경우

HTTP.sys는 다음과 같은 배포에 유용합니다.

  • IIS를 사용하지 않고 인터넷에 서버를 직접 노출해야 하는 경우

    HTTP.sys communicates directly with the Internet

  • 내부 배포에는 Kestrel에서 사용할 수 없는 기능이 필요합니다. 자세한 내용은 Kestrel 및 HTTP.sys를 참조하세요.

    HTTP.sys communicates directly with the internal network

HTTP.sys는 많은 유형의 공격으로부터 보호하고 모든 기능을 갖춘 웹 서버의 견고성, 보안 및 확장성을 제공하는 완성도 높은 기술입니다. IIS 자체는 HTTP.sys 위에 HTTP 수신기로 실행됩니다.

HTTP/2 지원

다음 기본 요구 사항이 충족되는 경우 ASP.NET Core 앱에 대해HTTP/2가 사용됩니다.

HTTP/2 연결이 설정된 경우 HttpRequest.Protocol에서 HTTP/2을 보고합니다.

HTTP/2는 기본적으로 사용됩니다. HTTP/2 연결이 설정되지 않는 경우 연결이 HTTP/1.1로 대체됩니다. Windows의 이후 릴리스에서는 HTTP.sys를 사용하여 HTTP/2를 사용하지 않도록 하는 기능을 포함하여 HTTP/2 구성 플래그를 사용할 수 있습니다.

Kerberos를 사용하여 커널 모드 인증

HTTP.sys는 Kerberos 인증 프로토콜을 사용하여 커널 모드 인증에 위임합니다. 사용자 모드 인증은 Kerberos 및 HTTP.sys로 지원되지 않습니다. 머신 계정은 Active Directory에서 가져온 Kerberos 토큰/티켓의 암호를 해독하는 데 사용되고 사용자를 인증하는 서버에 클라이언트에 의해 전달되어야 합니다. 앱의 사용자가 아닌 호스트에 대해 SPN(서비스 사용자 이름)을 등록합니다.

HTTP.sys 사용 방법

HTTP.sys를 사용하도록 ASP.NET Core 앱 구성

호스트를 빌드할 때 UseHttpSys 확장 메서드를 호출하여 필요한 HttpSysOptions를 지정합니다. 다음 예제에서는 옵션을 기본값으로 설정합니다.

public static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
        .ConfigureWebHostDefaults(webBuilder =>
        {
            webBuilder.UseHttpSys(options =>
            {
                options.AllowSynchronousIO = false;
                options.Authentication.Schemes = AuthenticationSchemes.None;
                options.Authentication.AllowAnonymous = true;
                options.MaxConnections = null;
                options.MaxRequestBodySize = 30000000;
                options.UrlPrefixes.Add("http://localhost:5005");
            });
            webBuilder.UseStartup<Startup>();
        });

추가 HTTP.sys 구성은 레지스트리 설정을 통해 처리됩니다.

HTTP.sys 옵션

속성 설명 기본값
AllowSynchronousIO HttpContext.Request.BodyHttpContext.Response.Body에 대해 동기 입력/출력이 허용되는지 여부를 제어합니다. false
Authentication.AllowAnonymous 익명 요청을 허용합니다. true
Authentication.Schemes 허용되는 인증 체계를 지정합니다. 수신기를 삭제하기 전에 언제든지 수정할 수 있습니다. 값은 AuthenticationSchemes 열거형: Basic, Kerberos, Negotiate, None, NTLM에서 제공됩니다. None
EnableResponseCaching 적합한 헤더가 있는 응답에 대해 커널 모드 캐싱을 시도합니다. 응답에 Set-Cookie, Vary 또는 Pragma 헤더가 포함될 수 없습니다. publicshared-max-age 또는 max-age 값인 Cache-Control 헤더나 Expires 헤더가 포함되어야 합니다. true
Http503Verbosity 제한 조건으로 인해 요청을 거부할 때 HTTP.sys 동작입니다. Http503VerbosityLevel.
기본
MaxAccepts 최대 동시 승인 수입니다. 5 × 환경.
ProcessorCount
MaxConnections 허용되는 최대 동시 연결 수입니다. 무한의 경우 -1을 사용합니다. 레지스트리의 시스템 수준 설정을 사용하려면 null을 사용합니다. null
(시스템 수준
설정)
MaxRequestBodySize MaxRequestBodySize 섹션을 참조하세요. 30000000바이트
(~28.6MB)
RequestQueueLimit 큐에 대기할 수 있는 최대 요청 수입니다. 1000
RequestQueueMode 이는 서버가 요청 큐를 만들고 구성하는 것을 담당하는지, 아니면 기존 큐에 연결해야 할지를 나타냅니다.
기존 큐에 연결하는 경우 대부분의 기존 구성 옵션이 적용되지 않습니다.
RequestQueueMode.Create
RequestQueueName HTTP.sys 요청 큐의 이름입니다. null(익명 큐)
ThrowWriteExceptions 클라이언트 연결 해제로 인해 실패한 응답 본문 쓰기가 예외를 throw하거나 정상적으로 완료되어야 하는지 여부를 나타납니다. false
(정상적으로 완료)
Timeouts 레지스트리에 구성될 수도 있는 HTTP.sys TimeoutManager 구성을 표시합니다. API 링크를 따라 기본값을 포함하여 각 설정에 대해 자세히 알아보세요.
UrlPrefixes UrlPrefixCollection을 지정하여 HTTP.sys를 등록합니다. 가장 유용한 것은 UrlPrefixCollection.Add컬렉션에 접두사를 추가하는 데 사용되는 것입니다. 이러한 API는 수신기를 삭제하기 전에 언제든지 수정할 수 있습니다.

MaxRequestBodySize

요청 본문에 대해 허용되는 최대 크기(바이트)입니다. null로 설정하면 최대 요청 본문 크기는 무제한입니다. 항상 무제한인 업그레이드된 연결에는 이 제한이 영향을 미치지 않습니다.

단일 IActionResult에 대해 ASP.NET Core MVC 앱에서 제한을 재정의할 때는 작업 메서드에서 RequestSizeLimitAttribute 특성을 사용하는 방법이 좋습니다.

[RequestSizeLimit(100000000)]
public IActionResult MyActionMethod()

앱에서 요청을 읽기 시작한 후 요청에 대한 제한을 구성하려고 하면 예외가 throw됩니다. IsReadOnly 속성을 사용하여 MaxRequestBodySize 속성이 제한을 구성하기에 너무 늦은, 읽기 전용 상태인지를 나타낼 수 있습니다.

앱에서 요청별로 MaxRequestBodySize를 재정의해야 하는 경우 IHttpMaxRequestBodySizeFeature를 사용합니다.

public void Configure(IApplicationBuilder app, IWebHostEnvironment env, 
    ILogger<Startup> logger, IServer server)
{
    app.Use(async (context, next) =>
    {
        context.Features.Get<IHttpMaxRequestBodySizeFeature>()
            .MaxRequestBodySize = 10 * 1024;

        var serverAddressesFeature = 
            app.ServerFeatures.Get<IServerAddressesFeature>();
        var addresses = string.Join(", ", serverAddressesFeature?.Addresses);

        logger.LogInformation("Addresses: {Addresses}", addresses);

        await next.Invoke();
    });

    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Error");
    }

    app.UseStaticFiles();
    app.UseRouting();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapRazorPages();
    });
}

Visual Studio를 사용하는 경우 앱이 IIS 또는 IIS Express를 실행하도록 구성되지 않았는지 확인합니다.

Visual Studio에서 기본 실행 프로필은 IIS Express용입니다. 프로젝트를 콘솔 앱으로 실행하려면 다음 스크린샷에 표시된 것처럼 선택한 프로필을 수동으로 변경합니다.

Select console app profile

Windows Server 구성

  1. 앱용으로 열 포트를 결정하고 Windows 방화벽 또는 New-NetFirewallRule PowerShell cmdlet을 통해 방화벽 포트를 열어 HTTP.sys에 도달하는 트래픽을 허용합니다. 다음 명령 및 앱 구성에서는 포트 443이 사용됩니다.

  2. Azure VM에 배포할 경우 네트워크 보안 그룹에서 포트를 엽니다. 다음 명령 및 앱 구성에서는 포트 443이 사용됩니다.

  3. 필요한 경우 X.509 인증서를 구하여 설치합니다.

    Windows에서 New-SelfSignedCertificate PowerShell cmdlet을 사용하여 자체 서명된 인증서를 만듭니다. 지원되지 않는 예는 UpdateIISExpressSSLForChrome.ps1을 참조하세요.

    서버의 로컬 머신>개인 저장소에 자체 서명 또는 CA 서명 인증서를 설치합니다.

  4. 앱이 프레임워크 종속 배포인 경우 .NET Core, .NET Framework 또는 둘 다(앱이 NET Framework를 대상으로 하는 .NET Core 앱인 경우)를 설치합니다.

    앱이 자체 포함 배포인 경우 앱의 배포에 런타임이 포함됩니다. 서버에 프레임워크를 설치할 필요가 없습니다.

  5. 앱에서 URL 및 포트를 구성합니다.

    기본적으로 ASP.NET Core는 http://localhost:5000으로 바인딩합니다. URL 접두사 및 포트를 구성하려면 다음 옵션을 사용합니다.

    다음 코드 예제는 포트 443에서 서버의 로컬 IP 주소 10.0.0.4와 함께 UrlPrefixes를 사용하는 방법을 보여 줍니다.

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseHttpSys(options =>
                {
                    options.UrlPrefixes.Add("https://10.0.0.4:443");
                });
                webBuilder.UseStartup<Startup>();
            });
    

    UrlPrefixes의 장점은 형식이 잘못된 접두사에 대해 오류 메시지가 즉시 생성된다는 점입니다.

    UrlPrefixes의 설정은 UseUrls/urls/ASPNETCORE_URLS 설정을 재정의합니다. 따라서 UseUrls, urlsASPNETCORE_URLS 환경 변수의 장점은 Kestrel과 HTTP.sys 간에 전환하기가 쉽다는 것입니다.

    HTTP.sys는 HTTP Server API UrlPrefix 문자열 형식을 사용합니다.

    Warning

    최상위 와일드카드 바인딩(http://*:80/http://+:80)을 사용하지 않아야 합니다. 최상위 와일드카드 바인딩으로 인해 앱 보안 취약성이 생길 수 있습니다. 강력한 와일드카드와 약한 와일드카드 모두에 적용됩니다. 와일드카드보다는 명시적 호스트 이름 또는 IP 주소를 사용합니다. 전체 부모 도메인을 제어하는 경우 하위 도메인 와일드카드 바인딩(예: *.mysub.com)은 보안 위험이 아닙니다(취약한 *.com과 반대임). 자세한 내용은 RFC 9110: 섹션 7.2: 호스트 및 :authority를 참조하세요.

  6. 서버에 URL 접두사를 미리 등록합니다.

    HTTP.sys 구성에 대한 기본 제공 도구는 netsh.exe입니다. netsh.exe는 URL 접두사를 예약하고 X.509 인증서를 할당하는 데 사용됩니다. 도구를 사용하려면 관리자 권한이 필요합니다.

    netsh.exe 도구를 사용하여 앱의 URL을 등록합니다.

    netsh http add urlacl url=<URL> user=<USER>
    
    • <URL>: 정규화된 URL(Uniform Resource Locator)입니다. 와일드카드 바인딩을 사용하지 마세요. 유효한 호스트 이름 또는 로컬 IP 주소를 사용합니다. ‘URL에는 후행 슬래시가 포함되어야 합니다.’
    • <USER>: 사용자 또는 사용자 그룹 이름을 지정합니다.

    다음 예제에서 서버의 로컬 IP 주소는 10.0.0.4입니다.

    netsh http add urlacl url=https://10.0.0.4:443/ user=Users
    

    URL이 등록되면 도구가 URL reservation successfully added로 응답합니다.

    등록된 URL을 삭제하려면 delete urlacl 명령을 사용합니다.

    netsh http delete urlacl url=<URL>
    
  7. 서버에 X.509 인증서를 등록합니다.

    netsh.exe 도구를 사용하여 앱의 인증서를 등록합니다.

    netsh http add sslcert ipport=<IP>:<PORT> certhash=<THUMBPRINT> appid="{<GUID>}"
    
    • <IP>: 바인딩의 로컬 IP 주소를 지정합니다. 와일드카드 바인딩을 사용하지 마세요. 유효한 IP 주소를 사용합니다.
    • <PORT>: 바인딩의 포트를 지정합니다.
    • <THUMBPRINT>: X.509 인증서 지문입니다.
    • <GUID>: 정보를 위해 앱을 나타내는 개발자 생성 GUID입니다.

    참조용으로 GUID를 패키지 태그로 앱에 저장합니다.

    • Visual Studio에서:
      • 솔루션 탐색기에서 앱을 마우스 오른쪽 단추로 클릭하고 속성을 선택하여 앱의 프로젝트 속성을 엽니다.
      • 패키지 탭을 선택합니다.
      • 태그 필드에 직접 만든 GUID를 입력합니다.
    • Visual Studio를 사용하지 않는 경우:
      • 앱의 프로젝트 파일을 엽니다.

      • 직접 만든 GUID를 사용하여 <PackageTags> 속성을 새로운 또는 기존 <PropertyGroup>에 추가합니다.

        <PropertyGroup>
          <PackageTags>9412ee86-c21b-4eb8-bd89-f650fbf44931</PackageTags>
        </PropertyGroup>
        

    다음 예제에서

    • 서버의 로컬 IP 주소는 10.0.0.4입니다.
    • 온라인 임의 GUID 생성기는 appid 값을 제공합니다.
    netsh http add sslcert 
        ipport=10.0.0.4:443 
        certhash=b66ee04419d4ee37464ab8785ff02449980eae10 
        appid="{9412ee86-c21b-4eb8-bd89-f650fbf44931}"
    

    인증서가 등록되면 도구가 SSL Certificate successfully added로 응답합니다.

    인증서 등록을 삭제하려면 delete sslcert 명령을 사용합니다.

    netsh http delete sslcert ipport=<IP>:<PORT>
    

    netsh.exe에 대한 참조 문서입니다.

  8. 앱을 실행합니다.

    1024보다 큰 포트 번호로 HTTP(HTTPS 아님)를 사용하여 localhost에 바인딩하는 경우에는 앱을 실행하는 데 관리자 권한이 필요하지 않습니다. 다른 구성(예: 로컬 IP 주소 사용 또는 포트 443에 바인딩)의 경우 관리자 권한으로 앱을 실행합니다.

    이 앱은 서버의 공용 IP 주소에서 응답합니다. 이 예제에서는 서버가 104.214.79.47의 공용 IP 주소에 있는 인터넷에서 연결됩니다.

    이 예제에는 개발 인증서가 사용됩니다. 브라우저의 신뢰할 수 없는 인증서 경고를 무시한 후 페이지가 안전하게 로드됩니다.

    Browser window showing the app's Index page loaded

프록시 서버 및 부하 분산 장치 시나리오

인터넷 또는 회사 네트워크의 요청과 상호 작용하는 HTTP.sys에서 호스팅하는 앱의 경우, 프록시 서버 및 부하 분산 장치 뒤에서 호스팅할 때 추가 구성이 필요할 수 있습니다. 자세한 내용은 프록시 서버 및 부하 분산 장치를 사용하도록 ASP.NET Core 구성을 참조하세요.

gRPC를 지원하기 위한 고급 HTTP/2 기능

HTTP.sys의 추가 HTTP/2 기능은 응답 트레일러 및 초기화 프레임 전송을 위한 지원을 포함하여 gRPC를 지원합니다.

HTTP.sys를 사용하여 gRPC를 실행하기 위한 요구 사항:

  • Windows 10, OS 빌드 19041.508 이상
  • TLS 1.2 이상 연결

트레일러

HTTP 트레일러는 응답 본문이 전송된 후에 전송된다는 점을 제외하고 HTTP 헤더와 유사합니다. IIS 및 HTTP.sys의 경우 HTTP/2 응답 트레일러만 지원됩니다.

if (httpContext.Response.SupportsTrailers())
{
    httpContext.Response.DeclareTrailer("trailername");	

    // Write body
    httpContext.Response.WriteAsync("Hello world");

    httpContext.Response.AppendTrailer("trailername", "TrailerValue");
}

앞의 예제 코드에서:

  • SupportsTrailers는 응답을 위해 트레일러가 지원되는지 확인합니다.
  • DeclareTrailerTrailer 응답 헤더에 지정된 트레일러 이름을 추가합니다. 응답 트레일러 선언은 선택 사항이지만 권장됩니다. DeclareTrailer가 호출되는 경우 해당 트레일러는 응답 헤더가 전송되기 전에 있어야 합니다.
  • AppendTrailer는 트레일러를 추가합니다.

Reset

초기화를 사용하면 서버에서 지정된 오류 코드를 사용하여 HTTP/2 요청을 초기화할 수 있습니다. 초기화 요청은 중단된 것으로 간주합니다.

var resetFeature = httpContext.Features.Get<IHttpResetFeature>();
resetFeature.Reset(errorCode: 2);

이전 코드 예제의 ResetINTERNAL_ERROR 오류 코드를 지정합니다. HTTP/2 오류 코드에 관한 자세한 내용은 HTTP/2 사양 오류 코드 섹션을 참조하세요.

추가 리소스