'Frameworks/Nginx'에 해당하는 글 2건

[Nginx] 기본 설정 방법

 

Nginx는 가벼운 고성능의 웹서버로서 높은 트래픽 처리를 위해 디자인되었다.

Nginx의 가장 강력한 기능 중 하나는 HTML이나 미디어 파일 같은 정적 컨텐츠를 효율적으로 서브하는 것이다. Nginx는 비동기적 이벤트 드리븐 모델(asynchronous event-driven model)을 사용하는데, 이것은 부하(load)에 대해 예측가능한 성능을 제공한다.

Nginx는 동적 컨텐트에 대해서는 CGI, FastCGI, 또는 아파치(Apache)와 같은 다른 서버에게 처리를 맡긴다. 이러한 동적 컨텐츠는 다시 Nginx에게 전달되어 결과적으로 클라이언트에게 전달된다. 이 글은 당신이 Nginx의 파라미터와 컨벤션에 익숙하게 만들어줄 것이다.

 

1. 디렉티브(Directives), 블록(Blocks), 그리고 컨텍스트(Contexts)

모든 nginx 컨피겨레이션 파일들은 /etc/nginx 디렉토리 안에 위치한다. 가장 주요한 컨피겨레이션 파일은 /etc/nginx/nginx.conf 파일이다.

nginx에서 켠피겨레이션 옵션은 디렉티브(directives)라고 불린다. 디렉티브는 블록(blocks) 또는 컨텍스트(contexts)라고 알려진 그룹으로 구성된다. 이 블록컨텍스트는 nginx에서 동일한 의미로 사용된다.

# 문자로 시작하는 줄은 주석으로서 nginx에 의해 해석되지 않는다. 디렉티브를 나타낼 때는 반드시 세미콜론(;)으로 끝나거나, 또는 중괄호 블록({})로 끝나야 한다.

아래에 보이는 것은 nginx 리포지토리에서 설치했을 때 디폴트로 포함되는 /etc/nginx/nginx.conf 파일의 압축된 형태이다.
이 컨피겨레이션 파일은 4개의 디렉티브(directives)로 시작한다: user, worker_processes, error_log, 그리고 pid이다. 이 디렉티브들은 어떠한 특정한 블록이나 컨텍스트 안에 포함되지 않는다. 따라서 그들은 메인 컨텍스트(main context) 안에 있다고 불린다. 그리고 eventshttp 블록은 추가적인 디렉티브를 위한 공간이며, 그들 또한 메인 컨텍스트 안에 존재한다.

user  nginx;
worker_processes  1;

error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;

events {
       . . .
}

http {
       . . .
}

 

2. http 블록

http 블록은 웹 트래픽을 처리하는 디렉티브들을 담고있다. 이 디렉티브들은 종종 Universal으로 불리는데, 왜냐하면 그것들은 nginx가 서브하는 모든 웹사이트 컨피겨레이션에 전달되기 때문이다. http 블록에서 사용되는 모든 디렉티브들의 목록은 Nginx 문서에서 찾아볼 수 있다.

http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    keepalive_timeout  65;

    #gzip  on;

    include /etc/nginx/conf.d/*.conf;
}

 

3. server 블록

  • 위의 http 블록 안에 있는 include 디렉티브는 nginx에게 웹사이트 컨피겨레이션 파일이 어디에 위치해 있는지를 알려준다. 만약 nginx 리포지토리에서 설치했다면 위에서와 같이 http 블록 안에 include /etc/nginx/conf.d/*.conf; 디렉티브가 포함되어 있을 것이다. 호스팅하는 각 웹사이트는 반드시 /etc/nginx/conf.d/ 디렉토리 안에 example.com.conf 형태로 만들어진 각자 자신만의 컨피겨레이션 파일을 갖고 있어야 한다. 그리고 사이트 중에서 비활성화된(disabled) 것들은 반드시 example.com.conf.disabled 형태로 파일 이름을 설정해야 한다.

  • 만약 nginx를 Debian 또는 Ubuntu 리포지토리에서 설치했다면, http 블록 안에는 include /etc/nginx/sites-enabled/*; 디렉티브가 포함되어 있을 것이다. 그 .../sites-enabled/ 디렉토리는 /etc/nginx/sites-available/ 디렉토리 안의 컨피겨레이션 파일들을 가리키는 심링크들(symlinks)을 담고 있다.

  • 당신의 nginx 설치 소스에 따라 샘플 컨피겨레이션 파일은 /etc/nginx/conf.d/default.conf 또는 etc/nginx/sites-enabled/default에 위치할 것이다.

그리고 설치 소스와는 상관없이 서버 컨피겨레이션 파일은 다음과 같은 어떤 하나의 기본 server 블록을 갖고 있을 것이다.

server {
    listen         80 default_server;
    listen         [::]:80 default_server;
    server_name    example.com www.example.com;
    root           /var/www/example.com;
    index          index.html;
    try_files $uri /index.html;
}

 

4. 리스닝 포트(Listening Ports)

listen 디렉티브는 nginx에게 HTTP 연결을 위해 필요한 hostname/IPTCP 포트(port)를 알려준다. default_server 인자가 의미하는 것은 이 가상의 호스트가 다른 가상의 호스트들의 listen statement와 매치되지 않는 모든 요청에 응답한다는 것이다. 그리고 두 번째 줄의 listen 디렉티브는 IPv6 형식의 요청을 처리한다는 것이고 default_server가 의미하는 것은 앞서 설명한 것과 동일하다.

 

5. 이름 기반의 가상 호스팅(Name-Based Virtual Hosting)

server_name 디렉티브는 하나의 IP 주소에 대해 여러개의 도메인(domains)을 사용할 수 있게 한다. 서버는 전달받은 요청 헤더(request header)에 기반하여 어떤 도메인을 서브할지 결정한다.

일반적으로 호스트하고자 하는 하나의 도메인 또는 하나의 사이트당 하나의 파일을 생성한다. 다음의 예제들이 있다.

  1. example.comwww.example.com 두 개 모두의 도메인에 대한 요청을 처리하는 경우에는 다음과 같이 설정한다.
# /etc/nginx/conf.d/example.com.conf

server {
    server_name   example.com www.example.com;
      . . .
}
  1. server_name 디렉티브는 또한 와일드카드(*)를 사용할 수 있다. *.example.com.example.com는 둘 다 example.com의 모든 서브도메인들(subdomains)에 대한 요청을 처리하도록 한다.
# /etc/nginx/conf.d/example.com.conf

server {    
    server_name   *.example.com;  # 또는 .example.com;
        . . .
}
  1. example.으로 시작하는 모든 도메인에 대한 요청을 처리하는 경우 다음과 같이 설정한다.
# /etc/nginx/conf.d/example.com.conf

server {    
    server_name   example.*;
        . . .
}

nginx는 유효하지 않은 도메인 네임을 server_name에 사용할 수 있도록 한다. nginx는 요청의 HTTP 헤더에 있는 이름을 사용하여 요청에 응답하며, 해당 도메인 네임이 유효한지 아닌지는 상관없다.

도메인 네임이 아닌 호스트네임(non-domain hostname)을 사용하는 것은 서버가 LAN에 있거나 또는 이미 서버에 요청을 보낼 클라이언트들을 알고 있는 경우 유용하다. 예를 들면 이것은 nginx가 듣고있는 IP 주소들로 설정된 /etc/hosts 엔트리를 사용하는 전면 프록시 서버(front-end proxy servers)를 사용할 때 유용하다.

 

6. location 블록

location 디렉티브는 서버 안의 리소스에 대한 요청을 어떻게 응답해야 할지를 설정한다. server_name 디렉티브가 nginx에게 해당 도메인에 대한 요청을 어떻게 처리해야 하는지 설정하는 것처럼, location 디렉티브는 특정 파일과 특정 디렉토리에 대한 요청을 처리한다. 예를 들면, http://example.com/blog/와 같은 요청에 대한 처리를 설정한다. 다음과 같은 예가 있다.

# /etc/nginx/sites-available/example.com

server {
    location / {
        . . .
    }

    location /images/ { 
        . . .
    }

    location /blog/ { 
        . . .
    }

    location /planet/ { 
        . . .
    }

    location /planet/blog/ { 
        . . .
    }
}

위의 location 디렉티브들은 리터럴 스트링(literal string)에 대한 매치이며, 호스트 세그멘트(host segment) 이후에 오는 HTTP 요청에서 어떠한 부분이라도 매치된다. 위와 같은 location 디렉티브 설정에서 다음과 같은 몇 가지 요청들에 대한 예를 살펴보자.

 

요청(Request): http://example.com/

응답(Response): example.com을 위한 server_name 엔트리가 존재한다는 가정하에, 위의 location / 디렉티브가 요청에 대해 어떻게 응답할지를 결정할 것이다.

Note:
nginx는 항상 가장 구체적인 매치(the most specific match)에 대해 요청을 처리할 것이다.

 

요청(Request): http://example.com/planet/blog/ 또는 http://example.com/planet/blog/about/

응답(Response): 이것은 location /planet/blog/ 디렉티브가 요청에 대해 어떻게 응답할지를 결정할 것이다. 비록 location /planet/ 디렉티브도 매치되긴 하지만 가장 구체적인 매치가 요청을 처리한다.

 

# /etc/nginx/sites-available/example.com

server {
    location ~ IndexPage\.php$ {
        . . .
    }

    location ~ ^/BlogPlanet(/|/index\.php)$ { 
        . . .
    }
}

만약 location 디렉티브 뒤에 틸드(~) 문자가 올 경우, nginx는 레귤러 익스프레션(regular expression) 매치를 수행한다. 위의 매치 예제들은 대소문자를 구분(case-sensitive)하기 때문에 위의 예제에서 첫 번째 location 디렉티브에 대해 IndexPage.php는 매치가되지만 indexpage.php는 매치되지 않는다.

위의 예제에서 두 번째 location 디렉티브에 대해 /BlogPlanet//BlogPlanet/index.php는 매치되지만, /BlogPlanet, /blogplanet/, 또는 /blogplanet/index.php는 매치되지 않는다.

Note:
nginx는 Perl Compatible Regular Expressions(PCRE)을 사용한다.

 

# /etc/nginx/sites-available/example.com

server {
    location ~* \.(pl|cgi|perl|prl)$ {
        . . .
    }

    location ~* \.(md|mdwn|txt|mkdn)$ { 
        . . .
    }
}

만약 레귤러 익스프레션을 대소문자 구분없이(case-insensitive) 매치되도록 하고 싶다면 a tiled and asterisk(~*)를 사용하도록 한다. 위의 예제에서는 특정 파일 확장자로 끝나는 요청들을 어떻게 처리할지를 나타낸다. 첫 번째 location 디렉티브는 .pl, .PL, .cgi, .CGI, .perl, .Perl, .prl, 그리고 .PrL로 끝나는 어떠한 요청에 대해서도 매치될 것이다.

 

# /etc/nginx/sites-available/example.com

server {
    location ^~ /images/IndexPage/ {
        . . .
    }

    location ^~ /blog/BlogPlanet/ {
        . . .
    }
}

만약 location 디렉티브 뒤에 a caret and tilde(^~)를 붙인다면, nginx는 특정 스트링과 매치가 있으면 더 이상 다른 매치를 찾기위해 진행하지 않고 바로 그 매치되는 디렉티브를 사용한다. 다른 곳에 더욱 구체적으로 매치되는 디렉티브가 있더라도, 해당 요청이 이러한 디렉티브 중에 하나에 매치된다면 곧바로 그 디렉티브가 사용된다.

 

# /etc/nginx/sites-available/example.com

server {
    location = / {
        . . .
    }
}

마지막으로 location 디렉티브 뒤에 an equals sign(=)를 붙인다면, 요청된 경로(path)에 대해서 정확히 일치하는 매치를 찾으면 다른 location 디렉티브에 대한 서치를 마치고 그 정확히 일치하는 디렉티브를 사용한다. 따라서 위의 예제에서는 http://example.com/는 정확히 일치하므로 매치되지만 http://example.com/index.html는 매치되지 않는다. 정확한 매치를 사용하는 것은 요청 처리 시간을 줄이는데 도움이 되는데, 특정 경로의 요청이 자주 발생한다면 매우 유용할 수 있다.

 

최종 정리된 디렉티브 매칭 처리 순서는 다음과 같다.

  1. 정확한 스트링 매치(exact string matches)를 먼저 찾는다. 만야 매치가 발견될 경우 nginx는 더 이상 서치를 멈추고 해당 디렉티브를 사용하여 요청을 처리한다.

  2. 그 다음 나머지 리터럴 스트링 매치(literal string matches)를 찾는다. nginx는 만약 ^~를 가진 매치를 발견했을 경우 서치를 중단하고 해당 디렉티를 사용하여 요청을 처리한다. 만약 ^~ 매치가 없을 경우 다음의 리터럴 스트링 매치를 계속 찾으며 가장 구체적인 매치를 저장해놓는다.

  3. 그 다음 레귤러 익스프레션(~ 또는 ~*)을 가진 매치를 찾는다. 만약 요청과 매치되는 레귤러 익스프레션을 찾을 경우 서치를 중단하고 해당 디렉티브를 사용하여 요청을 처리한다.

  4. 만약 레귤러 익스프레션과 매치되는 디렉티브를 발견하지 못한다면, 현재 저장되어 있는 가장 구체적으로 매치되는 리터럴 스트링 매치(literal string match)가 사용된다.

Note:
Nginx에서 location 디렉티브 안에 네스티드 블록(nested blocks)은 지원하지 않는다.

 

7. location 블록의 root와 index

location 디렉티브는 자체적인 인자값(arguments)을 갖고 있는 블록이다.

nginx가 어떤 location 디렉티브가 요청에 대해 가장 적절한 매치인지 결정하면, 이 요청에 대한 응답은 해당 location 디렉티브 블록 안에 있는 관련된 컨텐츠에 의해 결정된다. 다음과 같은 예제를 살펴보자.

# /etc/nginx/sites-available/example.com

server {
    location / {
        root html;
        index index.html index.htm;
    }
}

이 예제에서 해당 location의 문서의 root는 html/ 디렉토리에 있다. nginx의 디폴트 프리픽스에 의해서 전체 경로는 /etc/nginx/html/이다.

 

요청(Request): http://example.com/blog/includes/style.css

응답(Response): nginx는 /etc/nginx/html/blog/includes/style.css에 위치한 파일을 서브할 것이다.

Note:
root 디렉티브에는 절대경로(absolute paths) 또한 사용할 수 있다.

index 디렉티브는 아무런 파일명이 명시되어 있지 않을 때 어떤 것을 서브해야 하는지를 알려준다. 다음 예를 보자.

 

요청(Request): http://example.com

응답(Response): nginx는 /etc/nginx/html/index.html에 있는 파일을 서브할 것이다.

만약 index 디렉티브에 여러개의 파일이 명시되어 있다면, nginx는 파라미터들이 쓰여진 순서대로 처리하며, 그 중에서 파일이 존재하면 응답할 것이다. 즉 위의 예제에서는 index.html 파일을 먼저 찾아보고 없을 경우에는 다음으로 index.htm 파일을 찾아보고 이것도 없을 경우 404 오류(Not Found)를 응답한다.

다음은 도메인 example.com에 대응하는 서버의 조금 더 복잡한 형태의 location 디렉티브들을 보여주고 있다.

# /etc/nginx/sites-available/example.com

server {
    location / {
        root   /srv/www/example.com/public_html;
        index  index.html index.htm;
    }

    location ~ \.pl$ {
        gzip off;
        include /etc/nginx/fastcgi_params;
        fastcgi_pass unix:/var/run/fcgiwrap.socket;
        fastcgi_index index.pl;
        fastcgi_param SCRIPT_FILENAME /srv/www/example.com/public_html$fastcgi_script_name;
    }
}

위의 예제에서, 확장자가 .pl로 끝나는 모든 요처들은 두 번재 location 블록에 의해 처리되며, 그것은 fastcgi 핸들러를 명시하여 요청들을 처리한다. 그 외 나머지 요청에 대해서는 nginx는 첫 번째 location 디렉티브를 사용한다.
리소스들은 파일 시스템의 /srv/www/example.com/public_html/ 디렉토리에 위치한다. 만약 요청에서 파일 이름이 명시되지 않을 경우에는 nginx는 index.html 또는 index.htm 파일을 제공할 것이다. 만약 두 개의 파일 모두 존재하지 않을 경우 서버는 404 오류(Not Found)를 응답한다.

몇 가지 요청들에 대해서 위의 예제 서버가 어떻게 응답하는지 살펴보자.

 

요청(Request): http://example.com/

응답(Response): 우선 /srv/www/example.com/public_html/index.html 파일을 찾아보고 만약 존재하지 않으면 /srv/www/example.com/public_html/index.htm 파일을 찾아볼 것이다. 만약 둘 다 존재하지 않으면 서버는 404 오류(Not Found)를 응답한다.

 

요청(Request): http://example.com/blog/

응답(Response): 우선 /srv/www/example.com/public_html/blog/index.html 파일을 찾아보고 만약 존재하지 않으면 /srv/www/example.com/public_html/blog/index.htm파일을 찾아볼 것이다. 만약 둘 다 존재하지 않으면 서버는 404 오류(Not Found)를 응답한다.

 

요청(Request): http://example.com/tasks.pl

응답(Response): nginx는 FastCGI 핸들러를 사용하여 /srv/www/example.com/public_html/tasks.pl에 존재하는 파일을 실행하고 결과를 응답한다.

 

요청(Request): http://example.com/username/roster.pl

응답(Response): nginx는 FastCGI 핸들러를 사용하여 /srv/www/example.com/public_html/username/roster.pl에 존재하는 파일을 실행하고 결과를 응답한다.




References

[1] Linode. (2019, Apr 5). How to Configure NGINX [Web Document]

[2] Nginx. (?). Module ngx_http_core_module [Web Document]

[3] Perl. (?). Perl Compatible Regular Expressions(PCRE) [Web Document]

 


Hashtags

#엔진엑스 #엔진엑스 설정 #엔진엑스 가이드 #엔진엑스 매뉴얼 #엔진엑스 설정 #엔진엑스 컨피겨레이션 #Nginx 설정 #nginx 서버 #nginx 가이드 #nginx 매뉴얼 #Nginx #Nginx Guide #Nginx Manual #nginx.conf #Nginx Config #Nginx Configuration #Nginx Directives #Nginx Blocks Nginx Contexts #nginx http #nginx server #nginx location #nginx proxy server #nginx request #nginx response #sites-available #sites-enabled



© 2020, Byeongcheol Yoo. All rights reserved.

'Frameworks > Nginx' 카테고리의 다른 글

[Nginx] 초보자 가이드  (0) 2020.03.19

WRITTEN BY
아키텍토필
소프트웨어 아키텍트의 스터디 룸

,

[Nginx] 초보자 가이드


1. Nginx 기본 설명

nginx는 1개의 마스터 프로세스(master process)여러개의 워커 프로세스들(worker processes)을 가지고 있다.
마스터 프로세스의 주요 역할은 설정(configuration)을 읽고 평가하고, 워커 프로세스들을 관리하는 것이다.
반면 워커 프로세스들의 역할은 실질적인 요청들(requests)을 처리하는 것이다. nginx는 이벤트 기반 모델(event-based model) 사용하며, 운영체제 의존적인(OS-dependent) 메커니즘을 활용하여 워커 프로세스들 사이의 요청을 효율적으로 분배한다.
워커 프로세스의 개수는 컨피겨레이션 파일 안에 정의되어 있는데, 설정에 따라 절대적인 개수로 고정될 수도 있고 또는 가용한 CPU 코어의 개수에 따라 자동으로 조절될 수도 있다.

nginx와 그 모듈들이 동작하는 방식은 컨피겨레이션 파일 안에서 결정된다. 디폴트로는 그 컨피겨레이션 파일 이름은 nginx.conf로 되어 있으며, 그 파일이 위치하는 디렉토리는 /usr/local/nginx/conf, /etc/nginx, 또는 /usr/local/etc/nginx이다.


2. Nginx 시작, 중지 그리고 리로딩 설정 방법

nginx를 시작하기 위해서는 우선 실행파일(executable file)을 실행한다. nginx가 시작되면 실행파일을 -s 파라미터와 함께 실행하여 컨트롤할 수 있다. 사용 문법은 다음과 같다.

nginx -s [signal]

signal의 종류는 다음과 같이 4가지가 있다.

  • stop : 빠른 종료(fast shutdown)
  • quit : 우아한 종료(graceful shutdown)
  • reload : 컨피겨레이션 파일(configuration file) 다시 로딩하기
  • reopen : 로그 파일 다시 열기

예를 들어, nginx를 종료할 때 워커 프로세스들이 현재 처리하고 있는 요청들을 모두 완료할 때까지 기다리고 싶을 때는 다음과 같은 명령을 사용한다.

foo@bar:~$ nginx -s quit

위 명령은 nginx를 실행시킨 유저와 동일한 유저에 의해 실행되어야 한다. 만약 nginx를 실행한 유저가 root 유저일 경우 권한 획득을 위해 sudo와 같은 명령을 함께 사용해야 한다.

컨피겨레이션 파일이 변경되었을 경우, nginx에 reload 명령을 보내거나 nginx를 재시작하기 전까지는 변경된 설정은 적용되지 않는다. 컨피겨레이션을 리로드하기 위해서는 다음과 같은 명령을 사용한다.

foo@bar:~$ nginx -s reload

마스터 프로세스가 reload 시그널을 전달받은 경우, 그것은 우선 새로운 컨피겨레이션 파일의 문법 유효성 검사를 마친 뒤, 새로운 설정을 적용한다. 만약 문법 검사에서 이상이 없을 경우, 마스터 프로세스는 새로운 워커 프로세스들을 실행시키고, 예전 워커 프로세스들에게는 메시지를 보내 종료 요청을 한다. 예전 워커 프로세스들은 종료 요청을 받으면 더 이상 새로운 요청은 거부하고 기존에 처리하던 요청들을 마무리한 뒤 종료한다.

하지만 만약 문법 검사에 이상이 있거나 오류가 발생했을 경우에는 마스터 프로세스는 변경 내용을 롤백(roll back)하고 이전 설정(configuration)으로 계속 작업한다.

signal은 kill과 같은 Unix 툴을 사용하여 nginx 프로세스에게 전달될 수 있다. 이 경우에는 signal은 프로세스 ID를 이용해 프로세스에게 직접 전달된다. 그 nginx 마스터 프로세스의 프로세스 ID는 기본적으로 /usr/local/nginx/logs 또는 /var/run 디렉토리에 있는 nginx.pid 파일에 쓰여있다. 만약 마스터 프로세스의 프로세스 ID가 1628일 경우, nginx에게 우아한 종료(graceful shutdown) 요청을 보내기 위해서는 다음과 같이 명령을 사용할 수 있다.

foo@bar:~$ kill -s QUIT 1628

실행 중인 모든 nginx 프로세스들의 목록을 얻기 위해서는 ps 유틸리티를 사용하여 다음과 같이 명령을 사용한다.

foo@bar:~$ ps -ax | grep nginx

3. 컨피겨레이션 파일(configuration file) 구조

nginx는 여러 개의 모듈들로 구성되어 있는데, 그것들은 컨피겨레이션 파일 안의 디렉티브(directives)에 의해 제어된다. 디렉티브들은 심플 디렉티브(simple directives)블록 디렉티브(block directives)로 나뉜다. 심플 디렉티브의 이름과 파라미터는 스페이스(spaces)에 의해 구분되고 세미콜론(;)으로 끝난다. 블록 디렉티브는 심플 디렉티브와 기본적으로는 동일한 구조를 가지는데, 하지만 세미콜론 대신에 그것은 중괄호(braces)로 둘러싸인 추가적인 명령들의 집합이 뒤에 붙는다. 그리고 만약 블록 디렉티브가 중괄호 안에 다른 디렉티브를 가질 수 있으면 그것은 컨텍스트(context)라고 불린다(e.g. events, http, server 그리고 location 등).

컨피겨레이션 파일 안에서 다른 컨텍스트 밖에 있는 디렉티브들은 모두 메인 컨텍스트(main context) 안에 있는 것으로 본다.
eventshttp 디렉티브는 메인 컨텍스트 안에 있는 것이고, server 디렉티브는 http 컨텍스트 안에, 그리고 location 디렉티브는 server 컨텍스트 안에 있는 것이다.

그리고 # 기호 이후에 오는 모든 줄은 주석으로 간주된다.


4. 정적 컨텐트(static content) 서빙

웹 서버의 중요한 업무는 파일들(e.g. images 또는 정적 HTML pages 등)을 서빙하는 것이다. 이제 우리는 서버에 들어오는 요청에 따라서 서로 다른 로컬 디렉토리들(/data/www(HTML 파일 디렉토리) 그리고 /data/images(이미지 파일 디렉토리))에 있는 파일들이 서빙되는 예제를 구현할 것이다. 이를 위해서 컨피겨레이션 파일을 수정해야 하는데, http 블록 안에 server 블록을 설정하고, 그 server 블록 안에는 두 개의 location 블록들을 설정할 것이다.

우선, /data/www 디렉토리를 생성하고 그 안에 index.html 파일을 만들고 아무런 텍스트 내요을 작성한다. 그리고 /data/images/ 디렉토리를 만들고 그 안에 몇 장의 이미지 파일들을 넣는다.

그 다음 컨피겨레이션 파일을 연다. 디폴트 컨피겨레이션 파일 안에는 이미 몇 개의 server 블록에 대한 예제들이 포함되어 있는데, 대부분은 주석으로 처리되어있다. 이제 다른 모든 블록들을 주석으로 처리하고 새로운 server 블록을 다음과 같이 작성한다.

http {
    server {
    }
}

일반적으로 컨피겨레이션 파일 안에는 여러개의 server 블록들을 포함할 수 있는데, 그것들은 사용하는 포트번호 또는 서버이름에 따라 나뉘어져있다. 어떤 요청이 들어오면 nginx는 우선 어떤 server 블록이 해당 요청을 처리할지 결정하고, 그 다음은 요청 헤더(header)에 있는 URI를 server 블록 안의 location 디렉티브들의 파라미터(parameters)와 대조하여 검사한다.

이제 server 블록 안에 다음의 location 블록을 추가한다.

location / {
    root /data/www;
}

위의 location 블록은 요청에서 URI와 비교하여 "/" 프리픽스(prefix)를 나타낸다. 매칭되는 요청에 대해서 root 디렉티브에 설정된 경로(path)에 해당 URI가 붙여진다. 즉, /data/www에 붙여져서 로컬 파일 시스템에 있는 요청된 파일에 대한 경로를 형성한다.
만약 location 블록들 중에 매칭되는 것이 여러개 있다면, nginx는 그 중 가장 긴 프리픽스(prefix)를 가진 것을 선택한다. 위의 location 블록은 길이 1의 가장 짧은 프리픽스를 제공한다. 따라서 다른 모든 location 블록들이 매칭에 실패할 경우 이 블록이 사용될 것이다.

이제 아래의 두 번째 location 블록을 추가한다.

location /images/ {
    root /data;
}

위의 location 블록은 /images/로 시작하는 요청에 대해 매치가될 것이다(location / 블록에도 역시 매치될 것이지만 이것은 가장 짧은 길이의 프리픽스이다.)

현재까지 작성된 server 블록의 모습은 아래와 같다.

server {
    location / {
        root /data/www;
    }

    location /images/ {
        root /data;
    }
}

이것은 이미 포트 80에서 듣고 있는 서버로 동작하는 컨피겨레이션이며, 그것은 로컬 머신에서 http://localhost/로 접속이 가능하다.
그리고 /images/로 시작하는 URI를 가진 요청에 대해서는 서버는 /data/images 디렉토리에서 파일을 전송할 것이다.
예를 들어, http://localhost/images/example.png 요청에 대한 응답으로 nginx는 /data/images/example.png 파일을 전송할 것이다. 만약 그 파일이 존재하지 않을 경우 nginx는 404 오류(Not Found)를 전송할 것이다.
그리고 /images/로 시작하지 않는 URI를 가진 요청은 /data/www 디렉토리로 맵핑될 것이다. 예를 들어, http://localhost/some/example.html 요청에 대한 응답으로 nginx는 /data/www/some/example.html 파일을 전송할 것이다.

새로운 컨피겨레이션을 적용하기 위해서, 아직 nginx를 실행하지 않았으면 nginx를 시작시키고, 이미 샐행 중인 경우 다음과 같이 reload 시그널을 마스터 프로세스에 전송한다.

foo@bar:~$ nginx -s reload

Note:
만약 어떤 것이 예상한대로 동작하지 않을 경우, /usr/local/nginx/logs 또는 /var/log/nginx 디렉토리 안에 있는 access.log 또는 error.log 파일을 확인해 볼 수 있다.


5. 간단한 프록시 서버(proxy server) 세팅

nginx의 가장 흔한 사용 중 하나는 그것을 프록시 서버로 사용하는 것이다. 따라서 프로시 서버는 요청을 받으면 프록시된 다른 서버에게 요청을 전달하고, 그들에게 받은 응답을 결과적으로 클라이언트에게 전송한다.

우리는 기본적인 프록시 서버를 하나 설정할 것인데, 그것은 로컬 디렉토리에 있는 이미지 파일에 대한 요청을 처리하고, 나머지 모든 요청들은 프록시된 서버에게 전달한다. 이 예제에서, 두 서버 모두 하나의 nginx 인스턴스에서 정의된다.

우선, 프록시된 서버를 하나 정의할 것인데, 다음과 같이 컨피겨레이션 파일에 하나의 server 블록을 추가한다.

server {
    listen 8080;
    root /data/up1;

    location / {
    }
}

이것은 포트 8080을 듣고 있는 간단한 서버가 될 것인데(이전에는 listen 디렉티브를 생략했었는데, 왜냐하면 표준 포트인 80번이 사용되었기 때문이다.) 이 서버는 모든 요청을 로컬 파일 시스템의 /data/up1 디렉토리로 맵핑할 것이다. 따라서 /data/up1 디렉토리를 생성하고 이 안에 새로운 index.html 파일을 만들어 넣도록한다. 이 때 잘 보아야할 것은 root 디렉티브가 server 컨텍스트 안에 위치한다는 점이다. 그러한 root 디렉티브는 어떤 요청에 대해 선택된 location 블록이 자체적인 root 디렉티브를 갖고 있지 않을 때 사용된다.

다음으로, 이전에 작성했던 server 컨피겨레이션을 수정하여 프록시 컨피겨레이션으로 만들어보자. 첫 번째 location 블록에는 proxy_pass 디렉티브와 함께 프록시된 서버의 프로토콜, 이름, 포트 번호를 파라미터에 명시된대로 넣어준다(이 경우에는 http://localhost:8080가 된다.)

server {
    location / {
        proxy_pass http://localhost:8080;
    }

    location /images/ {
        root /data;
    }
}

그리고 두 번째 location 블록을 수정하여 특정 파일 확장자를 가진 이미지 요청에 대해 매치되도록 만든다. 변경된 location 블록은 다음과 같다.

location ~ \.(gif|jpg|png)$ {
    root /data/images;
}

위의 파라미터는 레귤러 익스프레션(regular expression)이며 이것은 .gif, .jpg, 또는 .png로 끝나는 모든 URI와 매치된다. 레귤러 익스프레션은 반드시 ~ 심볼을 앞에 붙여야한다. 이에 해당하는 요청들은 모두 /data/images 디렉토리로 맵핑될 것이다.

nginx가 요청을 처리하기 위해 어떤 location 블록을 선택할 때는, 우선 각 location 디렉티브의 프리픽스(prefix)를 검사하고 매치되는 가장 긴 프리픽스를 가진 하나의 location 블록을 기억해둔다. 그 다음으로 레귤러 익스프레션을 검사한다. 만약 매치되는 레귤러 익스프레션이 있을 경우 그 location을 선택하게 되고, 매치되는 레귤러 익스프레션이 없을 경우에는 이전에 기억해두었던 location 블록을 선택한다.

지금까지 완성된 프록시 서버의 컨피겨레이션은 다음과 같다.

server {
    location / {
        proxy_pass http://localhost:8080/;
    }

    location ~ \.(gif|jpg|png)$ {
        root /data/images;
    }
}

이 서버는 .gif, .jpg, 또는 .png로 끝나는 모든 요청을 필터링하여 /data/images 디렉토리로 맵핑할 것이다(해당 root 디렉티브의 파라미터에 요청의 URI를 덧붙인다.) 그리고 다른 모든 요청들은 위에 설정한 프록시된 서버로 전달될 것이다.

새로운 컨피겨레이션을 적용하기 위해서 이전처럼 reload 시그널을 마스터 프로세스에 전송한다.

foo@bar:~$ nginx -s reload

Note:
프록시 커넥션을 설정하기 위한 많은 다양한 디렉티브(directives)가 존재한다.


6. FastCGI 프록시 세팅

nginx는 요청들을 다양한 프레임워크와 PHP와 같은 프로그래밍 언어로 빌드된 어플리케이션을 실행하는 FastCGI 서버들로 라우트(route)하기 위해 사용될 수 있다.

FastCGI 서버와 함께 동작하기 위한 가장 기본적인 nginx 컨피겨레이션은 proxy_pass 대신에 fastcgi_pass 디렉티브를 사용하는 것이다. 그리고 FastCGI 서버에 전달되는 파라미터(parameters)를 설정하기 위해서 fastcgi_param 디렉티브를 사용한다.
FastCGI 서버가 localhost:9000에서 접속가능하다고 가정해보자. 이전의 프록시 설정을 기본으로 해서 proxy_pass 디렉티브를 fastcgi_pass 디렉티브로 교체하고 파라미터를 localhost:9000로 설정한다. PHP에서는 SCRIPT_FILENAME 파라미터는 스크립트 이름을 결정하기 위해 사용되며, QUERY_PARAMETER는 요청 파라미터를 전달하기 위해 사용된다. 완성된 컨피겨레이션은 다음과 같다.

server {
    location / {
        fastcgi_pass  localhost:9000;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param QUERY_STRING    $query_string;
    }

    location ~ \.(gif|jpg|png)$ {
        root /data/images;
    }
}

위의 서버는 정적 이미지에 대한 요청을 제외한 모든 요청들을 localhost:9000에서 동작 중인 프록시된 서버에게 FastCGI 프로토콜을 사용해 라우트(route)할 것이다.




References

[1] Nginx. (?). Beginner’s Guide [Web Document]

[2] Nginx. (?). Module ngx_http_proxy_module [Web Document]



Hashtags

#엔진엑스 #엔진엑스 설정 #엔진엑스 가이드 #엔진엑스 매뉴얼 #엔진엑스 설정 #엔진엑스 컨피겨레이션 #디렉티브 #Nginx 설정 #nginx 서버 #nginx 가이드 #nginx 매뉴얼 #Nginx #nginx block #nginx load balance #Nginx Guide #Nginx Manual #nginx.conf #Nginx Config #Nginx Configuration #Nginx Directives #Nginx Blocks Nginx Contexts #nginx http #nginx server #nginx location #nginx proxy server #nginx request #nginx response #sites-available #sites-enabled



© 2020, Byeongcheol Yoo. All rights reserved.

'Frameworks > Nginx' 카테고리의 다른 글

[Nginx] 기본 설정 방법  (2) 2020.03.19

WRITTEN BY
아키텍토필
소프트웨어 아키텍트의 스터디 룸

,