웹사이트 검색

Nginx에서 FastCGI 프록시 이해 및 구현


소개

Nginx는 가장 유연하고 강력한 웹 서버 솔루션 중 하나가 되었습니다. 그러나 디자인 측면에서 가장 먼저 프록시 서버입니다. 이 초점은 다른 서버와의 요청을 처리하기 위해 작업할 때 Nginx가 매우 성능이 좋다는 것을 의미합니다.

Nginx는 http, FastCGI, uwsgi, SCGI 또는 memcached를 사용하여 요청을 프록시할 수 있습니다. 이 가이드에서는 가장 일반적인 프록싱 프로토콜 중 하나인 FastCGI 프록싱에 대해 설명합니다.

FastCGI 프록싱을 사용하는 이유는 무엇입니까?

Nginx 내의 FastCGI 프록시는 일반적으로 클라이언트 요청을 직접 처리하지 않거나 처리해서는 안 되는 애플리케이션 서버에 대한 클라이언트 요청을 변환하는 데 사용됩니다. FastCGI는 각 요청을 별도의 프로세스로 실행하지 않음으로써 성능을 향상시키기 위한 프로토콜인 이전 CGI 또는 공통 게이트웨이 인터페이스를 기반으로 하는 프로토콜입니다. 동적 콘텐츠에 대한 요청을 처리하는 서버와 효율적으로 인터페이스하기 위해 사용됩니다.

Nginx 내에서 FastCGI 프록시의 주요 사용 사례 중 하나는 PHP 처리입니다. mod_php 모듈을 사용하여 직접 PHP 처리를 처리할 수 있는 Apache와 달리 Nginx는 PHP 요청을 처리하기 위해 별도의 PHP 프로세서에 의존해야 합니다. 대부분의 경우 이 처리는 Nginx와 함께 작동하도록 광범위하게 테스트된 PHP 프로세서인 php-fpm으로 처리됩니다.

FastCGI가 포함된 Nginx는 FastCGI 요청에 응답하도록 구성된 액세스 가능한 구성 요소가 있는 한 다른 언어를 사용하는 애플리케이션과 함께 사용할 수 있습니다.

FastCGI 프록시 기본 사항

일반적으로 프록시 요청에는 클라이언트의 요청을 백엔드 서버로 전달하는 프록시 서버(이 경우 Nginx)가 포함됩니다. Nginx가 FastCGI 프로토콜을 사용하여 프록시할 실제 서버를 정의하는 데 사용하는 지시문은 fastcgi_pass입니다.

예를 들어 FastCGI 프로토콜을 사용하여 PHP 처리를 처리하는 백엔드로 PHP에 대한 일치하는 요청을 전달하려면 기본 위치 블록이 다음과 같을 수 있습니다.

# server context

location ~ \.php$ {
    fastcgi_pass 127.0.0.1:9000;
}

. . .

위의 스니펫은 정보가 너무 적기 때문에 실제로 즉시 작동하지 않습니다. 프록시 연결이 설정될 때마다 원래 요청을 변환하여 프록시 요청이 백엔드 서버에 의미가 있는지 확인해야 합니다. FastCGI 패스로 프로토콜을 변경하고 있으므로 여기에는 몇 가지 추가 작업이 필요합니다.

http-to-http 프록시는 백엔드가 클라이언트를 대신하여 프록시 서버에 응답하는 데 필요한 정보를 갖도록 하기 위해 주로 http 헤더를 보강하는 것과 관련되지만 FastCGI는 http 헤더를 읽을 수 없는 별도의 프로토콜입니다. 이러한 고려 사항으로 인해 모든 관련 정보는 다른 수단을 통해 백엔드로 전달되어야 합니다.

FastCGI 프로토콜을 사용할 때 추가 정보를 전달하는 기본 방법은 매개변수를 사용하는 것입니다. 백그라운드 서버는 이를 읽고 처리하도록 구성되어 발견한 내용에 따라 동작을 수정해야 합니다. Nginx는 fastcgi_param 지시문을 사용하여 FastCGI 매개변수를 설정할 수 있습니다.

PHP용 FastCGI 프록시 시나리오에서 실제로 작동하는 최소한의 구성은 다음과 같습니다.

# server context

location ~ \.php$ {
    fastcgi_param REQUEST_METHOD $request_method;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    fastcgi_pass 127.0.0.1:9000;
}

. . .

위의 구성에서 REQUEST_METHODSCRIPT_FILENAME이라는 두 개의 FastCGI 매개변수를 설정했습니다. 백엔드 서버가 요청의 특성을 이해하려면 둘 다 필요합니다. 전자는 수행해야 하는 작업 유형을 알려주고 후자는 실행할 파일을 업스트림에 알려줍니다.

예제에서는 일부 Nginx 변수를 사용하여 이러한 매개변수의 값을 설정했습니다. $request_method 변수는 항상 클라이언트가 요청한 http 메서드를 포함합니다.

SCRIPT_FILENAME 매개변수는 $document_root 변수와 $fastcgi_script_name 변수의 조합으로 설정됩니다. $document_rootroot 지시문에 의해 설정된 대로 기본 디렉토리에 대한 경로를 포함합니다. $fastcgi_script_name 변수는 요청 URI로 설정됩니다. 요청 URI가 슬래시(/)로 끝나는 경우 fastcgi_index 지시문의 값이 끝에 추가됩니다. 이러한 유형의 자체 참조 위치 정의는 Nginx 인스턴스와 동일한 시스템에서 FastCGI 프로세서를 실행하고 있기 때문에 가능합니다.

다른 예를 살펴보겠습니다.

# server context
root /var/www/html;

location /scripts {
    fastcgi_param REQUEST_METHOD $request_method;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    fastcgi_index index.php;
    fastcgi_pass unix:/var/run/php5-fpm.sock;
}

. . .

/scripts/test/에 대한 요청을 처리하기 위해 위의 위치를 선택한 경우 SCRIPT_FILENAME의 값은 root 지시어, 요청 URI 및 fastcgi_index 지시어. 이 예에서 매개변수는 /var/www/html/scripts/test/index.php로 설정됩니다.

네트워크 소켓 대신 Unix 소켓을 사용하여 FastCGI 백엔드를 지정했다는 점에서 위의 구성에서 또 다른 중요한 변경 사항을 적용했습니다. Nginx는 두 가지 유형의 인터페이스를 사용하여 FastCGI 업스트림에 연결할 수 있습니다. FastCGI 프로세서가 동일한 호스트에 있는 경우 일반적으로 보안을 위해 Unix 소켓이 권장됩니다.

FastCGI 구성 해제

유지 관리 가능한 코드의 핵심 규칙은 DRY("반복하지 마십시오\) 원칙을 따르려고 노력하는 것입니다. 이렇게 하면 오류를 줄이고 재사용 가능성을 높이며 더 나은 구성을 허용할 수 있습니다. Nginx 관리를 위한 핵심 권장 사항 중 하나는 다음과 같습니다. 항상 가장 광범위한 적용 범위에서 지시문을 설정하기 위해 이러한 기본 목표는 Nginx 구성에도 적용됩니다.

FastCGI 프록시 구성을 처리할 때 대부분의 사용 인스턴스는 대부분의 구성을 공유합니다. 이 때문에 그리고 Nginx 상속 모델이 작동하는 방식 때문에 일반 범위에서 매개변수를 선언하는 것이 거의 항상 유리합니다.

상위 컨텍스트에서 FastCGI 구성 세부 정보 선언

반복을 줄이는 한 가지 방법은 상위 상위 컨텍스트에서 구성 세부 정보를 선언하는 것입니다. 실제 fastcgi_pass 외부의 모든 매개변수는 더 높은 수준에서 지정할 수 있습니다. 패스가 발생하는 위치로 아래로 캐스케이드됩니다. 이는 여러 위치에서 동일한 구성을 사용할 수 있음을 의미합니다.

예를 들어 위 섹션의 마지막 구성 스니펫을 수정하여 둘 이상의 위치에서 유용하게 만들 수 있습니다.

# server context
root /var/www/html;

fastcgi_param REQUEST_METHOD $request_method;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_index index.php;

location /scripts {
    fastcgi_pass unix:/var/run/php5-fpm.sock;
}

location ~ \.php$ {
    fastcgi_pass 127.0.0.1:9000;
}

. . .

위의 예에서 fastcgi_param 선언과 fastcgi_index 지시어는 모두 다음에 오는 위치 블록 모두에서 사용할 수 있습니다. 이것은 반복적인 선언을 제거하는 한 가지 방법입니다.

그러나 위의 구성에는 한 가지 심각한 단점이 있습니다. 하위 컨텍스트에서 fastcgi_param이 선언되면 상위 컨텍스트의 fastcgi_param 값이 아무것도 상속되지 않습니다. 상속된 값 사용하거나 전혀 사용하지 않습니다.

fastcgi_param 지시문은 Nginx 용어로 배열 지시문입니다. 사용자 관점에서 배열 지시문은 기본적으로 단일 컨텍스트에서 두 번 이상 사용할 수 있는 모든 지시문입니다. 각 후속 선언은 Nginx가 이전 선언에서 알고 있는 내용에 새 정보를 추가합니다. fastcgi_param 지시문은 사용자가 여러 매개변수를 설정할 수 있도록 배열 지시문으로 설계되었습니다.

배열 지시문은 다른 지시문과 다른 방식으로 자식 컨텍스트를 상속합니다. 배열 지시문의 정보는 하위 컨텍스트의 어느 위치에도 존재하지 않는 경우에만 하위 컨텍스트로 상속됩니다. 즉, 위치 내에서 fastcgi_param을 사용하면 상위 컨텍스트에서 상속된 값을 효과적으로 완전히 지울 수 있습니다.

예를 들어 위의 구성을 약간 수정할 수 있습니다.

# server context
root /var/www/html;

fastcgi_param REQUEST_METHOD $request_method;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_index index.php;

location /scripts {
    fastcgi_pass unix:/var/run/php5-fpm.sock;
}

location ~ \.php$ {
    fastcgi_param QUERY_STRING $query_string;
    fastcgi_pass 127.0.0.1:9000;
}

. . .

언뜻 보기에 REQUEST_METHODSCRIPT_FILENAME 매개변수가 두 번째 위치 블록으로 상속되고 QUERY_STRING 매개변수가 추가로 사용 가능하다고 생각할 수 있습니다. 해당 특정 컨텍스트에 대해.

실제로 발생하는 것은 모든 상위 fastcgi_param 값이 두 번째 컨텍스트에서 지워지고 QUERY_STRING 매개변수만 설정된다는 것입니다. REQUEST_METHODSCRIPT_FILENAME 매개변수는 설정되지 않은 상태로 유지됩니다.

동일한 컨텍스트의 매개변수에 대한 다중 값에 대한 참고 사항

이 시점에서 확실히 언급할 가치가 있는 한 가지는 단일 컨텍스트 내에서 동일한 매개 변수에 대해 여러 값을 설정하는 것의 의미입니다. 논의 포인트로 다음 예를 들어 보겠습니다.

# server context

location ~ \.php$ {
    fastcgi_param REQUEST_METHOD $request_method;
    fastcgi_param SCRIPT_FILENAME $request_uri;

    fastcgi_param DOCUMENT_ROOT initial;
    fastcgi_param DOCUMENT_ROOT override;

    fastcgi_param TEST one;
    fastcgi_param TEST two;
    fastcgi_param TEST three;

    fastcgi_pass 127.0.0.1:9000;
}

. . .

위의 예에서는 단일 컨텍스트 내에서 TESTDOCUMENT_ROOT 매개변수를 여러 번 설정했습니다. fastcgi_param은 배열 지시문이므로 각 후속 선언은 Nginx의 내부 레코드에 추가됩니다. TEST 매개변수는 one, twothree로 설정하는 배열의 선언을 포함합니다.

이 시점에서 깨달아야 할 중요한 점은 Nginx에서 더 이상 처리하지 않고 이 모든 것이 FastCGI 백엔드로 전달된다는 것입니다. 즉, 이러한 값을 처리하는 방법을 결정하는 것은 전적으로 선택한 FastCGI 프로세서에 달려 있습니다. 불행히도 다른 FastCGI 프로세서는 전달된 값을 완전히 다르게 처리합니다.

예를 들어 위의 매개변수가 PHP-FPM에 의해 수신된 경우 최종 값은 이전 값을 무시하도록 해석됩니다. 따라서 이 경우 TEST 매개변수는 three로 설정됩니다. 마찬가지로 DOCUMENT_ROOT 매개변수는 override로 설정됩니다.

그러나 위의 값을 FsgiWrap과 같은 것으로 전달하면 값이 매우 다르게 해석됩니다. 먼저 스크립트를 실행하는 데 사용할 값을 결정하기 위한 초기 단계를 만듭니다. initialDOCUMENT_ROOT 값을 사용하여 스크립트를 찾습니다. 그러나 스크립트에 실제 매개 변수를 전달할 때 PHP-FPM과 마찬가지로 최종 값을 전달합니다.

이러한 불일치와 예측 불가능성은 동일한 매개변수를 두 번 이상 설정할 때 의도를 올바르게 해석하기 위해 백엔드에 의존할 수 없고 의존해서는 안 된다는 것을 의미합니다. 안전한 유일한 해결책은 각 매개변수를 한 번만 선언하는 것입니다. 이것은 또한 fastcgi_param 지시어로 기본값을 안전하게 재정의하는 것과 같은 것이 없다는 것을 의미합니다.

Include를 사용하여 별도의 파일에서 FastCGI 구성 소싱

공통 구성 항목을 분리하는 또 다른 방법이 있습니다. include 지시문을 사용하여 별도 파일의 내용을 지시문 선언 위치로 읽을 수 있습니다.

즉, 모든 공통 구성 항목을 단일 파일에 보관하고 필요한 구성의 모든 위치에 포함할 수 있습니다. Nginx는 include가 호출되는 곳에 실제 파일 내용을 배치하므로 상위 컨텍스트에서 하위 컨텍스트로 상속되지 않습니다. 이렇게 하면 fastcgi_param 값이 지워지는 것을 방지하여 필요에 따라 추가 매개변수를 설정할 수 있습니다.

먼저 구성 디렉토리의 별도 파일에서 공통 FastCGI 구성 값을 설정할 수 있습니다. 우리는 이 파일을 fastcgi_common이라고 부를 것입니다:

fastcgi_param REQUEST_METHOD $request_method;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;

이제 해당 구성 값을 사용하려는 모든 위치에서 이 파일을 읽을 수 있습니다.

# server context
root /var/www/html;

location /scripts {
    include fastcgi_common;

    fastcgi_index index.php;
    fastcgi_pass unix:/var/run/php5-fpm.sock;
}

location ~ \.php$ {
    include fastcgi_common;
    fastcgi_param QUERY_STRING $query_string;
    fastcgi_param CONTENT_TYPE $content_type;
    fastcgi_param CONTENT_LENGTH $content_length;

    fastcgi_index index.php;
    fastcgi_pass 127.0.0.1:9000;
}

. . .

여기에서 일부 일반적인 fastcgi_param 값을 기본 Nginx 구성 디렉토리에 있는 fastcgi_common이라는 파일로 옮겼습니다. 그런 다음 내부에 선언된 값을 삽입하려는 경우 해당 파일을 소싱합니다.

이 구성에 대해 몇 가지 유의할 사항이 있습니다.

첫 번째는 소싱하려는 파일의 위치별로 사용자 지정하려는 값을 배치하지 않았다는 것입니다. 동일한 매개변수에 대해 여러 값을 설정할 때 발생하는 위에서 언급한 해석 문제와 배열이 아닌 지시문은 컨텍스트당 한 번만 설정할 수 있기 때문에 항목을 변경하지 않으려는 공통 파일에만 배치하십시오. 컨텍스트별로 사용자 지정하려는 모든 지시문(또는 매개 변수 키)은 공통 파일에서 제외해야 합니다.

두 번째 위치 블록에 일부 추가 FastCGI 매개변수를 설정했다는 점을 눈치채셨을 수도 있습니다. 이것이 우리가 달성하고자 했던 능력입니다. 공통 값을 삭제하지 않고 필요에 따라 추가 fastcgi_param 매개변수를 설정할 수 있었습니다.

fastcgi_params 파일 또는 fastcgi.conf 파일 사용

위의 전략을 염두에 두고 Nginx 개발자와 많은 배포 패키징 팀은 FastCGI 패스 위치에 포함할 수 있는 정상적인 공통 매개변수 세트를 제공하기 위해 노력했습니다. 이를 fastcgi_params 또는 fastcgi.conf라고 합니다.

이 두 파일은 대체로 동일하며 실제로 유일한 차이점은 이전에 단일 매개변수에 대해 여러 값을 전달하는 것에 대해 논의한 문제의 결과입니다. fastcgi_params 파일에는 SCRIPT_FILENAME 매개변수에 대한 선언이 없지만 fastcgi.conf 파일에는 있습니다.

fastcgi_params 파일은 훨씬 더 오랫동안 사용할 수 있었습니다. fastcgi_params에 의존하는 구성이 손상되지 않도록 하려면 SCRIPT_FILENAME에 대한 기본값을 제공하기로 결정했을 때 새 파일을 만들어야 했습니다. 그렇게 하지 않으면 해당 매개변수가 공통 파일과 FastCGI 패스 위치 모두에 설정될 수 있습니다. 이 두 파일의 역사에 대한 Martin Fjordvald의 뛰어난 게시물에 자세히 설명되어 있습니다.

널리 사용되는 배포판의 많은 패키지 관리자는 이러한 파일 중 하나만 포함하거나 콘텐츠를 정확히 미러링하도록 선택했습니다. 이 중 하나만 사용할 수 있는 경우 가지고 있는 것을 사용하십시오. 필요에 맞게 자유롭게 수정하십시오.

이 두 파일을 모두 사용할 수 있는 경우 대부분의 FastCGI 패스 위치에 대해 SCRIPT_FILENAMEfastcgi.conf 파일을 포함하는 것이 좋습니다. > 매개변수. 이는 일반적으로 바람직하지만 이 값을 사용자 지정하려는 경우가 있습니다.

이들은 루트 Nginx 구성 디렉토리에 상대적인 위치를 참조하여 포함될 수 있습니다. Nginx가 패키지 관리자와 함께 설치된 경우 루트 Nginx 구성 디렉토리는 일반적으로 /etc/nginx와 같습니다.

다음과 같은 파일을 포함할 수 있습니다.

# server context

location ~ \.php$ {
    include fastcgi_params;
    # You would use "fastcgi_param SCRIPT_FILENAME . . ." here afterwards
    
    . . .

}

또는 다음과 같이:

# server context

location ~ \.php$ {
    include fastcgi.conf;

    . . .

}

중요한 FastCGI 지시문, 매개변수 및 변수

위 섹션에서는 다른 개념을 설명하기 위한 수단으로 Nginx 변수에 상당한 수의 매개변수를 설정했습니다. 너무 많은 설명 없이 일부 FastCGI 지시문도 도입했습니다. 이 섹션에서는 설정해야 할 몇 가지 일반적인 지시문, 수정해야 할 수 있는 매개변수 및 필요한 정보를 포함할 수 있는 일부 변수에 대해 설명합니다.

일반 FastCGI 지시문

다음은 FastCGI 패스 작업에 가장 유용한 지시문 중 일부를 나타냅니다.

  • fastcgi_pass: 현재 컨텍스트의 요청을 백엔드로 전달하는 실제 지시어입니다. 이는 FastCGI 프로세서에 도달할 수 있는 위치를 정의합니다.
  • fastcgi_param: 매개변수를 값으로 설정하는 데 사용할 수 있는 배열 지시문입니다. 대부분 Nginx 변수와 함께 FastCGI 매개변수를 요청에 특정한 값으로 설정하는 데 사용됩니다.
  • try_files: FastCGI 관련 지시문이 아니라 FastCGI 전달 위치 내에서 사용되는 공통 지시문입니다. 이는 FastCGI 프로세서로 전달하기 전에 요청된 파일이 존재하는지 확인하기 위해 요청 삭제 루틴의 일부로 자주 사용됩니다.
  • include: 다시 말하지만 FastCGI 관련 지시문은 아니지만 FastCGI 전달 컨텍스트에서 많이 사용되는 지시어입니다. 대부분의 경우 이것은 여러 위치에서 공통의 공유 구성 세부 정보를 포함하는 데 사용됩니다.
  • fastcgi_split_path_info: 이 지시문은 두 개의 캡처된 그룹이 있는 정규식을 정의합니다. 첫 번째 캡처된 그룹은 $fastcgi_script_name 변수의 값으로 사용됩니다. 두 번째 캡처된 그룹은 $fastcgi_path_info 변수의 값으로 사용됩니다. 두 가지 모두 요청을 올바르게 구문 분석하는 데 자주 사용되므로 프로세서는 요청의 어떤 부분이 실행할 파일이고 어떤 부분이 스크립트에 전달할 추가 정보인지 알 수 있습니다.
  • fastcgi_index: 이것은 슬래시(/)로 끝나는 $fastcgi_script_name 값에 추가되어야 하는 색인 파일을 정의합니다. 이는 SCRIPT_FILENAME 매개변수가 $document_root$fastcgi_script_name로 설정되고 위치 블록이 파일 뒤에 정보가 있는 요청을 수락하도록 구성된 경우에 종종 유용합니다.
  • fastcgi_intercept_errors: 이 지시문은 FastCGI 서버에서 받은 오류를 Nginx에서 처리할지 아니면 클라이언트에 직접 전달해야 하는지를 정의합니다.

위의 지시문은 일반적인 FastCGI 패스를 디자인할 때 사용할 대부분의 항목을 나타냅니다. 이 모든 것을 항상 사용하지는 않을 수 있지만 다음에 설명할 FastCGI 매개 변수 및 변수와 매우 밀접하게 상호 작용하는 것을 볼 수 있습니다.

FastCGI와 함께 사용되는 공통 변수

FastCGI 패스와 함께 사용할 가능성이 있는 매개변수에 대해 이야기하기 전에 이러한 매개변수를 설정할 때 활용할 몇 가지 일반적인 Nginx 변수에 대해 조금 이야기해야 합니다. 이들 중 일부는 Nginx의 FastCGI 모듈에 의해 정의되지만 대부분은 Core 모듈에서 가져옵니다.

  • $query_string 또는 $args: 원래 클라이언트 요청에 제공된 인수입니다.
  • $is_args: \?”와 같음 요청에 인수가 있는 경우 그렇지 않으면 빈 문자열로 설정됩니다. 이는 인수가 있거나 없을 수 있는 매개변수를 구성할 때 유용합니다.
  • $request_method: 원래 클라이언트 요청 방법을 나타냅니다. 이는 현재 컨텍스트 내에서 작업을 허용할지 여부를 결정하는 데 유용할 수 있습니다.
  • $content_type: Content-Type 요청 헤더로 설정됩니다. 사용자의 요청이 POST인 경우 후속 콘텐츠를 올바르게 처리하기 위해 프록시에서 이 정보가 필요합니다.
  • $content_length: 클라이언트의 Content-Length 헤더 값으로 설정됩니다. 이 정보는 모든 클라이언트 POST 요청에 필요합니다.
  • $fastcgi_script_name: 실행할 스크립트 파일이 포함됩니다. 요청이 슬래시(/)로 끝나는 경우 fastcgi_index 지시문의 값이 끝에 추가됩니다. fastcgi_split_path_info 지시문이 사용되는 경우 이 변수는 해당 지시문에 의해 정의된 첫 번째 캡처된 그룹으로 설정됩니다. 이 변수의 값은 실행할 실제 스크립트를 나타내야 합니다.
  • $request_filename: 이 변수에는 요청된 파일의 파일 경로가 포함됩니다. rootalias 지시문과 $fastcgi_script_name 의 값을 모두 고려하여 현재 문서 루트의 값을 취하여 이 값을 가져옵니다. . 이것은 SCRIPT_FILENAME 매개변수를 할당하는 매우 유연한 방법입니다.
  • $request_uri: 클라이언트로부터 받은 전체 요청입니다. 여기에는 스크립트, 추가 경로 정보 및 쿼리 문자열이 포함됩니다.
  • $fastcgi_path_info: 이 변수에는 요청의 스크립트 이름 뒤에 사용할 수 있는 추가 경로 정보가 포함되어 있습니다. 이 값에는 실행할 스크립트가 알아야 하는 다른 위치가 포함되는 경우가 있습니다. 이 변수는 fastcgi_split_path_info 지시문을 사용할 때 두 번째 캡처된 정규식 그룹에서 값을 가져옵니다.
  • $document_root: 이 변수는 현재 문서 루트 값을 포함합니다. 이것은 root 또는 alias 지시문에 따라 설정됩니다.
  • $uri: 이 변수에는 정규화가 적용된 현재 URI가 포함됩니다. 다시 작성하거나 내부적으로 리디렉션하는 특정 지시문은 URI에 영향을 미칠 수 있으므로 이 변수는 이러한 변경 사항을 나타냅니다.

보시다시피 FastCGI 매개변수를 설정하는 방법을 결정할 때 사용할 수 있는 변수가 상당히 많습니다. 이들 중 많은 부분이 유사하지만 스크립트 실행에 영향을 미치는 몇 가지 미묘한 차이점이 있습니다.

일반 FastCGI 매개변수

FastCGI 매개변수는 요청을 보내는 FastCGI 프로세서에서 사용할 수 있게 하려는 키-값 정보를 나타냅니다. 모든 애플리케이션에 동일한 매개변수가 필요한 것은 아니므로 종종 앱 설명서를 참조해야 합니다.

이러한 매개변수 중 일부는 프로세서가 실행할 스크립트를 올바르게 식별하는 데 필요합니다. 다른 것들은 스크립트에서 사용할 수 있으며 설정된 매개변수에 의존하도록 구성된 경우 동작을 수정할 수 있습니다.

  • QUERY_STRING: 이 매개변수는 클라이언트가 제공하는 쿼리 문자열로 설정해야 합니다. 이것은 일반적으로 \?” 다음에 제공되는 키-값 쌍입니다. 일반적으로 이 매개변수는 $query_string 또는 $args 변수로 설정되며 둘 다 동일한 데이터를 포함해야 합니다.
  • REQUEST_METHOD: 이 매개변수는 클라이언트가 요청한 작업 유형을 FastCGI 프로세서에 나타냅니다. 이는 패스가 올바르게 작동하기 위해 설정해야 하는 몇 가지 매개변수 중 하나입니다.
  • CONTENT_TYPE: 위에서 설정한 요청 방법이 "POST\인 경우 이 매개변수를 설정해야 합니다. FastCGI 프로세서가 예상해야 하는 콘텐츠 유형을 나타냅니다. 거의 항상 다음과 같이 설정됩니다. 원래 요청의 정보에 따라 설정되는 $content_type 변수
  • CONTENT_LENGTH: 요청 방법이 "POST\인 경우 이 매개변수를 설정해야 합니다. 콘텐츠 길이를 나타냅니다. 거의 항상 $content_length로 설정됩니다. , 원래 클라이언트 요청의 정보에서 값을 가져오는 변수입니다.
  • SCRIPT_NAME: 이 매개변수는 실행될 기본 스크립트의 이름을 나타내는 데 사용됩니다. 이것은 필요에 따라 다양한 방법으로 설정할 수 있는 매우 중요한 매개변수입니다. 종종 이것은 $fastcgi_script_name으로 설정되며, 이는 요청 URI, 슬래시로 끝나는 경우 fastcgi_index가 추가된 요청 URI, 또는 첫 번째 캡처된 그룹인 경우 fastcgi_fix_path_info를 사용합니다.
  • SCRIPT_FILENAME: 이 매개변수는 디스크에서 실행할 스크립트의 실제 위치를 지정합니다. SCRIPT_NAME 매개변수와의 관계로 인해 일부 가이드에서는 $document_root$fastcgi_script_name을 사용하도록 제안합니다. 많은 장점이 있는 또 다른 대안은 $request_filename을 사용하는 것입니다.
  • REQUEST_URI: 여기에는 실행할 스크립트, 추가 경로 정보 및 모든 인수가 포함된 수정되지 않은 전체 요청 URI가 포함되어야 합니다. 일부 애플리케이션은 이 정보 자체를 구문 분석하는 것을 선호합니다. 이 매개변수는 이를 수행하는 데 필요한 정보를 제공합니다.
  • PATH_INFO: PHP 구성 파일에서 cgi.fix_pathinfo가 "1”로 설정되어 있으면 스크립트 이름 뒤에 추가되는 추가 경로 정보가 포함됩니다. 이 스크립트가 작동해야 하는 파일 인수를 정의하는 데 자주 사용됩니다. cgi.fix_pathinfo를 "1”로 설정하면 스크립트 요청이 다른 방법을 통해 삭제되지 않는 경우 보안에 영향을 미칠 수 있습니다(이에 대해서는 나중에 설명하겠습니다. 나중에). 때때로 이것은 fastcgi_split_path_info 지시문에서 두 번째 캡처된 그룹을 포함하는 $fastcgi_path_info 변수로 설정됩니다. 다른 경우에는 임시 변수를 사용해야 합니다. 그 값은 때때로 다른 처리에 의해 손상되기 때문입니다.
  • PATH_TRANSLATED: 이 매개변수는 PATH_INFO에 포함된 경로 정보를 실제 파일 시스템 경로로 매핑합니다. 일반적으로 이 값은 $document_root$fastcgi_path_info와 같이 설정되지만 때로는 위에 표시된 대로 나중에 변수를 임시 저장된 변수로 대체해야 합니다.

FastCGI로 전달하기 전에 요청 확인

아직 다루지 않은 매우 중요한 주제 중 하나는 애플리케이션 서버에 동적 요청을 안전하게 전달하는 방법입니다. 유효성에 관계없이 백엔드 애플리케이션에 모든 요청을 전달하는 것은 비효율적일 뿐만 아니라 위험합니다. 공격자가 서버에서 임의 코드를 실행하도록 하기 위해 악의적인 요청을 만들 수 있습니다.

이 문제를 해결하려면 FastCGI 프로세서에 합법적인 요청만 보내고 있는지 확인해야 합니다. 특정 설정의 요구 사항과 FastCGI 프로세서가 Nginx 인스턴스와 동일한 시스템에 있는지 여부에 따라 다양한 방법으로 이 작업을 수행할 수 있습니다.

구성을 설계하는 방법을 알려주는 기본 규칙 중 하나는 사용자 파일의 처리 및 해석을 허용해서는 안 된다는 것입니다. 악의적인 사용자가 이미지와 같이 무해해 보이는 파일에 유효한 코드를 삽입하는 것은 상대적으로 쉽습니다. 이와 같은 파일이 서버에 업로드되면 FastCGI 프로세서에 절대 전달되지 않도록 해야 합니다.

여기서 해결하려는 주요 문제는 실제로 CGI 사양에 지정된 문제입니다. 사양을 사용하면 실행할 스크립트 파일을 지정한 다음 스크립트에서 사용할 수 있는 추가 경로 정보를 지정할 수 있습니다. 이 실행 모델을 통해 사용자는 합법적인 스크립트처럼 보일 수 있는 URI를 요청할 수 있으며 실행될 실제 부분은 경로의 앞부분에 있습니다.

/test.jpg/index.php에 대한 요청을 고려하십시오. 구성이 적법성을 테스트하지 않고 단순히 .php로 끝나는 모든 요청을 프로세서에 전달하는 경우 프로세서는 사양을 따르는 경우 해당 위치를 확인하고 가능한 경우 실행합니다. 파일을 찾지 못하면 사양을 따라 /test.jpg 파일 실행을 시도하고 /index.php 를 표시합니다. 스크립트에 대한 추가 경로 정보로. 보시다시피 이것은 사용자 업로드 아이디어와 결합될 때 매우 바람직하지 않은 결과를 허용할 수 있습니다.

이 문제를 해결하는 방법에는 여러 가지가 있습니다. 애플리케이션이 처리를 위해 이 추가 경로 정보에 의존하지 않는 경우 가장 쉬운 방법은 프로세서에서 간단히 끄는 것입니다. PHP-FPM의 경우 php.ini 파일에서 이 기능을 끌 수 있습니다. 예를 들어 Ubuntu 시스템에서 다음 파일을 편집할 수 있습니다.

sudo nano /etc/php5/fpm/php.ini

cgi.fix_pathinfo 옵션을 검색하고 주석을 제거한 다음 "0\으로 설정하여 이 "기능\을 비활성화하십시오:

cgi.fix_pathinfo=0

변경하려면 PHP-FPM 프로세스를 다시 시작하십시오.

sudo service php5-fpm restart

이로 인해 PHP는 경로의 마지막 구성 요소에서만 실행을 시도합니다. 따라서 위의 예에서 /test.jpg/index.php 파일이 존재하지 않으면 PHP는 /test.jpg를 실행하는 대신 올바르게 오류를 발생시킵니다.

또 다른 옵션은 FastCGI 프로세서가 Nginx 인스턴스와 동일한 시스템에 있는 경우 파일을 프로세서에 전달하기 전에 디스크에 파일이 있는지 간단히 확인하는 것입니다. /test.jgp/index.php 파일이 존재하지 않으면 오류가 발생합니다. 그렇다면 처리를 위해 백엔드로 보내십시오. 이것은 실제로 위와 같은 동작을 많이 초래합니다.

location ~ \.php$ {
        try_files $uri =404;

        . . .

}

애플리케이션이 올바른 해석을 위해 경로 정보 동작에 의존하는 경우 백엔드로 요청을 보낼지 여부를 결정하기 전에 검사를 수행하여 이 동작을 안전하게 허용할 수 있습니다.

예를 들어 신뢰할 수 없는 업로드를 허용하는 디렉터리를 구체적으로 일치시키고 해당 업로드가 프로세서에 전달되지 않도록 할 수 있습니다. 예를 들어 애플리케이션의 업로드 디렉터리가 /uploads/인 경우 정규 표현식이 평가되기 전에 일치하는 다음과 같은 위치 블록을 만들 수 있습니다.

location ^~ /uploads {
}

내부에서 PHP 파일에 대한 모든 종류의 처리를 비활성화할 수 있습니다.

location ^~ /uploads {
    location ~* \.php$ { return 403; }
}

상위 위치는 /uploads로 시작하는 모든 요청과 일치하며 PHP 파일을 다루는 모든 요청은 백엔드로 보내는 대신 403 오류를 반환합니다.

또한 fastcgi_split_path_info 지시문을 사용하여 스크립트로 해석되어야 하는 요청 부분과 정규식을 사용하여 추가 경로 정보로 정의되어야 하는 부분을 수동으로 정의할 수 있습니다. 이를 통해 여전히 경로 정보 기능에 의존할 수 있지만 스크립트로 간주하는 것과 경로로 간주하는 것을 정확하게 정의할 수 있습니다.

예를 들어 .php로 끝나는 경로 구성 요소의 첫 번째 인스턴스를 실행할 스크립트로 간주하는 위치 블록을 설정할 수 있습니다. 나머지는 추가 경로 정보로 간주됩니다. 이는 /test.jpg/index.php에 대한 요청 인스턴스에서 전체 경로가 추가 경로 정보 없이 스크립트 이름으로 프로세서에 전송될 수 있음을 의미합니다.

이 위치는 다음과 같을 수 있습니다.

location ~ [^/]\.php(/|$) {

    fastcgi_split_path_info ^(.+?\.php)(.*)$;
    set $orig_path $fastcgi_path_info;

    try_files $fastcgi_script_name =404;

    fastcgi_pass unix:/var/run/php5-fpm.sock;
    fastcgi_index index.php;
    include fastcgi_params;

    fastcgi_param SCRIPT_FILENAME $request_filename;
    fastcgi_param PATH_INFO $orig_path;
    fastcgi_param PATH_TRANSLATED $document_root$orig_path;
}

위의 블록은 추가 경로 정보를 허용하기 위해 cgi.fix_pathinfo가 "1\로 설정된 PHP 구성에서 작동해야 합니다. 여기서 위치 블록은 .php 로 끝나는 요청뿐만 아니라 일치합니다. 뿐만 아니라 추가 디렉토리 구성요소를 나타내는 슬래시(/) 바로 앞에 .php가 있는 것도 뒤따릅니다.

블록 내에서 fastcgi_split_path_info 지시문은 정규식을 사용하여 두 개의 캡처된 그룹을 정의합니다. 첫 번째 그룹은 처음부터 .php의 첫 번째 인스턴스까지 URI 부분을 일치시키고 $fastcgi_script_name 변수에 배치합니다. 그런 다음 해당 지점 이후의 모든 정보를 두 번째 캡처된 그룹에 배치하고 $fastcgi_path_info라는 변수에 저장합니다.

set 지시문을 사용하여 이 시점에서 $fastcgi_path_info에 저장된 값을 $orig_path라는 변수에 저장합니다. 이는 $fastcgi_path_info 변수가 try_files 지시문에 의해 잠시 후에 지워지기 때문입니다.

try_files를 사용하여 위에서 캡처한 스크립트 이름을 테스트합니다. 이것은 실행하려는 스크립트가 디스크에 있는지 확인하는 파일 작업입니다. 그러나 이것은 또한 $fastcgi_path_info 변수를 지우는 부작용이 있습니다.

기존 FastCGI 패스를 수행한 후 평소와 같이 SCRIPT_FILENAME을 설정합니다. 또한 PATH_INFO$orig_path 변수로 오프로드한 값으로 설정합니다. $fastcgi_path_info가 삭제되더라도 원래 값은 이 변수에 유지됩니다. 또한 PATH_TRANSLATED 매개변수를 설정하여 추가 경로 정보를 디스크에 있는 위치에 매핑합니다. $document_root 변수를 $orig_path 변수와 결합하여 이를 수행합니다.

이를 통해 /index.php/users/view와 같은 요청을 구성할 수 있으므로 /index.php 파일이 /users/view<에 대한 정보를 처리할 수 있습니다. /test.jpg/index.php가 실행되는 상황을 피하면서 디렉토리. 항상 스크립트를 .php로 끝나는 가장 짧은 구성 요소로 설정하여 이 문제를 방지합니다.

스크립트 파일의 위치를 변경해야 하는 경우 별칭 지시문을 사용하여 이 작업을 수행할 수도 있습니다. 우리는 위치 헤더와 fastcgi_split_path_info 정의 모두에서 이를 설명해야 합니다.

location ~ /test/.+[^/]\.php(/|$) {

    alias /var/www/html;

    fastcgi_split_path_info ^/test(.+?\.php)(.*)$;
    set $orig_path $fastcgi_path_info;

    try_files $fastcgi_script_name =404;

    fastcgi_pass unix:/var/run/php5-fpm.sock;
    fastcgi_index index.php;
    include fastcgi_params;

    fastcgi_param SCRIPT_FILENAME $request_filename;
    fastcgi_param PATH_INFO $orig_path;
    fastcgi_param PATH_TRANSLATED $document_root$orig_path;
}

이를 통해 PATH_INFO 매개변수를 안전하게 활용하는 애플리케이션을 실행할 수 있습니다. 이 작업을 올바르게 수행하려면 php.ini 파일의 cgi.fix_pathinfo 옵션을 "1”로 변경해야 합니다. php-fpm.conf 파일에서 security.limit_extensions를 해제하십시오.

결론

이제 Nginx의 FastCGI 프록시 기능에 대해 더 잘 이해하셨기를 바랍니다. 이 기능을 통해 Nginx는 빠른 연결 처리 및 정적 콘텐츠 제공에서 강점을 발휘하는 동시에 동적 콘텐츠에 대한 책임을 더 적합한 소프트웨어에 오프로드할 수 있습니다. FastCGI를 사용하면 Nginx가 성능이 우수하고 안전한 구성에서 수많은 애플리케이션과 함께 작동할 수 있습니다.