apache Proxy 설정 정리 - Kim-Taesu/study GitHub Wiki

업스트림

  • 클라이언트나 로컬 기기(일반적으로 컴퓨터나 모바일기기)에서 서버나 원격 호스트(이하 서버)로 보내지는(전송되는) 데이터 또는 보내는 것을 의미한다

다운스트림

  • 업스트림의 반대로, 서버에서 로컬 기기로 전송되는 데이터의 흐름을 말한다.

Apache Module mod_proxy

  • 신뢰할 수 있는 서버가 아닌 이상 proxy 설정을 하지 않는 것을 권장
  • mod_proxy 및 관련 모듈은 Apache HTTP Server용 프록시/게이트웨이를 구현하여 여러 유명한 프로토콜과 다양한 로드밸런싱 알고리즘을 지원한다.
    • 서드파티 모듈도 추가할 수 있다.
  • 해당 모듈을 사용하기 위해 우선 Apache 서버에 모듈을 로드해야 한다.
    • 빌드 시 정적으로 포함되거나
    • LoadModule 지시문을 통해 동적으로 포함될 수 있다.
  • 필수 포함 목록
    • mod_proxy : 기본 proxy 기능 제공

    • 로드 밸런싱이 필요한 경우, mod_proxy_balancer 또는 1개 이상의 밸런서가 필요하다.

    • 1개 이상의 scheme 또는 protocol, modules 필요

      Protocol Module
      AJP13 (Apache JServe Protocol version 1.3) mod_proxy_ajp
      CONNECT (for SSL) mod_proxy_connect
      FastCGI mod_proxy_fcgi
      ftp mod_proxy_ftp
      HTTP/0.9, HTTP/1.0, and HTTP/1.1 mod_proxy_http
      HTTP/2.0 mod_proxy_http2
      SCGI mod_proxy_scgi
      UWSGI mod_proxy_uwsgi
      WS and WSS (Web-sockets) mod_proxy_wstunnel
  • 추가 확장 기능은 다른 모듈에서 제공된다.
    • mod_cache : 캐싱 관련
    • mod_ssl : SSL/TLS 프로토콜을 사용하여 원격 서버에 접속하는 기능

포워드 프록시, 리버스 프록시(게이트웨이)

  • Apache HTTP Server는 총 2가지(포워드 프록시, 리버스 프록시) 모드로 구성할 수 있다.

포워드 프록시

  • 클라이언트와 원본 서버 사이에 있는 중간 서버이다.
  • 원본 서버로부터 컨텐츠를 가져오기 위해 클라이언트는 원본 서버를 대상으로 하는 요청을 프록시 서버로 보낸다.
  • 프록시 서버는 원본 서버에 콘텐츠를 요청하고 클라이언트에게 반환한다.
  • 클라이언트는 반드시 포워드 프록시를 사용하여 다른 사이트(원본서버)에 접근하도록 구성되어야 한다.
  • 일반적인 사용 : 방화벽에 의해 제한되는 내부 클라이언트에 접근할 때 사용
  • 캐싱(mod_cache)을 사용하여 네트워크 사용량을 줄일 수 있다.
  • 포워드 프록시는 ProxyRequests 지시문을 통해 활성화 된다.
  • 포워드 프록시를 사용하면 클라이언트가 프록시 서버를 통해 임의의 사이트에 접근하고, 클라이언트에 대한 정보를 숨길 수 있다.
    • 따라서 포워드 프록시를 활성화하기 전에 승인된 클라이언트만 프록시 서버에 접근할 수 있도록 해야한다.

리버스 프록시(게이트웨이)

  • 일반 웹 서버처럼 클라이언트에 나타난다.
  • 클라이언트는 리버스 프록시의 콘텐츠에 대해 요청을 하게되면, 리버스 프록시 서버는 해당 요청을 원본 서버로 보낸다. 이후 리버스 프록시 서버가 마치 원본 서버인 것 처럼 컨텐츠를 클라이언트에게 반환한다.
  • 일반적인 사용 : 인터넷 사용자가 방화벽 뒤에 있는 서버에 대한 액세스를 제공할 때 사용
  • 리버스 프록시를 사용하여 여러 백엔드 서버 간으 ㅣ로드 균형을 조정하거나 느린 백엔드 서버에 캐싱을 제공할 수 있다.
  • 리버스 프록시를 사용하여 여러 서버를 동일한 1개의 URL로 가져올 수도 있다.
  • 리버스 프록시는 ProxyPass 지시문 또는 RewriteRule 지시문에 대한 [P] flag를 사용하여 활성화 된다.
  • 리버스 프록시를 구성하기 위해 ProxyRequests를 활성화 할 필요는 없다.

기본 사용 예제

Reverse Proxy

ProxyPass "/foo" "http://foo.example.com/bar"
ProxyPassReverse "/foo" "http://foo.example.com/bar"

Foward Proxy

ProxyRequests On
ProxyVia On

<Proxy "*">
  Require host internal.example.com
</Proxy>

Handler 예제

  • 핸들러를 추가하여 리버스 프록시 요청으로 처리하도록 강제할 수 있다.
# 리버스 프록시를 사용하여, PHP 스크립트에 대한 모든 요청을 지정된 FastCGI 서버로 전달한다.
<FilesMatch "\.php$">
    # Unix sockets require 2.4.7 or later
    SetHandler  "proxy:unix:/path/to/app.sock|fcgi://localhost/"
</FilesMatch>

Workers

  • 프록시는 worker라 불리는 object에서 원본 서버와의 통신 설정과 통신 파라미터를 관리한다.

  • 기본 제공되는 worker는 2개이다.

    • 포워드 프록시 worker (default)
    • 리버스 프록시 worker
  • 추가 worker는 설정파일에 명시적으로 기술하면 된다.

  • 2개의 기본 worker는 설정이 고정되어 있고 특정 요청과 일치하는 다른 worker가 없는 경우 사용된다.

    • HTTP Keep-Alive 또는 connection 재사용을 사용하지 않는다.
    • 각 요청에 대해 원본 서버에 대한 TCP 연결이 open/close 된다.
  • 설정파일에 명시적으로 기술한 worker는 URL로 식별된다.

    • 일반적으로 리버스 프록시에 사용될 때 ProxyPass 또는 ProxyPassMatch를 사용하여 생성 및 설정한다.
  • 예시

    1. /example로 요청이 프록시 서버로 들어오면 connectiontimeout=5, timeout=30 설정 값을 사용하는 원본 서버 URL("http://backend.example.com")과 연결된 worker가 생성된다.
    ProxyPass "/example" "http://backend.example.com" connectiontimeout=5 timeout=30
    
    1. 포워드 프록시에서 사용되는 경우 worker는 일반저긍로 ProxySet 지시문을 통해 정의된다.
    ProxySet "http://backend.example.com" connectiontimeout=5 timeout=30
    
    <Proxy "http://backend.example.com">
        ProxySet connectiontimeout=5 timeout=30
    </Proxy>
    
  • 보통 포워드 프록시는 일반적으로 다양한 원본 서버와 통신하기 때문에, 특정 원본서버로 보내도록 설정한 worker를 사용하지 않는다.

    • 특정 원본 서버에 대해 요청량이 많을 경우 사용할 수 있다.
  • 설정 파일에 명시적으로 설정한 worker는 포워드/리버스 프록시 개념이 없다.

    • 원본 서버와의 통신에 대한 공통 개념을 캡슐화 한다.
  • 리버스 프록시에서 사용하기 위한 worker(ProxyPass로 생성 된)는 원본 서버에 대한 URL이 worker에 설정한 URL과 일치/불일치할 때 포워드 프록시 요청으로도 사용될 수 있다.

예시

ProxyPass "/examples" "http://backend.example.com/examples"
ProxyPass "/docs" "http://backend.example.com/docs"
  • 위 예시는 총 2개의 worker가 정의되어 있다.
    • worker는 별도의 connection pool과 설정을 가지고 있다.

Worker Sharing

  • worker URL이 겹치는 경우 Worker Sharing이 발생한다.
  • worker의 URL이 설정파일에서 다른 worker URL의 하위 계층일 경우 발생
ProxyPass "/apps" "http://backend.example.com/" timeout=60
ProxyPass "/examples" "http://backend.example.com/examples" timeout=10
  • 위 예시에서 두 번째 worker는 실제로 생성되지 않는다.
    • 첫 번째 worker로 사용된다.
  • 따라서 connection pool이 1개만 존재하므로 connection이 더 자주 재사용된다.
  • 명시적으로 기입한 두 번째 worker의 설정은 무시되며 warning 로그가 남는다.
    • 위 예시에서 /examples 요청에 대한 timeout은 10대신 60으로 설정된다.
  • worker sharing을 방지하려면 가장 긴 worker URL이 가장 상단에 오도록 정렬해야한다.
  • 반대로 worker sharing을 최대로 사용하려면 URL 길이 역순으로 정렬하면 된다.

worker 유형

  • 명시적으로 설정한 worker는 2가지 유형이 있다.
    • direct worker
    • (load) balancer worker
  • 2가지 유형 모두 ProxyPass 지시문의 속성을 사용하여 중요한 설정을 할수 있다.
    • ProxySet을 사용하여 ProxyPass와 동일한 속성을 설정할 수 있다.

direct worker

  • 사용할 수 있는 옵션은 원본 서버 URL에 지정된 프로토콜에 따라 다르다.
  • 사용가능한 프로토콜은 ajp, fcgi, ftp, httpscgi가 포함된다.

balancer worker

  • 실제로 요청을 처리하기 위해 direct worker를 사용하는 가상의 worker
  • 각 밸런서는 여러 direct worker를 가질 수 있다.
  • 요청을 처리할 때 구성된 로드 밸런싱 알고리즘을 기반으로 worker를 선택한다.
  • worker URL이 밸런서를 프로토콜로 사용하는 경우 밸런서 worker가 생성된다.
  • 밸런서 url은 밸런서 worker를 고유하게 식별한다.
  • direct worker는 BalancerMember를 사용하여 밸런서에 추가된다.

Controlling Access to Your Proxy

  • <Proxy> 블록으로 proxy 접근을 설정할 수 있다.
<Proxy "*">
  Require ip 192.168.0
</Proxy>
  • 포워드 프록시(ProxyRequests 지시문 사용)를 사용하는 경우 프록서 서버로의 접근을 엄격하게 제한해야 한다.
    • 모든 클라이언트가 프록시 서버를 사용하여 클라이언트 IP를 숨기고 임의의 원본서버에 접근할 수 있기 때문이다.
  • 리버스 프록시(ProxtRequestsOff + ProxyPass 지시문 사용)를 사용하는 경우 클라이언트는 특별히 설정한 원본 서버에만 연결할 수 있으므로 프록시 서버에 대한 접근 제어는 덜 중요하다.

Slow Startup

  • ProxyBlock 지시문을 사용하는 경우, hostname의 IP는 프록시 서버에서 일치 여부를 테스트할 때 조회되고 캐싱된다.
  • hostname을 찾는 동안 몇 초의 시간이 소요될 수 있다.

Intranet Proxy

  • 인트라넷에 위치한 Apache HTTP 프록시 서버는 회사의 방화벽을 통해 외부 요청을 전달해야 한다.
    • ProxyRemote 지시문을 사용하여 개별 scheme를 회사 방화벽 프록시에 전달하도록 설정
  • 인트라넷 내부 리소스에 접근해야 하는 경우, 호스트에 접근할 때 방화벽을 우회할 수 있다.
    • NoProxy 지시문을 사용하여, 인트라넷에 속하고 직접 액세스해야 하는 호스트를 지정하면 된다.
  • 인트라넷 내부 사용자는 WWW 요청에서, 로컬 도메인 이름을 생략하는 경향이 있으므로 http://somehost.example.com/ 요청 대신 http://somehost/를 요청한다.
    • PromxyDomain 지시문을 사용하여 프록시 서버가 서비스용으로 구성된 경우, Apache httpd는 redirection 응답을 반환하고 클라이언트를 올바른 서버주소로 보낼 수 있다.

Request Body

  • POST와 같은 일부 요청에는 request body이 포함된다.
  • HTTP 프로토콜은 request body을 포함하는 요청이 chunked transfer encoding을 사용하거나 요청 헤더에 Content-Length 헤더를 보내도록 요구한다.
    • 이러한 요청을 원본 서버에 전달할 때 mod_proxy_http는 항상 Content-Length 헤더 전송을 시도한다.
    • 그러나 request body 크기가 크고 원래 요청이 chunked encoding을 사용했다면 업스트림 요청에서도 chunked encoding을 사용할 수 있다.
      • 환경 변수로 위 옵션을 제어할 수 있다.
      • proxy_sendcl을 설정하면 항상 Content-Length 헤더를 전송하여 업스트림 서버와의 최대 호환성을 보장하고,
      • proxy-sendchunked를 설정하면 chunked encoding을 사용하여 리소스 사용을 최소화 한다.
  • 일부 상황에서 프록시 서버는 request body를 처리하기 위해 body 값을 디스크에 스풀링해야 한다.
    • request body 원본 내용이 chunk encoding으로 전송되었지만, 원본 서버에서 request를 Content-Length 또는 HTTP/1.0으로 전송하도록 요청한 경우에 발생
    • request body에 이미 Cotent-Length 헤더가 있지만 원본 서버가 들어오는 request body를 필터링하도록 구성된 경우에도 발생할 수 있다.
  • LimitRequestBody는 프록시 서버가 디스크에 스풀링할 request body에만 적용된다.

chunked transfer encoding

  • 클라이언트가 요청한 response 크기가 큰 경우 chunk 단위로 client에 전송한다.
    • response 데이터 크기를 알 필요가 없다.
    • 스트림 형태일 경우 유리
  • response 헤더에 Content-Length 대신 Transfer-Encoding:chunked가 존재한다면 chunk 단위로 분할하여 데이터를 전송한다는 의미이다.
  • 받은 chunk 단위 데이터의 크기가 0일 때 모든 데이터를 전송했다는 의미이다.

Reverse Proxy Request Headers

  • 리버스 프록시를 사용할 때 mod_proxy_http는 추가 정보를 원본 서버에 전달하기 위해 여러 request 헤더를 추가한다.
헤더 설명
X-Forwarded-For 클라이언트의 IP 주소
X-Forwarded-Host 클라이언트가 요청한 original host (proxy server)
X-Forwarded-Server proxy server의 hostname
여러 프록시 서버를 거친 경우 1개 이상의 주소를 얻을 수 있다.
  • 커스텀 헤더를 추가하려면 RequestHeader 지시문을 사용하면 된다.

지시문

  • 프록시가 적용된 지시문을 위한 컨테이너

예시

  • yournetwork.example.com의 호스트만 프록시 서버를 통해 콘텐츠에 접근할 수 있도록 허용

    <Proxy "*">
      Require host yournetwork.example.com
    </Proxy>
    

지시문

  • 원격 서버(원본 서버)와 로컬 서버(프록시 서버) URL 매핑
  • 로컬 서버는 일반적인 의미에서 프록시 역할을 하지 않지만 원격서버의 미러처럼 보인다.
  • 로컬 서버는 종종 리버스 프록시 또는 게이트웨이라고 부른다.
  • ProxyPass 지시문의 path는 로컬 가상 경로의 이름이다.
  • ProxyPass 지시문의 url은 원격 서버의 부분 URL이며 쿼리 문자열을 포함할 수 없다.
  • ProxyRequests 지시문은 일반적으로 ProxyPass를 사용할 때 설정해야 한다.

내부에서 사용될 때

  • <Location> 섹션 안에서 사용될 때는 Location의 첫번 째 파라미터(URL)는 생략되고 로컬 디렉토리는 에서 가져온다.
  • 로컬 서버의 주소가 http://example.com/이라고 가정
<Location "/mirror/foo/">
    ProxyPass "http://backend.example.com/"
</Location>
  • http://example.com/mirror/foo/bar에 대한 로컬 요청이 내부적으로 http://backend.example.com/bar에 대한 프록시 요청으로 변환된다.
  • 위 conf 설정은 아래와 같은 구문으로 대체가 가능하다.
    • 하지만 해당 구문이 많이 존재할 경우 성능 저하가 발생할 수 있다.
ProxyPass "/mirror/foo/" "http://backend.example.com/"
  • 첫 번째 아규먼트의 마지막이 /로 끝나면 두 번째 아규먼트도 /로 끝나야한다.

! 지시문

  • ! 지시문은 하위 디렉토리를 리버스 프록시하지 않으려는 경우에 사용
<Location "/mirror/foo/">
    ProxyPass "http://backend.example.com/"
</Location>
<Location "/mirror/foo/i">
    ProxyPass "!"
</Location>
ProxyPass "/mirror/foo/i" "!"
ProxyPass "/mirror/foo" "http://backend.example.com"
  • /mirror/foo/i에 대한 요청을 제외하고 /mirror/foo에 대한 모든 요청을 backend.example.com에 프록시한다.

  • ProxyPass 설정을 혼합하면 원하는대로 프록시가 안될 수 있다.

ProxyPass "/mirror/foo/i" "!"
<Location "/mirror/foo/">
    ProxyPass "http://backend.example.com/"
</Location>
  • Location 블록의 ProxyPass 지시문이 먼저 적용되기 때문에 /mirror/foo/i에 대한 요청이 프록시 처리된다.
  • 하나의 ProxyPass 지시문만 Location 블록에 배치할 수 있다.

ProxyPassReverse 지시문

  • 리버스 프록시 서버에서 보낸 HTTP 응답 해더의 URL를 조정한다.
  • Apache httpd가 HTTP redirect response에서 Location, Content-Location 및 URI 헤더의 URL를 조정할 수 있도록 해준다.
  • Apache httpd를 리버스 프록시(또는 게이트웨이)로 사용하여 리버스 프록시 뒤에 남아 있는 원본 서버(백엔드 서버)의 HTTP redirect로 인해 리버스 프록시를 우회하는 것을 방지하는데 필요한 설정이다.

예시

  • 프록시 서버의 주소가 http://example.com/이라고 가정
ProxyPass         "/mirror/foo/" "http://backend.example.com/"
ProxyPassReverse  "/mirror/foo/" "http://backend.example.com/"
ProxyPassReverseCookieDomain  "backend.example.com"  "public.example.com"
ProxyPassReverseCookiePath  "/"  "/mirror/foo/"
  • http://example.com/mirror/foo/bar에 대한 프록시 서버 요청이 내부적으로 http://backend.example.com/bar에 대한 프록시 요청으로 변환될 뿐만 아니라(ProxyPass가 여기에서 제공하는 기능).
  • 또한 http://backend.example.com/barhttp://backend.example.com/quux로 리디렉션할 때 backend.example.com 서버가 보내는 리디렉션을 처리합니다.
  • Apache httpd는 HTTP redirect 응답을 클라이언트에 전달하기 전에 이를 http://example.com/mirror/foo/quux로 조정한다.
  • URL 구성에 사용되는 호스트 이름은 UseCanonicalName 지시문 설정과 관련하여 선택됩니다.

ProxyPreserveHost 지시문

  • 프록시 요청에 수신 host HTTP 요청을 사용
  • 해당 옵션이 활성화 되면 Host 헤더를 현재 사용자가 요청한 서버 host로 지정해준다.
  • 일반적으로 해당 옵션은 Off 해야한다.
  • 원본 서버(백엔드 서버)에서 원래 호스트 헤더를 평가해야 하는 경우 유용하다.
⚠️ **GitHub.com Fallback** ⚠️