Linux에서 Nginx를 사용하여 ASP.NET Core에 대한 호스팅 환경을 설정하고 해당 환경에 배포Set up a hosting environment for ASP.NET Core on Linux with Nginx, and deploy to it

작성자: 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 14.04의 경우 Kestrel 프로세스를 모니터링하기 위한 솔루션으로 supervisord를 사용하는 것이 좋습니다.Note: For Ubuntu 14.04, supervisord is recommended as a solution for monitoring the Kestrel process. systemd는 Ubuntu 14.04에서 사용할 수 없습니다.systemd is not available on Ubuntu 14.04. 이 문서의 이전 버전을 참조하세요.See previous version of this document

이 가이드의 내용:This guide:

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

필수 구성 요소Prerequisites

  1. sudo 권한을 가진 표준 사용자 계정으로 Ubuntu 16.04 Server에 액세스Access to an Ubuntu 16.04 Server with a standard user account with sudo privilege
  2. 기존 ASP.NET Core 응용 프로그램An existing ASP.NET Core application

앱을 통해 복사Copy over your app

개발 환경에서 dotnet publish를 실행하여 앱을 서버에서 실행될 수 있는 자체 포함된 디렉터리로 패키지합니다.Run dotnet publish from the dev environment to package an app into a self-contained directory that can run on the server.

무엇이든 워크플로에 통합된 도구(SCP, FTP 등)를 사용하여 ASP.NET Core 앱을 서버에 복사합니다.Copy the ASP.NET Core app to the server using whatever tool (SCP, FTP, etc.) integrates into your workflow. 다음과 같이 앱을 테스트합니다.Test the app, for example:

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

참고: Yeoman을 사용하여 새 프로젝트에 대한 새 ASP.NET Core 앱을 만듭니다.Note: Use Yeoman to create a new ASP.NET Core app for a new project.

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

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

역방향 프록시 서버를 사용하는 이유는 무엇인가요?Why use a reverse proxy server?

Kestrel은 ASP.NET Core에서 동적 콘텐츠를 지원할 수 있는 유용한 기능이지만, 웹 지원 부분은 IIS, Apache 또는 Nginx 같은 서버만큼 기능이 다양하지 않습니다.Kestrel is great for serving dynamic content from ASP.NET Core; however, the web serving parts aren’t as feature rich as servers like IIS, Apache, or Nginx. 역방향 프록시 서버는 정적 콘텐츠 지원, 요청 캐시, 요청 압축 및 HTTP 서버에서 SSL 종료 같은 작업을 오프로드할 수 있습니다.A reverse proxy server can offload work like serving static content, caching requests, compressing requests, and SSL 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 your requirements, you may choose a different setup.

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

역방향 프록시 서버를 설정할 경우 인증 미들웨어는 UseForwardedHeaders를 먼저 실행해야 합니다.When setting up a reverse proxy server, the authentication middleware needs UseForwardedHeaders to run first. 이렇게 순서를 지정하면 인증 미들웨어가 영향받는 값을 사용하고 올바른 리디렉션 URI를 생성할 수 있습니다.This ordering ensures that the authentication middleware can consume the affected values and generate correct redirect URIs.

Startup.csConfigure 메서드에서 UseForwardedHeaders 메서드를 호출한 후 UseAuthentication 또는 비슷한 인증 체계 미들웨어를 호출합니다.Invoke the UseForwardedHeaders method (in the Configure method of Startup.cs) before calling UseAuthentication or similar authentication scheme middleware:

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

app.UseAuthentication();

Nginx 설치Install Nginx

sudo apt-get install nginx
참고

선택적 Nginx 모듈을 설치하려면 소스에서 Nginx를 빌드해야 할 수 있습니다.If you plan to install optional Nginx modules, you may be required to build Nginx from source.

apt-get을 사용하여 Nginx를 설치합니다.Use apt-get to install Nginx. 설치 관리자는 시스템 시작 시 Nginx를 디먼으로 실행하는 System V init 스크립트를 만듭니다.The installer creates a System V init script that runs Nginx as daemon on system startup. 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.

Nginx 구성Configure Nginx

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

server {
    listen 80;
    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;
    }
}

이 Nginx 구성 파일은 들어오는 공용 트래픽을 포트 80에서 포트 5000으로 전달합니다.This Nginx configuration file forwards incoming public traffic from port 80 to port 5000.

Nginx 구성 변경을 완료한 후 sudo nginx -t를 실행하여 구성 파일의 구문을 확인할 수 있습니다.Once you have completed making changes to your Nginx configuration, you can run sudo nginx -t to verify the syntax of your configuration files. 구성 파일 테스트에 성공하면 Nginx를 통해 sudo nginx -s reload를 실행하여 변경 내용을 선택할 수 있습니다.If the configuration file test is successful, you can ask Nginx to pick up the changes by running sudo nginx -s reload.

응용 프로그램 모니터링Monitoring our application

이제 Nginx는 http://yourhost:80에 대해 만들어진 요청을 http://127.0.0.1:5000의 Kestrel에서 실행되는 ASP.NET Core 응용 프로그램에 전달하도록 설정됩니다.Nginx is now setup to forward requests made to http://yourhost:80 on to the ASP.NET Core application running on Kestrel at http://127.0.0.1:5000. 그러나 Nginx는 Kestrel 프로세스를 관리하도록 설정되지 않습니다.However, Nginx is not set up to manage the Kestrel process. systemd를 사용하고 서비스 파일을 만들어 기본 웹앱을 시작 및 모니터링할 수 있습니다.You can use systemd and 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-hellomvc.service

응용 프로그램에 대한 예제 서비스 파일은 다음과 같습니다.The following is an example service file for our application:

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

[Service]
WorkingDirectory=/var/aspnetcore/hellomvc
ExecStart=/usr/bin/dotnet /var/aspnetcore/hellomvc/hellomvc.dll
Restart=always
RestartSec=10  # Restart service after 10 seconds if dotnet service crashes
SyslogIdentifier=dotnet-example
User=www-data
Environment=ASPNETCORE_ENVIRONMENT=Production 

[Install]
WantedBy=multi-user.target

참고: 사용자 www-data가 구성에서 사용되지 않을 경우 여기서 정의된 사용자를 먼저 만들고 파일에 대한 적절한 소유권을 제공해야 합니다.Note: If the user www-data is not used by your configuration, the user defined here must be created first and given proper ownership for files.

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

systemctl enable kestrel-hellomvc.service

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

systemctl start kestrel-hellomvc.service
systemctl status kestrel-hellomvc.service

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

역방향 프록시를 구성하고 systemd를 통해 Kestrel을 관리하면 웹 응용 프로그램이 완전히 구성되고 로컬 컴퓨터(http://localhost)의 브라우저에서 웹 응용 프로그램에 액세스할 수 있습니다.With the reverse proxy configured and Kestrel managed through systemd, the web application is fully configured and can be accessed from a browser on the local machine at http://localhost. 차단 중인 방화벽이 없다면 원격 컴퓨터에서 액세스할 수도 있습니다.It is 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 application 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

로그 보기Viewing logs

Kestrel을 사용하는 웹 응용 프로그램은 systemd를 사용하여 관리되므로 모든 이벤트 및 프로세스가 중앙형 저널에 기록됩니다.Since the web application 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-hellomvc.service 관련 항목을 보려면 다음 명령을 사용합니다.To view the kestrel-hellomvc.service-specific items, use the following command:

sudo journalctl -fu kestrel-hellomvc.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-hellomvc.service --since "2016-10-18" --until "2016-10-18 04:00"

응용 프로그램 보안Securing our application

AppArmor 사용Enable AppArmor

LSM(Linux Security Modules)은 Linux 2.6 이후 Linux 커널에 포함된 프레임워크입니다.Linux Security Modules (LSM) is a framework that is 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.

방화벽 구성Configuring our firewall

사용되지 않는 모든 외부 포트를 닫습니다.Close off all external ports that are not in use. 복잡하지 않은 방화벽(ufw)은 방화벽을 구성하기 위한 명령줄 인터페이스를 제공하여 iptables에 대한 프런트 엔드를 제공합니다.Uncomplicated firewall (ufw) provides a front end for iptables by providing a command line interface for configuring the firewall. ufw가 필요한 모든 포트에서 트래픽을 허용하도록 구성되어 있는지 확인합니다.Verify that ufw is configured to allow traffic on any ports you need.

sudo apt-get install ufw
sudo ufw enable

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

Nginx 보안Securing Nginx

Nginx의 기본 배포 시에는 SSL이 사용하도록 설정되지 않습니다.The default distribution of Nginx doesn't enable SSL. 추가 보안 기능을 사용하도록 설정하려면 소스에서 빌드합니다.To enable additional security features, build from source.

소스 다운로드 및 빌드 종속성 설치Download the source and install the build dependencies

# Install the build dependencies
sudo apt-get update
sudo apt-get install build-essential zlib1g-dev libpcre3-dev libssl-dev libxslt1-dev libxml2-dev libgd2-xpm-dev libgeoip-dev libgoogle-perftools-dev libperl-dev

# Download nginx 1.10.0 or latest
wget http://www.nginx.org/download/nginx-1.10.0.tar.gz
tar zxf nginx-1.10.0.tar.gz

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: Your Web Server" CRLF;
static char ngx_http_server_full_string[] = "Server: Your Web Server" CRLF;

옵션 구성 및 빌드Configure the options and build

정규식의 경우 PCRE 라이브러리가 필요합니다.The PCRE library is required for regular expressions. 정규식은 ngx_http_rewrite_module에 대한 위치 지시문에서 사용됩니다.Regular expressions are used in the location directive for the ngx_http_rewrite_module. http_ssl_module은 HTTPS 프로토콜 지원을 추가합니다.The http_ssl_module adds HTTPS protocol support.

ModSecurity 같은 웹 응용 프로그램 방화벽을 사용하여 응용 프로그램을 강화해 보세요.Consider using a web application firewall like ModSecurity to harden your application.

./configure
--with-pcre=../pcre-8.38
--with-zlib=../zlib-1.2.8
--with-http_ssl_module
--with-stream
--with-mail=dynamic

SSL 구성Configure SSL

  • 신뢰할 수 있는 CA(인증 기관)에서 발급된 유효한 인증서를 지정하여 포트 443에서 HTTPS 트래픽을 수신하도록 서버를 구성합니다.Configure your 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 your 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.

  • 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 only.

  • Strict-Transport-Security 헤더를 추가하지 않거나, 나중에 SSL을 사용하지 않도록 설정하려면 적절한 max-age를 선택합니다.Do not add the Strict-Transport-Security header or chose an appropriate max-age if you plan to disable SSL in the future.

/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;
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 구성 파일을 편집합니다.Edit the /etc/nginx/nginx.conf configuration 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 hellomvc{
        server localhost:5000;
    }

    server {
        listen *:80;
        add_header Strict-Transport-Security max-age=15768000;
        return 301 https://$host$request_uri;
    }

    server {
        listen *:443    ssl;
        server_name     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://hellomvc;
            limit_req   zone=one burst=10;
        }
    }
}
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 hellomvc{
        server localhost:5000;
    }

    server {
        listen *:80;
        add_header Strict-Transport-Security max-age=15768000;
        return 301 https://$host$request_uri;
    }

    server {
        listen *:443    ssl;
        server_name     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://hellomvc;
            limit_req   zone=one burst=10;
        }
    }
}

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

클릭재킹은 감염된 사용자의 클릭을 수집하는 악의적인 기술입니다.Clickjacking is a malicious technique to collect an infected user's clicks. 클릭재킹은 희생자(방문자)를 속여서 감염된 사이트를 클릭하게 합니다.Clickjacking tricks the victim (visitor) into clicking on an infected site. X-FRAME-OPTIONS를 사용하여 사이트를 보호합니다.Use X-FRAME-OPTIONS to secure your site.

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

sudo nano /etc/nginx/nginx.conf

add_header X-Frame-Options "SAMEORIGIN";을 추가하고 파일을 저장한 다음 Nginx를 다시 시작합니다.Add the line add_header X-Frame-Options "SAMEORIGIN"; and save the file, then 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".

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

sudo nano /etc/nginx/nginx.conf

add_header X-Content-Type-Options "nosniff";를 추가하고 파일을 저장한 다음 Nginx를 다시 시작합니다.Add the line add_header X-Content-Type-Options "nosniff"; and save the file, then restart Nginx.