본문 바로가기
.NET 관련/.NET on Linux

Linux에 ASP.NET Core 사이트의 배포: Nginx의 이용

by kinorama 2016. 9. 26.

L사 프로젝트 진행중 틈나는 시간에 삽질해보며 작성중이라 상세하게 내용을 적을수는 없으나, 최대한 내용을 적어보도록 하겠다.

 

아래에서 설명하고자 하는 Linux OS는 CentOS 7.x 기준으로 설명한다. (MS의 ASP.NET Core 사이트에서는 Debian 계열의 Linux로 설명을 하고 있으나, 소속 회사에서 Linux OS는 CentOS를 주로 사용하고 있어 해당 OS를 먼저 살펴보았다.)

 

MS의 ASP.NET Core Documentation 사이트에서는 Reverse-proxy를 지원하는 Nginx (엔진X 라고 불리는) 웹서버와 ASP.NET Core 자체적으로 가지고 있는 Kestrel 웹서버, 그리고 Kestrel Process를 모니터링하고 boot 시 start, restart 등을 지원하는 Supervisor 라고 불리는 Process Control System에 대하여 설명하고 있다.

간단히 설명하면 사용자의 요청을 Nginx가 받아서 Kestrel로 전달하고(일종의 Web Server 역할), Kestrel이 서버의 응답 내용을 Nginx로 전달(일종의 WAS 역할)하여 사용자에게 요청에 대한 응답을 전달하는 구조이다. [예: example.com(Nginx) <-> localhost:5000(Kestrel)]

 

본 내용에서는 Nginx, Supervisor를 사용하여 CentOS에서 ASP.NET Core 사이트를 구동하는 방법을 설명하고자 한다. (Linux에 .NET Core가 미리 설치되어 있어야 하며, 해당 설치는 MS의 .NET Core 설치 사이트 참조하여 사전에 설치하도록 한다.)

 

 

1. NginX의 설치 및 설정 (버전 1.10.1 기준)

 

자바에서는 Web Server(Apache, Webtobe 등)에서 정적 컨텐츠(Static contents)를 처리하고, 동적 컨텐츠(Dynamic contents)는 WAS(JEUS, WebLogic, JBOSS 등)를 통해서 처리하고 있다. (물론 인프라 환경에 따라 다르게 구성되기도 하지만, 일반적인 경우로 국한한다.)

Nginx는 Apache와 같이 Web Server로서의 역할을 하며, 그들의 설명에 의하면 Apache에 비하여 정적 컨텐츠의 서비스에 상당한 성능적 우위를 가지고 있다고 한다.

 

(1) 설치 (root 권한으로 설치한다.) ----------------------

 

1) Nginx Repository 설치

 

sudo yum install

 

2) Nginx 설치

 

sudo yum install nginx

 

3) Nginx 시작

 

sudo systemctl start nginx 

 

- 옵션

  • 시작: sudo service nginx start
  • 재시작: sudo service nginx restart
  • 설정 재로드: sudo service nginx reload
  • 상태 확인: sudo service nginx status
  • 설정 테스트: sudo nginx -t

 - Linux 시작시에 자동으로 Nginx 서비스가 시작되도록 하려면,

 

 sudo systemctl enable nginx

   를 실행하여 서비스에 등록한다.  

 

- 방화벽이 있을 경우, 아래와 같이 80, 443 포트에 대하여 방화벽을 오픈하도록 한다.

 

sudo firewall-cmd --permanent --zone=public --add-service=http
sudo firewall-cmd --permanent --zone=public --add-service=https
sudo firewall-cmd --reload

 

- 시작되지 않고 오류가 발생할 경우, journalctl -xe 명령어로 에러에 대하여 살펴본다.

  보통 기존에 Apache 등의 웹서버가 이미 설치되어 있을 경우 에러가 발생한다. (에러 메세지를 보면 80포트가 이미 사용중이라고 나온다.)

  기존 웹서버를 미사용 처리하던지, Nginx를 다른 포트로 사용하도록 설정을 변경하도록 한다.

 

포트 사용여부 확인 (netstat 명령어 이용)

* 설치: sudo yum install net-tools

* 확인: netstat -an | grep LISTEN

 

4) 확인

- 브라우져에서 서버의 ip로 접속해본다. (http://your_server_ip)

 

[그림] Nginx 초기 페이지

 

- 상기와 같은 이미지가 나오면 정상적으로 Nginx가 설치된 경우이다.

- 서버의 IP 확인

 

ip addr 

를 실행하여 eth0의 IP를 확인한다. (가상화에 OS를 돌리는 경우는 사용자에 따라 다를수 있음)

 

5) 13: Permission Denied 오류 방지 처리

브라우져를 통해서 사이트 접속시, 502 Bad Request 에러가 나오며, Nginx의 에러 로그에 13: Permission Denied 오류로 기록되어 있는 경우는 다음과 같이 처리한다.

 

sudo yum install policycoreutils-python
sudo cat /var/log/audit/audit.log | grep nginx | grep denied | audit2allow -M swnginx
sudo semodule -i swnginx.pp

 

Nginx 재시작

 

 

 

(2) 설정 -----------------

 

보통 웹서버의 경우, 단일 사이트만 사용하도록 구성하지 않으며 다중의 사이트를 서비스 하도록 구성한다.

(Apache에서는 virtual host 구성이라고 한다.)

Nginx에서도 다중의 사이트 구성이 가능한데, Nginx에서는 Server Block 구성이라고 하며 아래에 상세내용을 기술하도록 하겠다.

 

1) 주요 위치 및 구성 파일

 

- 주요 구성 파일의 위치: Nginx는 /etc/nginx/에 위치

- 로그 파일의 위치: /var/log/nginx/에 위치

- 기본 웹사이트의 위치: /usr/share/nginx/html/에 위치

- 사용자 웹 Root의 위치: /var/www/ 하위에 위치

   (사용자 웹 Root는 사이트별 구성 파일에서 설정에 따라 달라질 수 있음)

 

[그림] Nginx 주요 구성 파일 위치

 

- Nginx의 Global Configuration 파일: /etc/nginx/nginx.conf

- Nginx의 Default Configuration 파일: /etc/nginx/conf.d/default.conf

- Nginx의 MIME Configuration 파일: /etc/nginx/mime.types

 

2) 다중 ASP.NET Core 사이트별 구성 파일 설정 (Server Block Configuration)

 

Nginx의 다중 사이트별 구성 파일의 위치는 기본적으로 /etc/nginx/conf.d/의 하위에 *.conf 확장자로 등록하면 되며, nginx.conf에 include /etc/nginx/conf.d/*.conf와 같이 설정되어 있다.

사이트별 구성 파일의 위치를 다른 곳에 위치하고자 할 경우는 상기 include 문을 사용하여 위치를 추가한다. (예: include /etc/nginx/sites-enabled/*)

 

예를 들어, 서비스하고자 하는 사이트가 core1.mytest.com과 core2.mytest.com 두개가 있다고 하면

/etc/nginx/conf.d/ 하위에 AspnetCore_1.conf, AspnetCore_2.conf와 같은 사이트별 구성 파일을 생성하여 위치시킨다. (core1.mytest.com -> AspnetCore_1.conf, core2.mytest.com -> AspnetCore_2.conf)

 

- 기본 구성 파일 (default.conf)

server {
    listen       80;
    server_name  192.168.56.101;

    #charset koi8-r;
    #access_log  /var/log/nginx/log/host.access.log  main;

    location / {
        root   /usr/share/nginx/html;
        index  index.html index.htm;
    }

    #error_page  404              /404.html;

    # redirect server error pages to the static page /50x.html
    #
    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }

    # proxy the PHP scripts to Apache listening on 127.0.0.1:80
    #
    #location ~ \.php$ {
    #    proxy_pass   http://127.0.0.1;
    #}

    # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
    #
    #location ~ \.php$ {
    #    root           html;
    #    fastcgi_pass   127.0.0.1:9000;
    #    fastcgi_index  index.php;
    #    fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;
    #    include        fastcgi_params;
    #}

    # deny access to .htaccess files, if Apache's document root
    # concurs with nginx's one
    #
    #location ~ /\.ht {
    #    deny  all;
    #}

* listen의 포트를 바꿀 경우, Nginx의 기본 포트를 변경할 수 있다.

* server_name은 보통 서버의 이름을 사용하나, 가상화를 이용하여 서버를 설정한 경우, 외부에 노출되는

  (포워드 되는) 서버의 IP를 기록하여 로컬에서 가상화에 접근할 수 있도록 한다.

 

- http://core1.mytest.com 사이트에 대한 configuration 파일(AspnetCore_1.conf)

server {

    # Web Server 설정
    listen 80;
    server_name core1.mytest.com;

 

    location / {

            #Web Root 설정
            root       /var/www/AspnetCore_1;
            index      index.html;

 

            #로그 기록 설정
            access_log /var/log/nginx/AspnetCore_1.access.log;
            error_log  /var/log/nginx/AspnetCore_1.error.log;

 

            #프록시 설정

            proxy_pass http://localhost:5001;
            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;
    }
 } 

(/etc/nginx/conf.d/AspnetCore_1.conf)

* 사용자가 브라우져를 통해 core1.mytest.com으로 접속할 경우, 해당 ASP.NET Core의 웹 서비스에 접속할 수 있도록 Kestrel 웹 서비스를 prox_pass에 기록하며, server_name에 core1.mytest.com을 기록한다.

 

- http://core2.mytest.com 사이트에 대한 configuration 파일(AspnetCore_2.conf)

 

server {

    # Web Server 설정
    listen 80;
    server_name core2.mytest.com;

 

    location / {

            #Web Root 설정
            root       /var/www/AspnetCore_2;
            index      index.html;

 

            #로그 기록 설정
            access_log /var/log/nginx/AspnetCore_2.access.log;
            error_log  /var/log/nginx/AspnetCore_2.error.log;

 

            #프록시 설정

            proxy_pass http://localhost:5002;
            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;
    }
 } 

(/etc/nginx/conf.d/AspnetCore_2.conf)

 

- 상기 두 구성 파일은 하나의 구성 파일로 합쳐서 작성해도 무관하며, 예를들면 아래와 같다.

 

# core1.mytest.com

server {

...

 

# core2.mytest.com

server {

...

}

(/etc/nginx/conf.d/virtualhost.conf)

 

 

2. ASP.NET Core 웹 사이트의 배포

 

Visual Studio 등을 통해 윈도우에서 개발된 ASP.NET Core 사이트에 대하여 Linux로 배포하는 방법은 여러가지가 있을 수 있으나, 여기서는 SFTP를 통해서 배포하는 방식에 대하여 간단하게 기술한다. (향후 시간이 된다면 Jenkins for .NET 등에 대하여 설명하도록 하겠다.)

 

(1) core1.mytest.com, core2.mytest.com 두 ASP.NET Core 사이트

두 사이트는 단순한 ASP.NET Core 사이트로서, 각각 "Hello World! port# 5001", "Hello World! port# 5002"가 출력되는 사이트이다. 본 내용에서 배포 예제로서 사용하였다.

 

1) core1.mytest.com 사이트

- 프로젝트명: AspNetCore_1   ("dotnet new -t web" 명령어로 프로젝트 생성)

- localhost:5001로 웹 서비스 처리

- "dotnet publish" CLI 명령어를 통해 배포 소스 생성

 

2) core2.mytest.com 사이트

- 프로젝트명: AspNetCore_2  ("dotnet new -t web" 명령어로 프로젝트 생성)

- localhost:5002로 웹 서비스 처리

- "dotnet publish" CLI 명령어를 통해 배포 소스 생성

 

(2) ASP.NET Core publish 소스의 SFTP를 통한 배포

SFTP 프로그램으로는 WinSCP를 사용하였으며, Linux 계정으로 서버에 접속하여 상기 두 사이트의 배포 소스를 웹서버로 복사 처리

 

1) core1.mytest.com 사이트

- /var/www/AspnetCore_1/ 하위에 배포소스 복사

 

2) core2.mytest.com 사이트

- /var/www/AspnetCore_2/ 하위에 배포소스 복사

 

(3) ASP.NET Core 사이트 실행

- Supervisor를 구동 시키지 않으면 각 사이트별로 CLI를 통해 실행 시켜야 하나, 해당 접속 세션이 종료되면 Kestrel 웹서버도 같이 종료되므로 Supervisor를 통해 Kestrel Process를 실행해준다.

 

- 사이트 실행에 따른 접속 결과

[그림] core1.mytest.com 사이트 접속

 

[그림] core2.mytest.com 사이트 접속

 

 

3. Supervisor의 설치 및 설정 (버전 3.3.1 기준)

 

ASP.NET Core로 개발된 사이트를 실행 시 Kestrel 웹 서버를 이용하게 되며, Linux에서 CLI 형태로 구동되므로 아래의 그림과 같이 실행이 된다. 하지만 사이트 구동을 위해 매번 실행을 하는 것은 사이트 운영환경에 적합하지않다.

 

[그림] CLI로 ASP.NET Core 사이트 실행

 

Supervisior는 해당 사이트에서 설명하듯이 Process Control System이다.

즉, Linux에서 어떤 프로세스를 모니터링 하다가 프로세스가 죽으면 다시 실행해주거나, 부팅 시 해당 프로세스를 구동해 주거나 하는 역할을 한다.

 

ASP.NET Core 사이트를 Linux 웹서버에서 운영하기 위해 Supervisor를 설치하여 Kestrel 웹서버 Process를 daemon 형태로 구동할 수 있도록 처리한다.

 

(1) 설치

Supervisor의 설치는 단순히 CentOS의 yum에서 제공되는 패키지를 설치하기만 하면 된다.

 

sudo yum install supervisor 

 

(2) 설정

Supervisor의 설정 파일의 위치는 /etc/supervisord.conf 이며, 해당 파일의 [program:x] 영역을 사이트별로 여러개 설정하여 사용한다. (x는 각각의 사이트를 구분할 수 있는 alias 명칭임.)

 

- 설정 파일 위치: /etc/supervisord.conf

- 로그 파일 위치: /var/log/supervisor/supervisord.log

- 각 사이트별 로그 파일 위치: supervisord.conf의 [program:x]에 위치 및 파일명 기술

 

[program:AspnetCore_1]
command=/usr/local/bin/dotnet /var/www/AspnetCore_1/AspNetCore_1.dll
directory=/var/www/AspnetCore_1/
autostart=true
autorestart=true
stdout_logfile=/var/log/AspnetCore_1.out.log
stderr_logfile=/var/log/AspnetCore_1.err.log
environment=HOME=/var/www/AspnetCore_1/,ASPNETCORE_ENVIRONMENT=Production
user=root
stopsignal=INT
stopasgroup=true
killasgroup=true


[program:AspnetCore_2]
command=/usr/local/bin/dotnet /var/www/AspnetCore_2/AspNetCore_2.dll
directory=/var/www/AspnetCore_2/
autostart=true
autorestart=true
stdout_logfile=/var/log/AspnetCore_2.out.log
stderr_logfile=/var/log/AspnetCore_2.err.log
environment=HOME=/var/www/AspnetCore_2/,ASPNETCORE_ENVIRONMENT=Production
user=root
stopsignal=INT
stopasgroup=true
killasgroup=true

(/etc/supervisord.conf)

 

(3) Supervisor의 실행

 

1) 시작

 sudo systemctl start supervisord

 

2) 기타

- 부팅시, 자동 시작

sudo systemctl enable supervisord

 

- 옵션

  • 시작: sudo service supervisord start
  • 재시작: sudo service supervisord restart
  • 종료: sudo service supervisord stop
  • 상태 확인: sudo systemctl status supervisord

3) 상태 확인

- 정상 동작일 경우, 아래 그림과 같은 상태가 표시된다.

 

[그림] Supervisor의 상태 확인

 

 

4. 참고 사이트

 

(1) Linux에서의 포트 사용여부 확인

    http://myblog.opendocs.co.kr/archives/tag/could-not-bind-to-address-0-0-0-080

(2) Nginx의 Permission Denied 오류 방지 처리

    http://crystalcube.co.kr/181

(3) ASP.NET Core 다중 사이트 구성

    http://coderscoffeehouse.com/tech/2016/08/19/real-world-aspnetcore-linux-example.html

(4) Nginx

    http://nginx.org/

(5) How To Install Nginx on CentOS 7

    https://www.digitalocean.com/community/tutorials/how-to-install-nginx-on-centos-7

(6) Nginx 설치 및 설정

    http://dkatlf900.tistory.com/32

(7) Supervisor

    http://supervisord.org/index.html

(8) CnetOS 5, supervisor 설치 및 설정하기

    http://saksin.tistory.com/1226

 

 

PS.

나는 전산 전공자도 아닐뿐더러 Linux를 접할일이 거의 없었기에 생소한 환경에 웹서버 구성을 한다는 것이 쉽지않은 일이었다. (기껏해야 97년도 대학원에서 Unix의 일종인 Xenix 워크스테이션을 잠깐 이용해 본것이 전부다. 디자인 전공이었으므로...)

Linux에 .NET 기반의 웹 사이트를 올려본 느낌은 외국의 어느 개발자 이야기처럼 "오프로드를 달리는 느낌"이랄까...

Linux 인프라 환경에서 공공 또는 대기업의 .NET 기반 프로젝트는 얼마나 인고의 시간이 흘러야 가능할까?

Flow나 Detail한 Diagram도 그리고 해서 상세한 설명을 하고 싶지만, 프로젝트 진행중이니 심적인 여유를 가지기가 어려운 현실에 본 내용이라도 잊어버리지 말자고 간략하게 정리하였다.

댓글