Nginx를 사용하여 Linux에서 ASP.NET Core 호스트Host ASP.NET Core on Linux with Nginx

작성자: Sourabh ShirhattiBy Sourabh Shirhatti

이 가이드에서는 Ubuntu 16.04 Server에서 프로덕션 준비 ASP.NET Core 환경을 설정하는 방법을 설명합니다.This guide explains setting up a production-ready ASP.NET Core environment on an Ubuntu 16.04 server. 이 지침은 최신 버전의 Ubuntu에서 작동할 수 있지만 최신 버전에서 테스트되지는 않았습니다.These instructions likely work with newer versions of Ubuntu, but the instructions haven't been tested with newer versions.

ASP.NET Core에서 지원하는 다른 Linux 배포에 대한 자세한 내용은 Linux에서 .NET Core의 필수 구성 요소를 참조하세요.For information on other Linux distributions supported by ASP.NET Core, see Prerequisites for .NET Core on Linux.

참고

Ubuntu 14.04의 경우 Kestrel 프로세스를 모니터링하기 위한 솔루션으로 supervisord를 사용하는 것이 좋습니다.For Ubuntu 14.04, supervisord is recommended as a solution for monitoring the Kestrel process. systemd는 Ubuntu 14.04에서 사용할 수 없습니다.systemd isn't available on Ubuntu 14.04. Ubuntu 14.04 지침의 경우 이 항목의 이전 버전을 참조하세요.For Ubuntu 14.04 instructions, see the previous version of this topic.

이 가이드의 내용:This guide:

  • 기존 ASP.NET Core 앱을 역방향 프록시 서버 뒤에 배치합니다.Places an existing ASP.NET Core app behind a reverse proxy server.
  • 역방향 프록시 서버를 설정하여 Kestrel 웹 서버에 요청을 전달합니다.Sets up the reverse proxy server to forward requests to the Kestrel web server.
  • 웹앱이 시작 시 디먼으로 실행되는지 확인합니다.Ensures the web app runs on startup as a daemon.
  • 웹앱 다시 시작을 지원하도록 프로세스 관리 도구를 구성합니다.Configures a process management tool to help restart the web app.

사전 요구 사항Prerequisites

  1. sudo 권한을 가진 표준 사용자 계정으로 Ubuntu 16.04 Server에 액세스합니다.Access to an Ubuntu 16.04 server with a standard user account with sudo privilege.
  2. 서버에서 .NET Core 런타임을 설치합니다.Install the .NET Core runtime on the server.
    1. .NET Core 다운로드 페이지를 참조하세요.Visit the Download .NET Core page.
    2. 미리 보기가 아닌 최신 .NET Core 버전을 선택합니다.Select the latest non-preview .NET Core version.
    3. 앱 실행 - 런타임 에 있는 테이블에서 미리 보기가 아닌 최신 런타임을 다운로드합니다.Download the latest non-preview runtime in the table under Run apps - Runtime.
    4. Linux 패키지 관리자 지침 링크를 선택하고 Ubuntu 버전의 Ubuntu 지침을 따릅니다.Select the Linux Package manager instructions link and follow the Ubuntu instructions for your version of Ubuntu.
  3. 기존 ASP.NET Core 앱입니다.An existing ASP.NET Core app.

공유 프레임워크를 업그레이드한 후 나중에 언제든지 서버에서 호스트되는 ASP.NET Core 앱을 다시 시작합니다.At any point in the future after upgrading the shared framework, restart the ASP.NET Core apps hosted by the server.

앱 게시 및 복사Publish and copy over the app

프레임워크 종속 배포인 경우 앱을 구성합니다.Configure the app for a framework-dependent deployment.

앱을 로컬에서 실행하고 보안 연결(HTTPS)을 확인하도록 구성하지 않은 경우 다음 방법 중 하나를 채택합니다.If the app is run locally and isn't configured to make secure connections (HTTPS), adopt either of the following approaches:

  • 보안 로컬 연결을 처리하도록 앱을 구성합니다.Configure the app to handle secure local connections. 자세한 내용은 HTTPS 구성 섹션을 참조하세요.For more information, see the HTTPS configuration section.
  • Properties/launchSettings.json 파일의 applicationUrl 속성에서 https://localhost:5001(있는 경우)을 제거합니다.Remove https://localhost:5001 (if present) from the applicationUrl property in the Properties/launchSettings.json file.

개발 환경에서 dotnet publish를 실행하여 서버에서 실행할 수 있는 디렉터리(예: bin/Release/{TARGET FRAMEWORK MONIKER}/publish, 여기서 자리 표시자 {TARGET FRAMEWORK MONIKER}는 대상 프레임워크 모니커/TFM)로 앱을 패키징합니다.Run dotnet publish from the development environment to package an app into a directory (for example, bin/Release/{TARGET FRAMEWORK MONIKER}/publish, where the placeholder {TARGET FRAMEWORK MONIKER} is the Target Framework Moniker/TFM) that can run on the server:

dotnet publish --configuration Release

.NET Core 런타임을 서버에서 유지 관리하지 않으려는 경우 앱은 자체 포함된 배포로 게시될 수도 있습니다.The app can also be published as a self-contained deployment if you prefer not to maintain the .NET Core runtime on the server.

조직의 워크플로에 통합된 도구(예: SCP, SFTP)를 사용하여 ASP.NET Core 앱을 서버에 복사합니다.Copy the ASP.NET Core app to the server using a tool that integrates into the organization's workflow (for example, SCP, SFTP). var 디렉터리(예: var/www/helloapp)에서 웹앱을 찾는 것이 일반적입니다.It's common to locate web apps under the var directory (for example, var/www/helloapp).

참고

프로덕션 배포 시나리오에서 지속적인 통합 워크플로는 앱을 게시하고 자산을 서버로 복사하는 워크플로를 수행합니다.Under a production deployment scenario, a continuous integration workflow does the work of publishing the app and copying the assets to the server.

앱을 테스트합니다.Test the app:

  1. 명령줄에서 dotnet <app_assembly>.dll 앱을 실행하세요.From the command line, run the app: dotnet <app_assembly>.dll.
  2. 브라우저에서 http://<serveraddress>:<port>로 이동하여 앱이 Linux에서 로컬로 작동하는지 확인합니다.In a browser, navigate to http://<serveraddress>:<port> to verify the app works on Linux locally.

역방향 프록시 서버 구성Configure a reverse proxy server

역방향 프록시는 동적 웹앱을 지원하기 위한 일반적인 설정입니다.A reverse proxy is a common setup for serving dynamic web apps. 역방향 프록시는 HTTP 요청을 종료하고 이 요청을 ASP.NET Core 앱에 전달합니다.A reverse proxy terminates the HTTP request and forwards it to the ASP.NET Core app.

역방향 프록시 서버를 사용합니다.Use a reverse proxy server

Kestrel은 ASP.NET Core에서 동적 콘텐츠를 제공하는 데 유용합니다.Kestrel is great for serving dynamic content from ASP.NET Core. 그러나 웹 지원 기능은 IIS, Apache 또는 Nginx와 같은 서버만큼 기능이 다양하지 않습니다.However, the web serving capabilities aren't as feature rich as servers such as IIS, Apache, or Nginx. 역방향 프록시 서버는 정적 콘텐츠 지원, 요청 캐시, 요청 압축 및 HTTP 서버에서 HTTPS 종료 같은 작업을 오프로드할 수 있습니다.A reverse proxy server can offload work such as serving static content, caching requests, compressing requests, and HTTPS termination from the HTTP server. 역방향 프록시 서버는 전용 컴퓨터에 있거나 HTTP 서버와 함께 배포될 수 있습니다.A reverse proxy server may reside on a dedicated machine or may be deployed alongside an HTTP server.

이 가이드에서는 Nginx의 단일 인스턴스가 사용됩니다.For the purposes of this guide, a single instance of Nginx is used. 이 인스턴스는 HTTP 서버와 함께 동일한 서버에서 실행됩니다.It runs on the same server, alongside the HTTP server. 요구 사항에 따라 다른 설정을 선택할 수 있습니다.Based on requirements, a different setup may be chosen.

요청이 역방향 프록시에 의해 전달되므로 Microsoft.AspNetCore.HttpOverrides 패키지의 전달된 헤더 미들웨어를 사용합니다.Because requests are forwarded by reverse proxy, use the Forwarded Headers Middleware from the Microsoft.AspNetCore.HttpOverrides package. 이 미들웨어는 X-Forwarded-Proto 헤더를 사용하여 Request.Scheme을 업데이트하므로 리디렉션 URI 및 기타 보안 정책이 제대로 작동합니다.The middleware updates the Request.Scheme, using the X-Forwarded-Proto header, so that redirect URIs and other security policies work correctly.

전달된 헤더 미들웨어는 다른 미들웨어보다 먼저 실행해야 합니다.Forwarded Headers Middleware should run before other middleware. 이 순서를 지정하면 전달된 헤더 정보에 따라 달라지는 미들웨어는 처리하기 위해 헤더 값을 사용할 수 있습니다.This ordering ensures that the middleware relying on forwarded headers information can consume the header values for processing. 진단 및 오류 처리 미들웨어 다음에 전달된 헤더 미들웨어를 실행하려면 전달된 헤더 미들웨어 순서를 참조하세요.To run Forwarded Headers Middleware after diagnostics and error handling middleware, see Forwarded Headers Middleware order.

다른 미들웨어를 호출하기 전에 Startup.Configure의 맨 위에 있는 UseForwardedHeaders 메서드를 호출합니다.Invoke the UseForwardedHeaders method at the top of Startup.Configure before calling other middleware. X-Forwarded-ForX-Forwarded-Proto 헤더를 전달하도록 미들웨어를 구성합니다.Configure the middleware to forward the X-Forwarded-For and X-Forwarded-Proto headers:

using Microsoft.AspNetCore.HttpOverrides;

...

app.UseForwardedHeaders(new ForwardedHeadersOptions
{
    ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto
});

app.UseAuthentication();

미들웨어에 ForwardedHeadersOptions가 지정되지 않은 경우 전달할 기본 헤더는 None입니다.If no ForwardedHeadersOptions are specified to the middleware, the default headers to forward are None.

표준 localhost 주소(127.0.0.1)를 포함하여 루프백 주소(127.0.0.0/8, [::1])에서 실행 중인 프록시는 기본적으로 신뢰할 수 있습니다.Proxies running on loopback addresses (127.0.0.0/8, [::1]), including the standard localhost address (127.0.0.1), are trusted by default. 조직 내의 다른 신뢰할 수 있는 프록시 또는 네트워크가 인터넷과 웹 서버 간의 요청을 처리하는 경우 ForwardedHeadersOptions를 사용하여 KnownProxies 또는 KnownNetworks 목록에 추가합니다.If other trusted proxies or networks within the organization handle requests between the Internet and the web server, add them to the list of KnownProxies or KnownNetworks with ForwardedHeadersOptions. 다음 예제는 IP 주소 10.0.0.100의 신뢰할 수 있는 프록시 서버를 Startup.ConfigureServices의 전달된 헤더 미들웨어 KnownProxies에 추가합니다.The following example adds a trusted proxy server at IP address 10.0.0.100 to the Forwarded Headers Middleware KnownProxies in Startup.ConfigureServices:

using System.Net;

...

services.Configure<ForwardedHeadersOptions>(options =>
{
    options.KnownProxies.Add(IPAddress.Parse("10.0.0.100"));
});

자세한 내용은 프록시 서버 및 부하 분산 장치를 사용하도록 ASP.NET Core 구성를 참조하세요.For more information, see 프록시 서버 및 부하 분산 장치를 사용하도록 ASP.NET Core 구성.

Nginx 설치Install Nginx

apt-get을 사용하여 Nginx를 설치합니다.Use apt-get to install Nginx. 설치 관리자는 시스템 시작 시 Nginx를 디먼으로 실행하는 systemd 시작 스크립트를 만듭니다.The installer creates a systemd init script that runs Nginx as daemon on system startup. Ubuntu의 설치 지침은 Nginx: 공식 Debian/Ubuntu 패키지를 따릅니다.Follow the installation instructions for Ubuntu at Nginx: Official Debian/Ubuntu packages.

참고

선택적 Nginx 모듈이 필요한 경우 소스에서 Nginx를 빌드해야 할 수 있습니다.If optional Nginx modules are required, building Nginx from source might be required.

Nginx가 처음 설치되었으므로 다음을 실행하여 명시적으로 시작합니다.Since Nginx was installed for the first time, explicitly start it by running:

sudo service nginx start

브라우저에 Nginx에 대한 기본 방문 페이지가 표시되는지 확인합니다.Verify a browser displays the default landing page for Nginx. 방문 페이지는 http://<server_IP_address>/index.nginx-debian.html에 도달할 수 있습니다.The landing page is reachable at http://<server_IP_address>/index.nginx-debian.html.

Nginx 구성Configure Nginx

Nginx를 역방향 프록시로 구성하여 HTTP 요청을 ASP.NET Core 앱에 전달하려면 /etc/nginx/sites-available/default를 수정합니다.To configure Nginx as a reverse proxy to forward HTTP requests to your ASP.NET Core app, modify /etc/nginx/sites-available/default. 텍스트 편집기에서 해당 항목을 열고 콘텐츠를 다음으로 바꿉니다.Open it in a text editor, and replace the contents with the following:

server {
    listen        80;
    server_name   example.com *.example.com;
    location / {
        proxy_pass         http://localhost:5000;
        proxy_http_version 1.1;
        proxy_set_header   Upgrade $http_upgrade;
        proxy_set_header   Connection keep-alive;
        proxy_set_header   Host $host;
        proxy_cache_bypass $http_upgrade;
        proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header   X-Forwarded-Proto $scheme;
    }
}

앱이 SignalR 또는 Blazor Server 앱인 경우, 자세한 내용은 각각 ASP.NET Core SignalR 프로덕션 호스팅 및 크기 조정ASP.NET Core 호스트 및 배포 Blazor Server를 참조하세요.If the app is a SignalR or Blazor Server app see ASP.NET Core SignalR 프로덕션 호스팅 및 크기 조정 and ASP.NET Core 호스트 및 배포 Blazor Server respectively for more information.

server_name이 일치하지 않으면 Nginx는 기본 서버를 사용합니다.When no server_name matches, Nginx uses the default server. 기본 서버가 정의되지 않은 경우 구성 파일의 첫 번째 서버는 기본 서버입니다.If no default server is defined, the first server in the configuration file is the default server. 구성 파일에 있는 444 상태 코드를 반환하는 특정 기본 서버를 추가하는 것이 좋습니다.As a best practice, add a specific default server which returns a status code of 444 in your configuration file. 기본 서버 구성 예제는 다음과 같습니다.A default server configuration example is:

server {
    listen   80 default_server;
    # listen [::]:80 default_server deferred;
    return   444;
}

이전 구성 파일과 기본 서버를 사용하여 Nginx는 포트 80에서 호스트 헤더 example.com 또는 *.example.com가 포함된 공용 트래픽을 허용합니다.With the preceding configuration file and default server, Nginx accepts public traffic on port 80 with host header example.com or *.example.com. 이러한 호스트와 일치하지 않는 요청은 Kestrel로 전달되지 않습니다.Requests not matching these hosts won't get forwarded to Kestrel. Nginx는 일치하는 요청을 http://localhost:5000의 Kestrel에 전달합니다.Nginx forwards the matching requests to Kestrel at http://localhost:5000. 자세한 내용은 How nginx processes a request(nginx가 요청을 처리하는 방법)를 참조하세요.See How nginx processes a request for more information. Kestrel의 IP/포트를 변경하려면 Kestrel: 엔드포인트 구성을 참조하세요.To change Kestrel's IP/port, see Kestrel: Endpoint configuration.

경고

적절한 server_name 지시문을 지정하지 않으면 앱이 보안 취약성에 노출됩니다.Failure to specify a proper server_name directive exposes your app to security vulnerabilities. 전체 부모 도메인을 제어하는 경우 하위 도메인 와일드카드 바인딩(예: *.example.com)에는 이러한 보안 위험이 발생하지 않습니다(취약한 *.com과 반대임).Subdomain wildcard binding (for example, *.example.com) doesn't pose this security risk if you control the entire parent domain (as opposed to *.com, which is vulnerable). 자세한 내용은 rfc7230 섹션-5.4를 참조하세요.See rfc7230 section-5.4 for more information.

Nginx 구성이 설정되면 sudo nginx -t를 실행하여 구성 파일의 구문을 확인합니다.Once the Nginx configuration is established, run sudo nginx -t to verify the syntax of the configuration files. 구성 파일 테스트에 성공하면 sudo nginx -s reload를 실행하여 Nginx가 변경 내용을 선택하도록 합니다.If the configuration file test is successful, force Nginx to pick up the changes by running sudo nginx -s reload.

앱을 서버에서 직접 실행하려면:To directly run the app on the server:

  1. 앱의 디렉터리로 이동합니다.Navigate to the app's directory.
  2. dotnet <app_assembly.dll> 앱을 실행합니다. 여기서 app_assembly.dll은 앱의 어셈블리 파일 이름입니다.Run the app: dotnet <app_assembly.dll>, where app_assembly.dll is the assembly file name of the app.

앱이 서버에서 실행되지만 인터넷을 통해 응답하지 않는 경우 서버의 방화벽을 확인하고 포트 80이 열려 있는지 확인합니다.If the app runs on the server but fails to respond over the Internet, check the server's firewall and confirm that port 80 is open. Ubuntu Azure VM을 사용하는 경우 인바운드 포트 80 트래픽을 사용하는 NSG(네트워크 보안 그룹) 규칙을 추가합니다.If using an Azure Ubuntu VM, add a Network Security Group (NSG) rule that enables inbound port 80 traffic. 인바운드 규칙을 사용할 때 아웃바운드 트래픽이 자동으로 부여되므로 아웃바운드 포트 80 규칙을 사용하도록 설정할 필요가 없습니다.There's no need to enable an outbound port 80 rule, as the outbound traffic is automatically granted when the inbound rule is enabled.

앱 테스트를 완료한 후에 명령 프롬프트에서 Ctrl+C를 사용하여 앱을 종료합니다.When done testing the app, shut the app down with Ctrl+C at the command prompt.

앱 모니터링Monitor the app

서버는 http://<serveraddress>:80에 대해 실행된 요청을 http://127.0.0.1:5000의 Kestrel에서 실행되는 ASP.NET Core 앱에 전달하도록 설정됩니다.The server is setup to forward requests made to http://<serveraddress>:80 on to the ASP.NET Core app running on Kestrel at http://127.0.0.1:5000. 그러나 Nginx는 Kestrel 프로세스를 관리하도록 설정되지 않습니다.However, Nginx isn't set up to manage the Kestrel process. systemd를 사용하여 기본 웹앱을 시작 및 모니터링하기 위한 서비스 파일을 만들 수 있습니다.systemd can be used to create a service file to start and monitor the underlying web app. systemd는 프로세스를 시작, 중지 및 관리하기 위한 다양하고 강력한 기능을 제공하는 init 시스템입니다.systemd is an init system that provides many powerful features for starting, stopping, and managing processes.

서비스 파일 만들기Create the service file

서비스 정의 파일을 만듭니다.Create the service definition file:

sudo nano /etc/systemd/system/kestrel-helloapp.service

앱에 대한 예제 서비스 파일은 다음과 같습니다.The following is an example service file for the app:

[Unit]
Description=Example .NET Web API App running on Ubuntu

[Service]
WorkingDirectory=/var/www/helloapp
ExecStart=/usr/bin/dotnet /var/www/helloapp/helloapp.dll
Restart=always
# Restart service after 10 seconds if the dotnet service crashes:
RestartSec=10
KillSignal=SIGINT
SyslogIdentifier=dotnet-example
User=www-data
Environment=ASPNETCORE_ENVIRONMENT=Production
Environment=DOTNET_PRINT_TELEMETRY_MESSAGE=false

[Install]
WantedBy=multi-user.target

앞의 예제에서 서비스를 관리하는 사용자는 User 옵션으로 지정됩니다.In the preceding example, the user that manages the service is specified by the User option. 사용자(www-data)가 존재해야 하며 앱 파일에 대한 적절한 소유권이 있어야 합니다.The user (www-data) must exist and have proper ownership of the app's files.

TimeoutStopSec를 사용하여 초기 인터럽트 신호를 받은 후 앱이 종료되기를 기다리는 기간을 구성합니다.Use TimeoutStopSec to configure the duration of time to wait for the app to shut down after it receives the initial interrupt signal. 이 기간 내에 앱이 종료되지 않으면 앱을 종료하기 위해 SIGKILL이 실행됩니다.If the app doesn't shut down in this period, SIGKILL is issued to terminate the app. 단위 없는 초로 된 값(예: 150) 또는 시간 범위 값(예: 2min 30s)으로 값을 입력하거나, 시간 제한을 사용하지 않으려면 infinity를 입력합니다.Provide the value as unitless seconds (for example, 150), a time span value (for example, 2min 30s), or infinity to disable the timeout. TimeoutStopSec는 관리자 구성 파일(systemd-system.conf, system.conf.d, systemd-user.conf, user.conf.d)에서 DefaultTimeoutStopSec의 값으로 기본 설정됩니다.TimeoutStopSec defaults to the value of DefaultTimeoutStopSec in the manager configuration file (systemd-system.conf, system.conf.d, systemd-user.conf, user.conf.d). 대부분의 배포에서 기본 시간 제한은 90초입니다.The default timeout for most distributions is 90 seconds.

# The default value is 90 seconds for most distributions.
TimeoutStopSec=90

Linux에는 대/소문자를 구분하는 파일 시스템이 있습니다.Linux has a case-sensitive file system. ASPNETCORE_ENVIRONMENTProduction으로 설정하면 appsettings.production.json이 아니라 appsettings.Production.json구성 파일이 검색됩니다.Setting ASPNETCORE_ENVIRONMENT to Production results in searching for the configuration file appsettings.Production.json, not appsettings.production.json.

일부 값(예: SQL 연결 문자열)은 환경 변수를 읽기 위해 구성 공급자에 대해 이스케이프되어야 합니다.Some values (for example, SQL connection strings) must be escaped for the configuration providers to read the environment variables. 다음 명령을 사용하여 구성 파일에서 사용할 제대로 이스케이프된 값을 생성합니다.Use the following command to generate a properly escaped value for use in the configuration file:

systemd-escape "<value-to-escape>"

콜론(:) 구분 기호는 환경 변수 이름에서 지원되지 않습니다.Colon (:) separators aren't supported in environment variable names. 콜론 대신 이중 밑줄(__)을 사용합니다.Use a double underscore (__) in place of a colon. 환경 변수 구성 공급자는 환경 변수를 구성으로 읽을 때 이중 밑줄을 콜론으로 변환합니다.The Environment Variables configuration provider converts double-underscores into colons when environment variables are read into configuration. 다음 예제에서 연결 문자열 키 ConnectionStrings:DefaultConnection은 서비스 정의 파일에 ConnectionStrings__DefaultConnection으로 설정됩니다.In the following example, the connection string key ConnectionStrings:DefaultConnection is set into the service definition file as ConnectionStrings__DefaultConnection:

콜론(:) 구분 기호는 환경 변수 이름에서 지원되지 않습니다.Colon (:) separators aren't supported in environment variable names. 콜론 대신 이중 밑줄(__)을 사용합니다.Use a double underscore (__) in place of a colon. 환경 변수 구성 공급자는 환경 변수를 구성으로 읽을 때 이중 밑줄을 콜론으로 변환합니다.The Environment Variables configuration provider converts double-underscores into colons when environment variables are read into configuration. 다음 예제에서 연결 문자열 키 ConnectionStrings:DefaultConnection은 서비스 정의 파일에 ConnectionStrings__DefaultConnection으로 설정됩니다.In the following example, the connection string key ConnectionStrings:DefaultConnection is set into the service definition file as ConnectionStrings__DefaultConnection:

Environment=ConnectionStrings__DefaultConnection={Connection String}

파일을 저장하고 서비스를 사용하도록 설정합니다.Save the file and enable the service.

sudo systemctl enable kestrel-helloapp.service

서비스를 시작하고 실행 중인지 확인합니다.Start the service and verify that it's running.

sudo systemctl start kestrel-helloapp.service
sudo systemctl status kestrel-helloapp.service

◝ kestrel-helloapp.service - Example .NET Web API App running on Ubuntu
    Loaded: loaded (/etc/systemd/system/kestrel-helloapp.service; enabled)
    Active: active (running) since Thu 2016-10-18 04:09:35 NZDT; 35s ago
Main PID: 9021 (dotnet)
    CGroup: /system.slice/kestrel-helloapp.service
            └─9021 /usr/local/bin/dotnet /var/www/helloapp/helloapp.dll

역방향 프록시를 구성하고 systemd를 통해 Kestrel을 관리하면 웹앱이 완전히 구성되고 로컬 컴퓨터(http://localhost)의 브라우저에서 웹앱에 액세스할 수 있습니다.With the reverse proxy configured and Kestrel managed through systemd, the web app is fully configured and can be accessed from a browser on the local machine at http://localhost. 차단 중인 방화벽이 없다면 원격 컴퓨터에서 액세스할 수도 있습니다.It's also accessible from a remote machine, barring any firewall that might be blocking. 응답 헤더를 검사하는 Server 헤더는 Kestrel에서 지원하는 ASP.NET Core 앱을 보여줍니다.Inspecting the response headers, the Server header shows the ASP.NET Core app being served by Kestrel.

HTTP/1.1 200 OK
Date: Tue, 11 Oct 2016 16:22:23 GMT
Server: Kestrel
Keep-Alive: timeout=5, max=98
Connection: Keep-Alive
Transfer-Encoding: chunked

로그 보기View logs

Kestrel을 사용하는 웹앱은 systemd를 사용하여 관리되므로 모든 이벤트 및 프로세스가 중앙형 저널에 기록됩니다.Since the web app using Kestrel is managed using systemd, all events and processes are logged to a centralized journal. 그러나 이 저널에는 systemd를 통해 관리하는 모든 서비스 및 프로세스에 대한 모든 항목이 포함됩니다.However, this journal includes all entries for all services and processes managed by systemd. kestrel-helloapp.service 관련 항목을 보려면 다음 명령을 사용합니다.To view the kestrel-helloapp.service-specific items, use the following command:

sudo journalctl -fu kestrel-helloapp.service

추가 필터링을 위해 --since today, --until 1 hour ago 같은 시간 옵션이나 이러한 옵션의 조합을 사용하여 반환되는 항목 수를 줄일 수 있습니다.For further filtering, time options such as --since today, --until 1 hour ago or a combination of these can reduce the amount of entries returned.

sudo journalctl -fu kestrel-helloapp.service --since "2016-10-18" --until "2016-10-18 04:00"

데이터 보호Data protection

ASP.NET Core 데이터 보호 스택은 인증 미들웨어(예: cookie 미들웨어) 및 CSRF(교차 사이트 요청 위조) 보호를 비롯한 여러 ASP.NET Core 미들웨어에 사용됩니다.The ASP.NET Core Data Protection stack is used by several ASP.NET Core middlewares, including authentication middleware (for example, cookie middleware) and cross-site request forgery (CSRF) protections. 사용자 코드에서 데이터 보호 API가 호출되지 않더라도 영구적 암호화 키 저장소를 만들도록 데이터 보호를 구성해야 합니다.Even if Data Protection APIs aren't called by user code, data protection should be configured to create a persistent cryptographic key store. 데이터 보호를 구성하지 않으면 키는 메모리에 보관되고 앱이 다시 시작되면 삭제됩니다.If data protection isn't configured, the keys are held in memory and discarded when the app restarts.

키 링이 메모리에 저장된 경우 앱을 다시 시작하면 다음과 같이 됩니다.If the key ring is stored in memory when the app restarts:

  • 모든 cookie 기반 인증 토큰이 무효화됩니다.All cookie-based authentication tokens are invalidated.
  • 사용자는 다음 요청에서 다시 로그인해야 합니다.Users are required to sign in again on their next request.
  • 키 링으로 보호된 데이터의 암호를 더 이상 해독할 수 없습니다.Any data protected with the key ring can no longer be decrypted. 여기에는 CSRF 토큰ASP.NET Core MVC TempData cookie가 포함될 수 있습니다.This may include CSRF tokens and ASP.NET Core MVC TempData cookies.

키 링을 유지하고 암호화하도록 데이터 보호를 구성하려면 다음을 참조하십시오.To configure data protection to persist and encrypt the key ring, see:

긴 요청 헤더 필드Long request header fields

프록시 서버 기본 설정은 일반적으로 플랫폼에 따라 요청 헤더 필드를 4K 또는 8K로 제한합니다.Proxy server default settings typically limit request header fields to 4 K or 8 K depending on the platform. 앱에 기본값보다 긴 필드가 필요할 수 있습니다(예: Azure Active Directory를 사용하는 앱).An app may require fields longer than the default (for example, apps that use Azure Active Directory). 더 긴 필드가 필요한 경우 프록시 서버의 기본 설정을 조정해야 합니다.If longer fields are required, the proxy server's default settings require adjustment. 적용할 값은 시나리오에 따라 달라집니다.The values to apply depend on the scenario. 자세한 내용은 서버의 설명서를 참조하세요.For more information, see your server's documentation.

경고

필요한 경우가 아니면 프록시 버퍼의 기본값을 늘리지 마세요.Don't increase the default values of proxy buffers unless necessary. 이러한 값을 늘리면 악의적인 사용자의 버퍼 오버런(오버플로) 및 DoS(서비스 거부) 공격의 위험이 증가됩니다.Increasing these values increases the risk of buffer overrun (overflow) and Denial of Service (DoS) attacks by malicious users.

앱 보안 유지Secure the app

AppArmor 사용Enable AppArmor

LSM(Linux Security Modules)은 Linux 2.6 이후 Linux 커널에 포함된 프레임워크입니다.Linux Security Modules (LSM) is a framework that's part of the Linux kernel since Linux 2.6. LSM은 보안 모듈의 다양한 구현을 지원합니다.LSM supports different implementations of security modules. AppArmor는 프로그램을 제한된 리소스 집합으로 한정할 수 있는 필수 Access Control 시스템을 구현하는 LSM입니다.AppArmor is a LSM that implements a Mandatory Access Control system which allows confining the program to a limited set of resources. AppArmor가 사용하도록 설정되고 제대로 구성되어 있는지 확인합니다.Ensure AppArmor is enabled and properly configured.

방화벽 구성Configure the firewall

사용되지 않는 모든 외부 포트를 닫습니다.Close off all external ports that are not in use. 복잡하지 않은 방화벽(ufw)은 방화벽을 구성하기 위한 CLI를 제공하여 iptables에 대한 프런트 엔드를 제공합니다.Uncomplicated firewall (ufw) provides a front end for iptables by providing a CLI for configuring the firewall.

경고

방화벽이 올바르게 구성되지 않으면 전체 시스템에 대한 액세스가 차단됩니다.A firewall will prevent access to the whole system if not configured correctly. 올바른 SSH 포트를 지정하지 못하면 SSH를 사용하여 시스템에 연결하는 경우 실직적으로 시스템에 액세스할 수 없게 됩니다.Failure to specify the correct SSH port will effectively lock you out of the system if you are using SSH to connect to it. 기본 포트는 22입니다.The default port is 22. 자세한 내용은 ufw 소개매뉴얼을 참조하세요.For more information, see the introduction to ufw and the manual.

ufw를 설치하고 필요한 모든 포트에서 트래픽을 허용하도록 구성합니다.Install ufw and configure it to allow traffic on any ports needed.

sudo apt-get install ufw

sudo ufw allow 22/tcp
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp

sudo ufw enable

Nginx 보안 유지Secure Nginx

Nginx 응답 이름 변경Change the Nginx response name

편집 src/http/ngx_http_header_filter_module.c:Edit src/http/ngx_http_header_filter_module.c:

static char ngx_http_server_string[] = "Server: Web Server" CRLF;
static char ngx_http_server_full_string[] = "Server: Web Server" CRLF;

옵션 구성Configure options

추가 필수 모듈을 사용하여 서버를 구성합니다.Configure the server with additional required modules. ModSecurity와 같은 웹앱 방화벽을 사용하여 앱을 강화해 보세요.Consider using a web app firewall, such as ModSecurity, to harden the app.

HTTPS 구성HTTPS configuration

보안(HTTPS) 로컬 연결을 위해 앱 구성Configure the app for secure (HTTPS) local connections

dotnet 실행 명령은 applicationUrl 속성(예: https://localhost:5001;http://localhost:5000)이 제공하는 URL에서 수신 대기하도록 앱을 구성하는 앱의 Properties/launchSettings.json 파일을 사용합니다.The dotnet run command uses the app's Properties/launchSettings.json file, which configures the app to listen on the URLs provided by the applicationUrl property (for example, https://localhost:5001;http://localhost:5000).

다음 방법 중 하나를 사용하여 dotnet run 명령 또는 개발 환경(Visual Studio Code에서 F5 또는 Ctrl+F5)에 개발 중인 인증서를 사용하도록 앱을 구성합니다.Configure the app to use a certificate in development for the dotnet run command or development environment (F5 or Ctrl+F5 in Visual Studio Code) using one of the following approaches:

보안 (HTTPS) 클라이언트 연결을 위해 역방향 프록시 구성Configure the reverse proxy for secure (HTTPS) client connections

  • 신뢰할 수 있는 CA(인증 기관)에서 발급된 유효한 인증서를 지정하여 포트 443에서 HTTPS 트래픽을 수신 대기하도록 서버를 구성합니다.Configure the server to listen to HTTPS traffic on port 443 by specifying a valid certificate issued by a trusted Certificate Authority (CA).

  • 다음 /etc/nginx/nginx.conf 파일에 설명된 일부 사례를 채택하여 보안을 강화합니다.Harden the security by employing some of the practices depicted in the following /etc/nginx/nginx.conf file. 예를 들어 더 강력한 암호화를 선택하고 HTTP를 사용한 모든 트래픽을 HTTPS로 리디렉션합니다.Examples include choosing a stronger cipher and redirecting all traffic over HTTP to HTTPS.

    참고

    개발 환경에서는 영구 리디렉션(301)보다 임시 리디렉션(302)을 사용하는 것이 좋습니다.For development environments, we recommend using temporary redirects (302) rather than permanent redirects (301). 링크 캐싱은 개발 환경에서 불안정한 동작을 일으킬 수 있습니다.Link caching can cause unstable behavior in development environments.

  • HSTS(HTTP Strict-Transport-Security) 헤더를 추가하면 클라이언트에서 만든 모든 후속 요청이 HTTPS를 통해 이루어집니다.Adding an HTTP Strict-Transport-Security (HSTS) header ensures all subsequent requests made by the client are over HTTPS.

    HSTS에 대한 중요 지침은 ASP.NET Core에서 HTTPS 적용를 참조하세요.For important guidance on HSTS, see ASP.NET Core에서 HTTPS 적용.

  • 추후 HTTPS가 사용하지 않도록 설정될 경우 다음 방법 중 하나를 사용합니다.If HTTPS will be disabled in the future, use one of the following approaches:

    • HSTS 헤더를 추가하지 않습니다.Don't add the HSTS header.
    • 짧은 max-age 값을 선택합니다.Choose a short max-age value.

/etc/nginx/proxy.conf 구성 파일을 추가합니다.Add the /etc/nginx/proxy.conf configuration file:

proxy_redirect          off;
proxy_set_header        Host $host;
proxy_set_header        X-Real-IP $remote_addr;
proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header        X-Forwarded-Proto $scheme;
client_max_body_size    10m;
client_body_buffer_size 128k;
proxy_connect_timeout   90;
proxy_send_timeout      90;
proxy_read_timeout      90;
proxy_buffers           32 4k;

/etc/nginx/nginx.conf 구성 파일의 내용을 다음 파일로 바꿉니다.Replace the contents of the /etc/nginx/nginx.conf configuration file with the following file. 예제에서는 httpserver 섹션이 하나의 구성 파일에 포함됩니다.The example contains both http and server sections in one configuration file.

http {
    include        /etc/nginx/proxy.conf;
    limit_req_zone $binary_remote_addr zone=one:10m rate=5r/s;
    server_tokens  off;

    sendfile on;
    keepalive_timeout   29; # Adjust to the lowest possible value that makes sense for your use case.
    client_body_timeout 10; client_header_timeout 10; send_timeout 10;

    upstream helloapp{
        server localhost:5000;
    }

    server {
        listen     80;
        return     301 https://$host$request_uri;
    }

    server {
        listen                    443 ssl;
        server_name               example.com *.example.com;
        ssl_certificate           /etc/ssl/certs/testCert.crt;
        ssl_certificate_key       /etc/ssl/certs/testCert.key;
        ssl_protocols             TLSv1.1 TLSv1.2;
        ssl_prefer_server_ciphers on;
        ssl_ciphers               "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH";
        ssl_ecdh_curve            secp384r1;
        ssl_session_cache         shared:SSL:10m;
        ssl_session_tickets       off;
        ssl_stapling              on; #ensure your cert is capable
        ssl_stapling_verify       on; #ensure your cert is capable

        add_header Strict-Transport-Security "max-age=63072000; includeSubdomains; preload";
        add_header X-Frame-Options DENY;
        add_header X-Content-Type-Options nosniff;

        #Redirects all traffic
        location / {
            proxy_pass http://helloapp;
            limit_req  zone=one burst=10 nodelay;
        }
    }
}

참고

Blazor WebAssembly 앱에서 수행하는 많은 수의 요청을 수용하려면 앱에 더 큰 burst 매개 변수 값이 필요합니다.Blazor WebAssembly apps require a larger burst parameter value to accommodate the larger number of requests made by an app. 자세한 내용은 ASP.NET Core 호스트 및 배포 Blazor WebAssembly를 참조하세요.For more information, see ASP.NET Core 호스트 및 배포 Blazor WebAssembly.

클릭재킹(clickjacking)으로부터 Nginx 보호Secure Nginx from clickjacking

또한 ‘UI 교정 공격’이라고도 하는클릭재킹(Clickjacking)은 웹 사이트 방문자를 속여서 현재 방문 중인 것과 다른 페이지에서 링크 또는 단추를 클릭하게 하는 악의적인 공격입니다.Clickjacking, also known as a UI redress attack, is a malicious attack where a website visitor is tricked into clicking a link or button on a different page than they're currently visiting. X-FRAME-OPTIONS를 사용하여 사이트를 보호합니다.Use X-FRAME-OPTIONS to secure the site.

클릭재킹 공격을 완화하려면:To mitigate clickjacking attacks:

  1. nginx.conf 파일을 편집합니다.Edit the nginx.conf file:

    sudo nano /etc/nginx/nginx.conf
    

    add_header X-Frame-Options "SAMEORIGIN"; 줄을 추가합니다.Add the line: add_header X-Frame-Options "SAMEORIGIN";

  2. 파일을 저장합니다.Save the file.

  3. Nginx를 다시 시작합니다.Restart Nginx.

MIME 형식 검색MIME-type sniffing

이 헤더는 응답 콘텐츠 형식을 재정의하지 않도록 브라우저에 지시하므로 대부분의 브라우저에서 선언된 콘텐츠 형식이 아닌 응답에 대한 MIME 검색을 차단합니다.This header prevents most browsers from MIME-sniffing a response away from the declared content type, as the header instructs the browser not to override the response content type. nosniff 옵션을 사용하면 서버에 콘텐츠가 text/html이라고 표시될 경우 브라우저가 이를text/html로 렌더링합니다.With the nosniff option, if the server says the content is text/html, the browser renders it as text/html.

  1. nginx.conf 파일을 편집합니다.Edit the nginx.conf file:

    sudo nano /etc/nginx/nginx.conf
    

    add_header X-Content-Type-Options "nosniff"; 줄을 추가합니다.Add the line: add_header X-Content-Type-Options "nosniff";

  2. 파일을 저장합니다.Save the file.

  3. Nginx를 다시 시작합니다.Restart Nginx.

추가 Nginx 제안Additional Nginx suggestions

서버에서 공유 프레임워크를 업그레이드한 후 서버에서 호스트되는 ASP.NET Core 앱을 다시 시작합니다.After upgrading the shared framework on the server, restart the ASP.NET Core apps hosted by the server.

추가 자료Additional resources