nginx가 요청을 처리하는 방법
이름 기반 가상 서버
먼저 nginx는 어느 server가 요청을 처리할지 결정합니다. 3개의 가상 서버가 모두 포트 *:80을 수신하는 간단한 구성으로 시작해보겠습니다.
server {
listen 80;
server_name example.org www.example.org;
...
}
server {
listen 80;
server_name example.net www.example.net;
}
server {
listen 80;
server_name example.com www.example.com;
}
이 구성에서 nginx는 요청의 헤더 필드 “Host”만 테스트하여 어느 서버로 요청을 라우팅할지 결정합니다. 이 값이 서버 이름과 일치하지 않거나 요청에 이 헤더 필드 자체가 포함되어 있지 않으면 nginx가 이 포트에 대한 기본 서버로 요청을 라우팅합니다. 위의 구성에서 기본 서버는 첫 번째 서버가 되는데, 이는 nginx의 표준 기본 동작입니다. 특정 서버를 기본값으로 설정할 수도 있습니다. listen 명령에서 default_server 매개변수를 사용합니다.
server {
listen 80 default_server;
server_name example.net www.example.net;
...
}
default_server 매개변수는 0.8.21버전부터 사용할 수 있습니다. 이전 버전에서는 default 매개변수를 대신 사용해야 합니다.
기본 서버는 서버 이름의 속성이 아니라 리스닝 포트의 속성입니다. 자세한 내용은 나중에 설명하겠습니다.
정의되지 않은 서버 이름으로 요청을 처리하지 못하게 방지
“Host” 헤더 필드가 없는 요청을 허용하지 말아야 할 경우, 서버에서 해당 요청을 거부하도록 하려면 다음과 같이 정의합니다.
server {
listen 80;
server_name "";
return 444;
}
서버 이름은 “Host” 헤더 필드 없이 요청과 매칭할 빈 문자열로 설정합니다. nginx의 특수한 비표준 코드 444를 반환하여 연결을 종료합니다.
0.8.48버전 이후로 이 방식이 서버 이름의 기본 설정이 되었으므로 server_name “”을 생략할 수 있습니다. 이전 버전에서는 장비의 hostname을 기본 서버 이름으로 사용했습니다.
혼합형 이름 기반 및 IP 기반 가상 서버
가상 서버가 여러 주소를 수신하는 좀 더 복잡한 구성을 살펴보겠습니다.
server {
listen 192.168.1.1:80;
server_name example.org www.example.org;
}
server {
listen 192.168.1.1:80;
server_name example.net www.example.net;
}
server {
listen 192.168.1.2:80;
server_name example.com www.example.com;
}
이 구성에서 nginx는 먼저 요청의 IP 주소와 포트를 server 블록의 listen 명령에 대해 테스트합니다. 그러면 요청의 “Host” 헤더 필드를 IP 주소와 포트에 매칭되는 server 블록의 server_name 항목에 대해 테스트합니다. 서버 이름을 찾을 수 없는 경우, 요청은 기본 서버에서 처리됩니다. 예를 들어 192.168.1.1:80 포트에서 수신한 http://www.example.com에 대한 요청은 192.168.1.1:80 포트의 기본 서버(첫 번째 서버)에서 처리합니다. 이 포트에 대해 정의된 http://www.example.com이 없기 때문입니다.
앞서 말씀드렸듯이, 기본 서버는 리스닝 포트의 속성이고 각 포트에 서로 다른 서버를 정의할 수 있습니다.
server {
listen 192.168.1.1:80;
server_name example.org www.example.org;
}
server {
listen 192.168.1.1:80 default_server;
server_name example.net www.example.net;
}
server {
listen 192.168.1.2:80 default_server;
server_name example.com www.example.com;
}
간단한 PHP 사이트 구성
이제 nginx가 일반적인 간단한 PHP 사이트에 대한 요청을 처리할 location을 선택하는 방법을 알아보겠습니다.
server {
listen 80;
server_name example.org www.example.org;
root /data/www;
location / {
index index.html index.php;
}
location ~* \.(gif|jpg|png)$ {
expires 30d;
}
location ~ \.php$ {
fastcgi_pass localhost:9000;
fastcgi_param SCRIPT_FILENAME
$document_root$fastcgi_script_name;
include fastcgi_params;
}
}
먼저 나열된 순서와 관계없이 리터럴 문자열로 지정된 가장 구체적인 접두사 위치에 대해 검색합니다. 위의 구성에서 접두사 위치는 “/”뿐이고, 모든 요청과 매칭되므로 마지막 방법으로 사용합니다. 그러면 nginx가 구성 파일에 나열된 순서대로 정규식에서 지정한 위치를 검사합니다. 처음으로 일치하는 정규식이 나오면 검색을 중단하고, nginx가 이 위치를 사용합니다. 요청과 일치하는 정규식이 없으면 nginx는 앞서 발견한 가장 구체적인 접두사 위치를 사용합니다.
단, 모든 유형의 위치가 인수 없이 요청 행의 URI 부분만 테스트합니다. 그 이유는 다음과 같이 쿼리 문자열의 인수를 여러 가지 방식으로 부여할 수 있기 때문입니다.
/index.php?user=john&page=1
/index.php?page=1&user=john
게다가 누구나 쿼리 문자열로 무엇이든 요청할 수 있습니다.
/index.php?page=1&something+else&user=john
위의 구성에서 요청을 어떻게 처리하는지 살펴보겠습니다.
- “/logo.gif” 요청은 접두사 위치 “/”와 가장 먼저 매칭된 다음, 정규식 “\.(gif|jpg|png)$”와 매칭되므로 후자의 위치에서 처리됩니다. 이 요청은 “root /data/www” 명령을 사용하여 /data/www/logo.gif 파일에 매핑되고 파일은 클라이언트로 전송됩니다.
- “/index.php” 요청도 접두사 위치 “/”와 가장 먼저 매칭된 다음, 정규식 “\.(php)$”와 매칭됩니다. 그러므로 이 요청은 후자의 위치에서 처리되고 localhost:9000을 수신하는 FastCGI 서버로 전달됩니다. fastcgi_param 명령은 FastCGI 매개변수 SCRIPT_FILENAME을 “/data/www/index.php”로 설정하고, FastCGI 서버가 이 파일을 실행합니다. $document_root 변수는 root 명령의 값과 같고 $fastcgi_script_name 변수는 요청 URI(즉, ,“/index.php”)와 같습니다.
- “/about.html” 요청은 접두사 위치 “/”와만 매칭되므로 이 위치에서 처리됩니다. 이 요청은 “root /data/www” 명령을 사용하여 /data/www/about.html 파일에 매핑되고 파일은 클라이언트로 전송됩니다.
- “/” 요청을 처리하는 방법은 좀 더 복잡합니다. 접두사 위치 “/”와만 매칭되므로 이 위치에서 처리됩니다. 그러면 index 명령이 매개변수와 “root /data/www” 명령에 따라 인덱스 파일이 있는지 테스트합니다. /data/www/index.html 파일이 존재하지 않고 /data/www/index.php 파일이 있을 경우, 이 명령은 내부적으로 “/index.php”로 리디렉션하고 nginx는 마치 클라이언트가 요청을 보낸 것처럼 이 위치를 검색합니다. 앞서 확인하였듯이, 리디렉션된 요청은 최종적으로 FastCGI 서버에서 처리됩니다.