NGINX Plus

정적 콘텐츠 제공

유형별 root 디렉터리, 파일 존재 확인 및 성능 최적화를 통해 정적 콘텐츠를 제공하도록 NGINX 및 NGINX Plus 를 구성합니다.

이 문서에서는 정적 콘텐츠를 제공하도록 NGINX 및 NGINX Plus 를 구성하는 방법, 요청된 파일을 찾기 위해 검색할 경로를 정의하는 방법, 인덱스 파일을 설정하는 방법, 최적의 성능을 위해 커널뿐만 아니라 NGINX 및 NGINX Plus 를 튜닝하는 방법에 대해 설명합니다.

목차

1. root 디렉터리 및 인덱스 파일
2. 몇 가지 옵션 시도하기
3. 콘텐츠 제공을 위한 성능 최적화
3-1. sendfile 활성화하기
3-2. tcp_nopush 활성화하기
3-3. tcp_nodelay 활성화하기
3-4. Backlog Queue 최적화
3-4-1. Listen Queue 표시하기
3-4-2. 운영 체제 조정하기
3-4-3. NGINX 조정하기

1. root 디렉터리 및 인덱스 파일

root 지시문은 파일을 검색하는 데 사용할 root 디렉터리를 지정합니다. 요청된 파일의 경로를 얻기 위해 NGINX는 root 지시문에 지정된 경로에 요청 URI를 추가합니다. 이 지시문은 http { }, server { } 또는 location { } 컨텍스트 내의 모든 Level에 배치할 수 있습니다. 아래 예제에서 root 지시문은 가상 서버에 대해 정의됩니다. 이 지시문은 root 지시문이 포함되지 않은 모든 location { } 블록에 적용되어 root를 명시적으로 정의합니다.

server {
    root /www/data;

    location / {
    }

    location /images/ {
    }

    location ~ \.(mp3|mp4) {
        root /www/media;
    }
}

여기서 NGINX는 파일 시스템의 /www/data/images/ 디렉터리에서 /images/로 시작하는 URI를 검색합니다. 그러나 URI가 .mp3 또는 .mp4 확장자로 끝나는 경우, NGINX는 일치하는 location 블록에 정의되어 있기 때문에 /www/media/ 디렉터리에서 파일을 검색하는 대신 해당 파일을 찾습니다.

요청이 /(슬래시)로 끝나면 NGINX는 디렉터리에 대한 요청으로 처리하고 디렉터리에서 인덱스 파일을 찾으려고 시도합니다. index 지시문은 인덱스 파일의 이름을 정의합니다(기본값은 index.html). 예제를 계속 진행하기 위해, 요청 URI가 /images/some/path/인 경우 NGINX는 /www/data/images/some/path/index.html 파일이 존재하면 전달합니다. 존재하지 않는 경우 NGINX는 기본적으로 HTTP 코드 404( Not Found)를 반환합니다. 대신 자동으로 생성된 디렉터리 목록을 반환하도록 NGINX를 구성하려면 autoindex 지시문에 on 매개변수를 추가합니다.

location /images/ {
    autoindex on;
}

index 지시문에 둘 이상의 파일명을 나열할 수 있습니다. NGINX는 지정된 순서대로 파일을 검색하여 가장 먼저 찾은 파일을 반환합니다.

location / {
    index index.$geo.html index.htm index.html;
}

여기서 사용되는 $geo 변수는 geo 지시문을 통해 설정된 사용자 정의 변수입니다. 변수 값은 클라이언트의 IP 주소에 따라 달라집니다.

인덱스 파일을 반환하기 위해 NGINX는 인덱스 파일의 존재 여부를 확인한 다음 기본 URI에 인덱스 파일 이름을 추가하여 얻은 URI로 내부 리다이렉션을 수행합니다. 내부 리다이렉션은 위치 검색을 새로 수행하며 다음 예제에서와 같이 다른 위치로 끝날 수 있습니다.

location / {
    root /data;
    index index.html index.php;
}

location ~ \.php {
    fastcgi_pass localhost:8000;
    #...
}

여기서 요청의 URI가 /path/이고 /data/path/index.html은 존재하지 않지만 /data/path/index.php는 존재하는 경우 /path/index.php에 대한 내부 리다이렉션이 두 번째 위치로 매핑됩니다. 따라서 해당 요청이 Proxy됩니다.

2. 몇 가지 옵션 시도하기

try_files 지시문을 사용하여 지정한 파일이나 디렉터리가 있는지 확인하고, 있으면 내부 리다이렉션을 하고, 없으면 지정한 상태 코드를 반환합니다. 예를 들어 요청 URI에 해당하는 파일이 있는지 확인하려면 다음과 같이 try_files 지시문과 $uri 변수를 사용합니다.

server {
    root /www/data;

    location /images/ {
        try_files $uri /images/default.gif;
    }
}

파일은 현재 위치 또는 가상 서버의 컨텍스트에 설정된 root 또는 alias 지시문을 사용하여 처리되는 URI 형식으로 지정됩니다. 이 경우 원본 URI에 해당하는 파일이 존재하지 않으면 NGINX는 마지막 매개변수에 지정된 URI로 내부 리다이렉션을 수행하여 /www/data/images/default.gif를 반환합니다.

마지막 매개변수는 상태 코드(등호 기호 바로 앞에 올 수 있음) 또는 위치 이름일 수도 있습니다. 다음 예제에서는 try_files 지시문의 매개변수 중 어느 것도 기존 파일이나 디렉터리로 확인되지 않으면 404 오류가 반환됩니다.

location / {
    try_files $uri $uri/ $uri.html =404;
}

다음 예제에서는 원본 URI나 끝에 /(슬래시)가 추가된 URI가 모두 기존 파일이나 디렉터리로 확인되지 않으면 요청이 Proxy된 서버로 전달되는 지정된 위치로 리다이렉션됩니다.

location / {
    try_files $uri $uri/ @backend;
}

location @backend {
    proxy_pass http://backend.example.com;
}

3. 콘텐츠 제공을 위한 성능 최적화

로딩 속도는 모든 콘텐츠 제공에 있어 중요한 요소입니다. NGINX 구성을 약간만 최적화하면 생산성을 높이고 최적의 성능에 도달하는 데 도움이 될 수 있습니다.

3-1. sendfile 활성화하기

기본적으로 NGINX는 파일 전송을 자체 처리하고 파일을 보내기 전에 버퍼에 복사합니다. sendfile 지시문을 사용하면 데이터를 버퍼에 복사하는 단계가 없어지고 한 파일 설명자에서 다른 파일 설명자로 데이터를 직접 복사할 수 있습니다. 또는 하나의 빠른 연결이 Worker Process를 완전히 점유하는 것을 방지하려면 sendfile_max_chunk 지시문을 사용하여 단일 sendfile() 호출에서 전송되는 데이터의 양을 제한할 수 있습니다(이 예에서는 1MB로 제한).

3-2. tcp_nopush 활성화하기

tcp_nopush 지시문을 sendfile on; 지시문과 함께 사용합니다. 이렇게 하면 NGINX가 sendfile()로 데이터 Chunk를 가져온 직후 하나의 패킷으로 HTTP 응답 헤더를 전송할 수 있습니다.

location /mp3 {
    sendfile   on;
    tcp_nopush on;
    #...
}

3-3. tcp_nodelay 활성화하기

tcp_nodelay 지시문을 사용하면 원래 느린 네트워크에서 작은 패킷 문제를 해결하기 위해 설계된 Nagle의 알고리즘을 재정의할 수 있습니다. 이 알고리즘은 여러 개의 작은 패킷을 큰 패킷으로 통합하여 200ms의 지연을 두고 패킷을 전송합니다. 요즘에는 대용량 정적 파일을 전송할 때 패킷 크기에 관계없이 데이터를 즉시 전송할 수 있습니다. 지연은 온라인 애플리케이션(ssh, 온라인 게임, 온라인 거래 등)에도 영향을 미칩니다. 기본적으로 tcp_nodelay 지시문은 on으로 설정되어 있는데, 이는 Nagle의 알고리즘이 비활성화되어 있음을 의미합니다. 이 지시문은 Keepalive 연결에만 사용하세요.

location /mp3  {
    tcp_nodelay       on;
    keepalive_timeout 65;
    #...
}

3-4. Backlog Queue 최적화

중요한 요소 중 하나는 NGINX가 들어오는 연결을 얼마나 빨리 처리할 수 있는지입니다. 일반적인 규칙은 연결이 설정되면 수신 소켓의 ” Listen” Queue에 넣는 것입니다. 정상적인 부하에서는 Queue가 작거나 Queue가 전혀 없습니다. 그러나 부하가 높으면 Queue가 급격히 증가하여 성능이 고르지 않고 연결이 끊기며 대기 시간이 늘어날 수 있습니다.

3-4-1. Listen Queue 표시하기

현재 Listen Queue을 표시하려면 다음 명령을 실행합니다.

netstat -Lan

출력은 다음과 같을 수 있으며, 포트 80의 Listen Queue에 구성된 최대 Queue 연결 128개에 대해 수락되지 않은 연결이 10개 있음을 보여 줍니다. 이 상태는 정상입니다.

Current listen queue sizes (qlen/incqlen/maxqlen)
Listen         Local Address         
0/0/128        *.12345            
10/0/128        *.80       
0/0/128        *.8080

반대로 다음 명령에서는 허용되지 않은 연결 수(192개)가 제한인 128개를 초과합니다. 이는 웹 사이트에 트래픽이 많을 때 매우 흔한 현상입니다. 최적의 성능을 얻으려면 운영 체제와 NGINX 구성 모두에서 NGINX가 수락을 위해 대기할 수 있는 최대 연결 수를 늘려야 합니다.

Current listen queue sizes (qlen/incqlen/maxqlen)
Listen         Local Address         
0/0/128        *.12345            
192/0/128        *.80       
0/0/128        *.8080

3-4-2. 운영 체제 조정하기

net.core.somaxconn 커널 매개변수의 값을 기본값(128)에서 트래픽이 폭주할 수 있을 만큼 높은 값으로 늘립니다. 이 예에서는 4096으로 증가시켰습니다.

FreeBSD의 경우 다음 명령을 실행합니다.

sudo sysctl kern.ipc.somaxconn=4096

리눅스의 경우.

1. 다음 명령을 실행합니다.

sudo sysctl -w net.core.somaxconn=4096

2. 텍스트 편집기를 사용하여 /etc/sysctl.conf에 다음 줄을 추가합니다.

net.core.somaxconn = 4096

3-4-3. NGINX 조정하기

somaxconn 커널 매개변수를 512보다 큰 값으로 설정한 경우, backlog 매개변수를 NGINX listen 지시문으로 변경하여 일치하도록 합니다.

server {
    listen 80 backlog=4096;
    # ...
}