-
Notifications
You must be signed in to change notification settings - Fork 1
NGINX가 요청을 처리하는 법
이름 기반의 가상 서버들
nginx는 먼저 요청을 처리할 서버를 결정합니다. 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 매개변수를 대신 사용해야 합니다.
기본 서버는 서버 이름이 아니라 listen 포트의 속성임을 유의해야 합니다. 이에 대해서는 나중에 더 자세히 설명하겠습니다.
- Host는 HTTP 요청 헤더에 포함되어 있음
- HTTP 1.1에서 필수적으로 요구되는 헤더
- "Host" 헤더가 없는 HTTP 요청을 보내면, 웹 서버는 어떤 도메인에 대한 요청인지 알 수 없기 때문에 기본적으로 요청 처리에 실패
정의되지 않은 서버 이름의 요청 처리를 방지하는 방법
-
Host 헤더 필드가 없는 요청을 허용하지 않을 경우, 요청만 삭제하는 서버를 정의할 수 있습니다.
server { listen 80; server_name ""; return 444; }- 여기서 서버 이름은 Host 헤더 필드가 없는 요청과 일치하는 빈 문자열로 설정, 연결을 닫는 특수 nginx의 비표준 코드 444가 반환됩니다.
버전 0.8.48부터 이것이 서버 이름의 기본 설정이므로 서버 이름 ""은 생략할 수 있습니다. 이전 버전에서는 컴퓨터의 호스트 이름이 기본 서버 이름으로 사용되었습니다.
이름 기반 및 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 주소와 포트를 서버 블록의 listen 지시어와 비교합니다. 그 후에 IP 주소와 포트가 일치하는 서버 블록의 server_name 항목과 요청의 Host 헤더 필드를 비교합니다. 만약 서버 이름을 찾지 못하면, 요청은 기본 서버에서 처리됩니다.
예를 들어 192.168.1.1:80 포트에서 받은 www.example.com에 대한 요청은 이 포트에 대해 정의되어 있지 않기 때문에 192.168.1.1:80 포트의 기본 서버, 즉 첫 번째 서버에서 처리됩니다.
이미 설명했듯이 기본 서버는 수신 포트의 속성이며, 포트마다 다른 기본 서버를 정의할 수 있습니다:
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;
...
}
이 설정에서는 두 개의 서버 블록이 192.168.1.1:80 주소와 포트에 바인딩되어 있고, 한 개의 서버 블록이 192.168.1.2:80 주소와 포트에 바인딩되어 있습니다. 각각의 서버 블록은 서로 다른 도메인 이름을 server_name으로 가지고 있습니다.
요청이 어떻게 처리되는지 예시를 들어 설명하겠습니다.
- 클라이언트가 "Host: www.example.org" 헤더를 가진 요청을 192.168.1.1:80으로 보내면, 첫 번째 서버 블록에서 처리됩니다. 이는 첫 번째 서버 블록이 해당 IP 주소와 포트에 바인딩되어 있고,
server_name이 요청의 "Host" 헤더와 일치하기 때문입니다. - 클라이언트가 "Host: www.example.net" 헤더를 가진 요청을 192.168.1.1:80으로 보내면, 두 번째 서버 블록에서 처리됩니다. 이는 두 번째 서버 블록이 해당 IP 주소와 포트에 바인딩되어 있고,
server_name이 요청의 "Host" 헤더와 일치하기 때문입니다. - 클라이언트가 "Host: www.example.com" 헤더를 가진 요청을 192.168.1.2:80으로 보내면, 세 번째 서버 블록에서 처리됩니다. 이는 세 번째 서버 블록이 해당 IP 주소와 포트에 바인딩되어 있고,
server_name이 요청의 "Host" 헤더와 일치하기 때문입니다. - 만약 클라이언트가 "Host" 헤더 없는 요청을 192.168.1.1:80으로 보내면, 두 번째 서버 블록에서 처리됩니다. 이는 두 번째 서버 블록이 해당 IP 주소와 포트에 바인딩되어 있고,
default_server로 설정되어 있기 때문입니다. - 마찬가지로, "Host" 헤더 없는 요청이 192.168.1.2:80으로 보내지면, 세 번째 서버 블록에서 처리됩니다. 이는 세 번째 서버 블록이 해당 IP 주소와 포트에 바인딩되어 있고,
default_server로 설정되어 있기 때문입니다.
위 설정에서 나타난 IP 주소들은 nginx 웹 서버가 요청을 수신을 대기하는 (listen) 네트워크 인터페이스의 IP 주소들입니다.
- 192.168.1.1: 이 IP 주소는 첫 번째와 두 번째 `server 블록에서 사용되고 있습니다. 이 두 블록은 모두 192.168.1.1 IP 주소에서 80 포트로 들어오는 요청을 수신하도록 설정되어 있습니다.
- 192.168.1.2: 이 IP 주소는 세 번째
server블록에서 사용되고 있습니다. 이 블록은 192.168.1.2 IP 주소에서 80 포트로 들어오는 요청을 수신하도록 설정되어 있습니다.
따라서 이 nginx 서버는 192.168.1.1과 192.168.1.2라는 두 개의 IP 주소를 사용하고 있다고 보면 됩니다. 이 두 주소는 서버가 설치된 시스템의 네트워크 인터페이스에 설정된 실제 IP 주소여야 합니다. 그렇지 않으면, 이 IP 주소로 들어오는 요청을 웹 서버가 수신할 수 없습니다.
간단한 PHP 사이트 구성**
이제 일반적이고 간단한 PHP 사이트에 대한 요청을 처리하는 데 nginx가 어떻게 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는 먼저 나열된 순서와 상관없이 리터럴 문자열에 의해 주어진 가장 구체적인 접두사 위치를 찾습니다. 위의 설정에서 유일한 접두사 location은 / 이며, 이는 모든 요청에 일치하므로 마지막 수단으로 사용됩니다.
그런 다음, 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접두사 위치 "/"와만 일치하므로 이 위치에서 처리됩니다.
/data/www/about.html파일에 매핑되고 해당 파일이 클라이언트로 전송됩니다. -
/"/" 요청을 처리하는 것은 더 복잡합니다. 이 요청은 접두사 위치 "/"와만 일치하므로 이 위치에서 처리됩니다. 그런 다음 index 지시어는 매개변수와 "root /data/www" 지시어에 따라 인덱스 파일이 있는지 검사합니다. 데이터/www/index.html 파일이 존재하지 않고 /데이터/www/index.php 파일이 존재하면 지시문은 "/index.php"로 내부 리디렉션을 수행하고 nginx는 요청이 클라이언트에 의해 전송된 것처럼 위치를 다시 검색합니다. 앞서 살펴본 것처럼 리디렉션된 요청은 결국 FastCGI 서버에서 처리됩니다.
- 허용 함수 정리
- 소켓 프로그래밍
- CGI
- 가상 호스트
- NGINX autoindex 동작 정리
- HTTP Request 파싱
- HTTP Request 값 유효성 검사
- Config 파일 Parsing