튜토리얼: NGINX 및 NGINX Plus를 사용하여 .NET Core와 Kestrel 프록시하기

NGINX | 2017년 2월 14일

약 2년 전 Microsoft®는 .NET Core를 발표했습니다. 이 프레임워크를 사용하면 Linux 및 Mac 시스템에서 .NET 애플리케이션을 네이티브로 개발하고 실행할 수 있습니다. ASP.NET Core에는 내부 웹 서버 라이브러리인 Kestrel이 포함되어 있습니다.

As indicated in the documentation for Kestrel on the Microsoft 웹사이트의 Kestrel 설명서와 GitHub 리포지토리에 나와 있듯이, 일반적으로 Kestrel은 IIS 또는 NGINX와 같은 프로덕션 웹 서버 뒤에서 실행합니다. 이 튜토리얼에서는 NGINX 및 NGINX Plus 뒤에 Kestrel을 구현하는 방법을 설명합니다.

이 튜토리얼에서는 다음 내용을 알아봅니다:

설치 및 구성이 완료되면:

  • .NET Core 및 Kestrel:
    • 동적 애플리케이션 코드 실행
    • 로컬 IP 주소에서 수신 대기하고 HTTP 요청에 응답
  • 리버스 프록시로 작동하는 NGINX 또는 NGINX Plus:
    • IPv6 및 IPv4를 통한 HTTP/2 트래픽을 수락합니다
    • .NET 애플리케이션에 SSL 오프로딩을 제공합니다
    • 정적 파일 제공 기능을 제공합니다
    • 액세스 로그를 제공합니다
    • 캐싱 기능을 추가합니다
  • NGINX Plus:
    • 실시간 활동 모니터링 및 메트릭 제공
    • 능동형 상태 확인을 통해 앱이 정상적으로 작동하는지 확인합니다

.NET Core 애플리케이션 배포 아키텍처는 Node.js 또는 Go 애플리케이션의 배포 아키텍처와 유사합니다. NGINX는 .NET 앱에 트래픽 관리 기능을 제공하여 프로덕션 배포와 앱 확장을 간소화합니다. 여러 .NET 애플리케이션을 동일한 머신이나 서로 다른 머신에서 실행할 수 있으며, NGINX 또는 NGINX Plus가 애플리케이션 간의 부하 분산과 지능형 트래픽 라우팅을 수행합니다.

지침

다음 지침에서는 .NET Core를 사용하여 “Hello World” 앱을 빠르게 빌드하고 Linux에서 실행한 다음, 고급 트래픽 관리 기능을 갖춘 NGINX 또는 NGINX Plus 리버스 프록시 뒤에 배포하는 방법을 설명합니다.

  1. .NET Core, NGINX 및 NGINX Plus 설치
  2. “Hello World” 앱 실행
  3. Kestrel HTTP 서버 실행
  4. NGINX 또는 NGINX Plus를 .NET 애플리케이션의 리버스 프록시로 구성
  5. NGINX Plus 실시간 활동 모니터링 및 능동 상태 검사 구성

.NET Core, NGINX 및 NGINX Plus 설치

  1. Microsoft 웹사이트의 설치 지침에 따라 .NET Core를 설치합니다. 이 예제에서는 Ubuntu 16.04를 사용합니다. 다음 명령은 이 글을 작성할 당시에는 정확했지만, Kestrel이 아직 개발 중이므로 변경될 수 있습니다. 필요한 경우 .NET Core 설명서를 참조하세요.
$ sudo apt-get install apt-transport-https$ sudo sh -c 'echo "deb [arch=amd64] https://apt-mo.trafficmanager.net/repos/dotnet-release/ xenial main" > /etc/apt/sources.list.d/dotnetdev.list'
$ sudo apt-key adv --keyserver apt-mo.trafficmanager.net --recv-keys 417A0893
$ sudo apt-get update
$ sudo apt-get install dotnet-dev-1.0.0-preview2-003131
  1. NGINX를 설치합니다:
$ sudo apt-get install nginx
  1. 실시간 활동 모니터링이나 능동 상태 확인 또는 두 기능 모두를 사용하려면 NGINX Plus를 설치하세요. 자세한 지침은 NGINX Plus 관리 가이드를 참조하세요.
    1. Edit the ./project.json 파일을 편집하여 Kestrel을 프로젝트의 종속성으로 추가합니다.
{  "version": "1.0.0-*",
  "buildOptions": {
    "debugType": "portable",
    "emitEntryPoint": true
  },
  "dependencies": {},
  "frameworks": {
    "netcoreapp1.0": {
      "dependencies": {
        "Microsoft.NETCore.App": {
          "type": "platform",
          "version": "1.0.1"
        }, "Microsoft.AspNetCore.Server.Kestrel": "1.0.0"
      },
      "imports": "dnxcore50"
    }
  }
}
  1. 간단한 앱을 위한 이 코드를 Program.cs라는 새 파일에 복사합니다. 이 앱은 현재 날짜와 시간을 반환하며 localhost의 5000번 포트에서 Kestrel을 실행합니다.
using System;using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;

namespace ConsoleApplication
{
    public class Program
    {
        public static void Main(string[] args)
        {
            var host = new WebHostBuilder()
                .UseKestrel()
                .Configure(app =>
                {
                    app.Run(async (context) => await context.Response.WriteAsync("Current date: " + DateTime.Now + "n"));
                })
                .Build();

            host.Run();
        }
    }
}
  1. .NET Core 서버를 시작하려면 dotnet run 명령을 실행합니다:
$ dotnet runProject app (.NETCoreApp,Version=v1.0) will be compiled because inputs were modified
Compiling app for .NETCoreApp,Version=v1.0

Compilation succeeded.
    0 Warning(s)
    0 Error(s)

Time elapsed 00:00:01.9047678

Hello World!
Hosting environment: Production
Content root path: /app/bin/Debug/netcoreapp1.0
Now listening on: http://localhost:5000
Application started. Press Ctrl+C to shut down.
  1. 연결 및 HTTP를 테스트하려면 curl 명령을 실행합니다:
$ curl -v localhost:5000* Rebuilt URL to: localhost:5000/
*   Trying ::1...
* Connected to localhost (::1) port 5000 (#0)
> GET / HTTP/1.1
> Host: localhost:5000
> User-Agent: curl/7.47.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Date: Tue, 14 Feb 2017 19:50:59 GMT
< Transfer-Encoding: chunked
< Server: Kestrel
<
Current date: 02/14/17 12:50:59 PM
* Connection #0 to host localhost left intact
  1. SSL 인증서를 설치합니다. 인증서를 발급받는 방법에는 여러 가지가 있습니다. 여기서는 SSL이 적용된 샘플 .NET Core 앱을 빠르게 실행하기 위해 다음 openssl 명령으로 자체 서명 인증서와 관련 키를 생성합니다. 인증서와 키는 NGINX의 표준 위치인 /etc/nginx에 설치하지만, 다른 위치를 선택해도 됩니다.
$ openssl req -x509 -subj /CN=localhost -days 365 -set_serial 2 -newkey rsa:4096 -keyout /etc/nginx/cert.key -nodes -out /etc/nginx/cert.pemGenerating a 4096 bit RSA private key
.........++
............................++
writing new private key to '/etc/nginx/cert.key'
-----
  • 잘 알려진 인증 기관(CA)에서 인증서를 구매하세요
  • 회사 IT 부서 또는 인증 기관(CA)에 생성을 요청하세요
  • 기존 IIS 서버에서 내보냅니다
  • 다음과 같은 무료 CA를 사용하세요: Let’s Encrypt
  • 자체 서명 인증서를 직접 생성합니다
  1. HTTP 가상 서버용 기본 NGINX 및 NGINX Plus 구성 파일에서 리버스 프록시를 구성합니다. 기본 NGINX 및 NGINX Plus 구성 파일은 /etc/nginx/nginx.conf입니다. 그러나 여러 NGINX 배포판(및 NGINX Plus)에서는 실제 구성 대부분을 기본 파일에 배치하지 않고, 대신 /etc/nginx의 하위 디렉터리에 기능별로 더 작은 파일을 만드는 방식을 따릅니다. 그런 다음 이러한 디렉터리에 있는 기능별 파일의 내용을 다음과 같이 nginx.conf 기본 파일로 읽어 들입니다. 이때 include 지시문을 사용합니다. 예:
include /etc/nginx/conf.d/*.conf;include /etc/nginx/sites-enabled/*;
  1. 시스템에서 HTTP 가상 서버의 기본 구성 파일이 무엇인지 확실하지 않은 경우 include 지시문을 /etc/nginx/nginx.conf에서 찾으십시오. NGINX 또는 NGINX Plus를 리버스 프록시로 구성하려면 HTTP 가상 서버의 기본 구성 파일에 다음 세 가지 구성 블록을 추가하십시오:
server {    listen 80 default_server;
    listen [::]:80 default_server;
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl http2 default_server;
    listen [::]:443 ssl http2 default_server;

    ssl_certificate /etc/nginx/cert.pem;
    ssl_certificate_key /etc/nginx/cert.key;

    location / {
        proxy_pass http://dotnet;
        proxy_set_header Host $host;
    }
}

upstream dotnet {
    zone dotnet 64k;
    server 127.0.0.1:5000;
}
  • For NGINX Open Source builds provided by nginx.org에서 제공하는 NGINX Open Source 빌드와 NGINX Plus의 경우 디렉터리는 /etc/nginx/conf.d이고, HTTP 가상 서버의 기본 파일은 default.conf입니다.
  • Ubuntu와 함께 배포되는 NGINX Open Source 빌드의 경우 디렉터리는 /etc/nginx/sites-enabled이고, HTTP 가상 서버의 기본 파일은 default입니다.
  • 첫 번째 server 블록은 포트 80에서 HTTP 요청을 수신하고 이를 HTTPS 요청용 가상 서버로 리디렉션합니다.
  • 두 번째 server 블록은 포트 443에서 HTTPS 요청을 수신하고, 여기서는 dotnet이라고 하는 하나 이상의 업스트림(백엔드) 서버 그룹으로 요청을 프록시합니다. (1단계에서 자체 서명 SSL 인증서를 /etc/nginx가 아닌 다른 디렉터리에 설치했다면, ssl_certificate 및 ssl_certificate_key 지시문에 올바른 경로를 입력하세요.)
  • The upstream 블록은 백엔드 서버의 dotnet 그룹을 정의합니다. Kestrel HTTP 서버 실행에서 Kestrel을 localhost:5000에 구성했으므로 해당 포트에서 IPv4 및 IPv6 트래픽을 모두 수신합니다. (Kestrel이 하나의 프로토콜만 사용하도록 구성하면 불안정해지고 502 오류가 발생할 수 있습니다.) 마찬가지로 NGINX와 NGINX Plus는 localhost를 IPv4 주소와 IPv6 주소(127.0.0.1 및 ::1) 모두로 확인합니다. 여기서는 간단하게 업스트림 서버를 127.0.0.1로 지정하고 localhost는 사용하지 않으므로 IPv4 트래픽만 수신합니다. IPv6가 포함된 고급 구성에 익숙하다면 localhost를 사용할 수 있습니다.
  1. 다음 curl 명령을 실행하여 HTTPS를 통한 .NET Core 앱 연결을 테스트합니다. (대신 브라우저에서 Linux 서버 주소로 접속해도 됩니다.)
$ curl -kv https://localhost* Rebuilt URL to: https://localhost/
*   Trying ::1...
* Connected to localhost (::1) port 443 (#0)
...[SKIPPED]...
< HTTP/1.1 200 OK
< Server: nginx/1.10.0 (Ubuntu)
< Date: Tue, 14 Feb 2017 20:22:07 GMT
< Transfer-Encoding: chunked
< Connection: keep-alive
<
Current date: 02/14/17 1:22:07 PM
  1. 참고: 502 Bad Gateway 오류가 표시되면 NGINX 또는 NGINX Plus가 .NET 애플리케이션에 연결할 수 없다는 의미입니다. 애플리케이션이 실행 중이며 포트 5000에서 응답을 제공하는지 확인하세요. nghttp2 패키지를 설치한 경우 다음 nghttp 명령을 실행하여 HTTP/2 연결을 테스트할 수도 있습니다. 다음 예시의 상당히 긴 출력 내용 중 시작 부분 근처에서 주황색으로 강조 표시된 줄을 찾으세요.
$ nghttp -v https://localhost[  0.000] Connected
The negotiated protocol: h2
[  0.009] send SETTINGS frame 
          (niv=2)
          [SETTINGS_MAX_CONCURRENT_STREAMS(0x03):100]
          [SETTINGS_INITIAL_WINDOW_SIZE(0x04):65535]
[  0.009] send PRIORITY frame 
          (dep_stream_id=0, weight=201, exclusive=0)
  • 응답 코드는 200 OK입니다.
  • 앱 서버가 다른 소프트웨어가 아닌 Kestrel입니다
  • 응답 본문에 “현재 날짜”라는 문구가 포함되어 있습니다
  • 앱이 1초의 제한 시간 내에 응답합니다

“Hello World” 앱 실행

원하는 상위 디렉터리에 “Hello World” 앱을 설치하고 초기화합니다:

$ cd parent-dir-for-apps
$ mkdir app
$ cd app
$ dotnet restore

앱이 정상적으로 작동하는지 확인하려면 dotnet run 명령을 실행합니다.

Kestrel HTTP 서버 실행

이제 .NET Core가 Linux에서 실행되고 있으며 Kestrel을 HTTP 서버로 사용하여 동적 데이터를 제공하고 있습니다.

.NET 애플리케이션을 리버스 프록시하도록 NGINX 또는 NGINX Plus 구성

NGINX 또는 NGINX Plus를 .NET 애플리케이션의 리버스 프록시로 사용하면 .NET Core 애플리케이션이 실행 중인 동일한 머신에서 SSL/TLS를 통한 보안, HTTP/2 지원 및 빠른 애플리케이션 제공을 위한 다양한 기능을 손쉽게 구성할 수 있습니다. 다음 지침에서는 NGINX와 NGINX Plus가 시스템에 이미 설치되어 있다고 가정합니다. 설치되어 있지 않은 경우 .NET Core, NGINX 및 NGINX Plus 설치를 참조하세요.

NGINX Plus 실시간 활동 모니터링 및 능동 상태 검사 구성

이제 NGINX 또는 NGINX Plus와 .NET Core의 기본 구성을 완료했습니다. NGINX 또는 NGINX Plus는 .NET Core 앱에 HTTP 처리, 수동 상태 확인, SSL/TLS 보안 및 HTTP/2 연결을 제공합니다.

NGINX Plus를 설치한 경우 실시간 활동 모니터링과 능동 상태 확인이라는 두 가지 추가 기능을 구성할 수 있습니다.

실시간 활동 모니터링 구성

[편집자 주 – 이 섹션은 여기에서 원래 설명했던 별도의 확장 Status 모듈을 대체하고 더 이상 사용되지 않도록 하는 NGINX Plus API를 참조하도록 업데이트되었습니다.]

다음 server 블록을 HTTP 가상 서버용 기본 NGINX 구성 파일에 추가합니다. 통계 및 메트릭에 대한 액세스를 제한할 것을 강력히 권장합니다. 여기서는 localhost 및 로컬 네트워크의 사용자에게만 액세스를 허용합니다.

실시간 활동 모니터링에 대한 자세한 내용은 블로그의 간단한 3단계로 NGINX Plus 실시간 활동 모니터링하기 및 NGINX Plus 관리자 가이드를 참조하세요.

server {    listen 8080;
    allow 127.0.0.1;   # Allow localhost to access the statistics
    allow 10.3.3.0/24; # Allow local network to access the statistics
    deny all;          # Prevent access from anywhere else

    root /usr/share/nginx/html;

    location / {
        return 302 /dashboard.html;
    }

    location /api {
        api write=on;
    }

    location = /dashboard.html {
        root /usr/share/nginx/html;
    }

    # Redirect requests made to the old dashboard
    location = /status.html {
        return 301 /dashboard.html;
    }
}

활성 상태 확인 구성

능동 상태 검사를 사용하면 NGINX Plus가 정상적으로 작동하는 애플리케이션에만 트래픽을 전송하도록 보장할 수 있습니다. NGINX Plus가 애플리케이션에 주기적으로 전송할 HTTP 요청과 애플리케이션이 정상으로 간주되기 위해 반환해야 하는 응답 유형을 정의합니다.

여기서는 앱의 응답이 다음 조건을 충족해야 합니다:

HTTP 가상 서버의 기본 구성 파일에서 다음 location 블록을 기본 server 블록(NGINX 또는 NGINX Plus를 .NET 애플리케이션의 리버스 프록시로 구성의 2단계에서 정의한 HTTPS 트래픽용 블록)에 추가합니다:

location @healthcheck {    proxy_pass http://dotnet;
    proxy_set_header Host localhost;
    health_check match=currentdate;
    proxy_connect_timeout 1s;
    proxy_read_timeout 1s;
}

또한 다음 match 블록을 server 및 upstream 블록과 동일한 계층 수준에 추가합니다:

match currentdate {    status 200;
    header Server = Kestrel;
    body ~ "Current date";
}

백엔드 앱이 정상적으로 작동하는지 기본 제공 실시간 활동 모니터링 대시보드의 Upstreams 탭에서 확인할 수 있습니다(브라우저에서 //http://nginx-plus-server-address:8080/ 주소로 이동):

NGINX Plus 실시간 활동 모니터링 대시보드는 NGINX가 프록시하는 백엔드 .NET 애플리케이션의 상태를 보여줍니다.

더 많은 NGINX 구성 옵션은 Microsoft 설명서를 참조하세요.

결론

ASP.NET으로 개발한 앱을 프로덕션 환경에 배포할 때 NGINX와 NGINX Plus는 리버스 프록시에 필요한 트래픽 관리 기능을 제공합니다. NGINX와 NGINX Plus는 보안, 확장성, 인증, 트래픽 제한 기능을 제공하며 HTTP 요청을 .NET Core 애플리케이션으로 지능적으로 라우팅합니다.

NGINX Plus를 직접 사용해 보려면 지금 30일 무료 체험을 시작하거나 사용 사례에 대해 논의하려면 문의해 주세요.


공유

작성자 소개

관련 블로그 게시물

시청하기: KubeCon North America 2023에서의 NGINX Gateway Fabric
NGINX | 2023. 11. 30.

시청하기: KubeCon North America 2023에서의 NGINX Gateway Fabric

이 영상에서는 KubeCon의 NGINX 부스를 찾아가, 저희가 공개한 Kubernetes Gateway API 구현을 살펴봅니다.

F5 NGINX로 대규모 WAF 플릿을 확인하고 관리하는 2가지 방법
NGINX | 2023. 03. 23.

F5 NGINX로 대규모 WAF 플릿을 확인하고 관리하는 2가지 방법

앱 보안을 강화하는 두 가지 방법을 소개합니다. NGINX Management Suite를 통해 WAF 운영에 대한 가시성을 높이고, NGINX App Protect WAF를 활용해 코드형 보안을 구현하는 것입니다.

Ingress 컨트롤러 선택 가이드, 4부: NGINX Ingress Controller 옵션
NGINX | 2021. 09. 27.

Ingress 컨트롤러 선택 가이드, 4부: NGINX Ingress Controller 옵션

개발 주체, 개발 철학, 프로덕션 환경 준비도, 보안 및 지원을 기준으로 어떤 NGINX Ingress 컨트롤러가 가장 적합한지 알아보세요.

진화하는 공격 환경에 NGINX App Protect Denial of Service가 적응하는 방법
NGINX | 2021. 07. 06.

진화하는 공격 환경에 NGINX App Protect Denial of Service가 적응하는 방법

NGINX App Protect Denial of Service(DoS)가 계층 7 DoS 공격을 방어하기 위해 완화 방법을 실시간으로 조정하는 방식을 설명합니다. 정상적인 사용자 행동과 서버 상태에 대한 모델을 생성하여 공격을 나타내는 이상 징후를 감지하고 맞춤형 완화 시그니처를 적용할 수 있습니다.

NGINX Instance Manager를 활용한 대규모 구성 업데이트 및 인증서 관리
NGINX | 2021. 06. 30.

NGINX Instance Manager를 활용한 대규모 구성 업데이트 및 인증서 관리

NGINX Instance Manager 버전 1.0에는 두 가지 새로운 기능이 도입되었습니다. NGINX 인스턴스에 태그와 사용자 역할을 지정하면 전체 그룹에 구성을 한 번에 적용할 수 있습니다. 인증서 검사는 만료 예정인 인증서를 감지하여 서비스 중단을 방지할 수 있도록 인증서를 교체할 수 있게 해줍니다.

Netflix가 자사 CDN의 핵심으로 NGINX를 선택한 이유
NGINX | 2015. 03. 25.

Netflix가 자사 CDN의 핵심으로 NGINX를 선택한 이유

Netflix가 글로벌 콘텐츠 전송 네트워크인 Open Connect의 스트리밍 미디어 기술로 NGINX를 선택한 이유를 NGINX 개발자 Gleb Smirnoff에게서 알아보세요.