사전 리버스 프록시
패턴

리버스 프록시

gabury1

서버 앞에 세워 두고 요청을 대신 받는 중개자입니다. 클라이언트는 이 중개자를 서버로 알고 요청을 보냅니다. 중개자는 받은 요청을 뒤쪽 서버로 넘기고, 돌아온 응답을 클라이언트에게 되돌려 줍니다.

상세

HTTP(HyperText Transfer Protocol)는 연결을 사슬처럼 이어 붙여 요청을 처리할 수 있게 만들어져 있습니다. 그 사슬 중간에 놓이는 것이 중개자입니다. RFC(Request for Comments) 9110 은 중개자의 흔한 형태를 프록시와 게이트웨이와 터널 셋으로 나눕니다. 하나의 중개자가 요청의 성격에 따라 오리진 서버, 프록시, 게이트웨이, 터널로 역할을 바꿔 가며 동작하기도 한다고 적습니다.

리버스 프록시는 이 셋 중 게이트웨이의 다른 이름입니다. RFC 9110 은 게이트웨이를 이렇게 정의합니다. 바깥쪽 연결에 대해서는 오리진 서버로 동작하는 중개자입니다. 받은 요청은 번역해 안쪽의 다른 서버 하나 또는 여럿으로 전달합니다. 정의의 무게는 앞쪽 절반에 있습니다. 요청을 보낸 쪽에서 보면 응답을 준 것이 바로 이 중개자입니다. 뒤에 서버가 몇 대 있는지, 거기서 무엇이 도는지는 보이지 않습니다.

sequenceDiagram
    participant 클라이언트
    participant 프록시 as 리버스 프록시
    participant 오리진 as 오리진 서버
    클라이언트->>프록시: 요청
    Note over 프록시: 바깥쪽 연결에는 오리진 서버로 동작한다
    프록시->>오리진: 요청을 안쪽으로 전달
    오리진-->>프록시: 응답
    프록시-->>클라이언트: 응답

클라이언트는 프록시에만 연결합니다. 프록시는 그 바깥쪽 연결에 대해 오리진 서버로 동작합니다. 안쪽으로는 받은 요청을 번역해 다시 보냅니다. 그래서 프록시는 지나가는 요청을 그대로 흘려보내지 않습니다.

RFC 9110 은 게이트웨이가 쓰이는 자리로 셋을 듭니다. 낡았거나 신뢰할 수 없는 정보 서비스를 감싸는 것, 가속기 캐싱으로 서버 성능을 개선하는 것, HTTP 서비스를 여러 대의 기계에 걸쳐 분할하거나 부하를 나누는 것입니다.

대가

세우기로 한 순간 홉이 하나 늘어납니다. 늘어난 홉은 흔적을 남깁니다. RFC 9110 은 Via 헤더 필드가 사용자 에이전트와 서버 사이, 또는 오리진 서버와 클라이언트 사이에 낀 중간 프로토콜과 수신자의 존재를 나타낸다고 적습니다. 프록시는 전달하는 메시지마다 적절한 Via 헤더 필드를 보내야 합니다(MUST). HTTP 사이를 잇는 게이트웨이도 안쪽으로 보내는 요청 메시지마다 적절한 Via 헤더 필드를 보내야 합니다(MUST). 전달하는 응답 메시지에는 보낼 수 있습니다(MAY). 중개자마다 메시지를 어떻게 받았는지를 자기 정보로 덧붙이므로, 최종 결과는 전달한 수신자의 순서대로 늘어섭니다.

백엔드가 보는 요청도 달라집니다. RFC 7239 는 오늘날 사용자 에이전트를 위해 프록시 노릇을 하는 응용이 여럿 있다고 적습니다. 많은 경우 그 프록시는 최종 사용자의 행동이나 인지 없이 존재합니다. 웹 서버를 운영하는 조직 안의 기반 설비 일부로 프록시가 놓이는 경우가 그 예입니다. 그런 프록시는 부하 분산이나 암호 처리 떠넘기기 같은 기능에 쓰일 수 있습니다. 그런데 이 프록시들은 요청이 프록시의 IP(Internet Protocol) 주소에서 시작된 것처럼 보이게 만듭니다. 원 요청의 다른 정보도 바꿀 수 있습니다. RFC 7239 는 이것이 원 요청으로부터의 정보 손실이라고 못 박습니다. 클라이언트의 IP 주소를 쓸 데가 따로 있는 웹 서버에서는 이 손실이 문제를 일으킬 수 있습니다. 프록시의 주소나 프록시가 바꾼 다른 정보로는 그 쓰임이 채워지지 않기 때문입니다. RFC 7239 는 이 정보를 주로 쓰는 데가 진단과 접근 제어와 남용 관리라고 적습니다.

헤더도 그냥 지나가지 않습니다. nginx 공식 문서는 원 요청의 Host 와 Connection 헤더 필드가 기본적으로는 프록시되는 서버로 전달되지 않는다고 적습니다. HTTP/1.0 이나 HTTP/1.1 로 프록시하면 이 필드들이 다시 정의됩니다.

nginx
proxy_set_header Host $proxy_host;
proxy_set_header Connection close;

HTTP/2 에서는 :authority 유사 헤더 필드가 $proxy_host 값으로 기본 전송됩니다. 명시적인 Host 헤더 필드로 교체하지 않는 한 그렇습니다. 백엔드가 원래 값을 보게 하려면 proxy_set_header 로 되돌려 놓아야 합니다. 잃어버린 것을 헤더로 복원하는 일이 이 배치를 고른 쪽의 몫으로 남습니다.

얻는 쪽은 RFC 9110 이 든 셋입니다. 낡았거나 신뢰할 수 없는 서비스를 감싸는 것, 가속기 캐싱, 여러 기계에 걸친 분할과 부하 분산입니다. 내주는 쪽이 홉 하나와 원 요청의 정보입니다.

이름의 출처

이 이름을 붙인 사람 하나를 대지는 못합니다. 대신 이름이 처음 정의된 문서를 댈 수 있습니다. RFC 3040, Internet Web Replication and Caching Taxonomy 입니다. 2001년 1월에 나왔습니다. 저자는 Equinix 의 I. Cooper, UNINETT 의 I. Melve, CacheFlow 의 G. Tomlinson 세 사람입니다.

이 문서는 이름을 세운 것이 아니라 고치려 했습니다. RFC 3040 은 서로게이트를 이렇게 정의합니다. 오리진 서버와 같은 자리에 놓이거나 망의 다른 지점에 놓이는 게이트웨이입니다. 하나 이상의 오리진 서버를 대신해 동작할 권한을 위임받습니다. 대개 그 서버들과 긴밀히 협력합니다. 응답은 대개 내부 캐시에서 나갑니다. 그리고 문서는 흔히 리버스 프록시와 오리진 서버 가속기라 불리는 장치가 둘 다 서로게이트로 정의하는 편이 더 적절하다고 적습니다. 용어집의 리버스 프록시 항목에는 뜻풀이가 없습니다. see "surrogate" 한 줄로 넘깁니다.

굳은 것은 반대쪽 이름입니다. 뒤에 나온 RFC 9110 은 게이트웨이를 정의하면서 표제 옆 괄호에 a.k.a. "reverse proxy" 를 그대로 답니다. 표준 문서가 밀었던 서로게이트가 아니라 현장에서 쓰던 이름이 표준 문서 안으로 들어가 남았습니다.

RFC 3040 이 리버스 프록시와 나란히 놓았던 또 하나의 옛 이름은 제품 설정에 남아 있습니다. Squid 공식 문서의 http_port 지시어는 모드 플래그 accel 을 accelerator / reverse proxy mode 라고 적습니다. 모드 플래그를 빼면 기본값인 포워드 프록시 모드가 됩니다. 같은 소프트웨어의 같은 지시어에서 두 배치가 플래그 하나로 갈립니다.

예시

nginx 의 최소 설정

nginx 공식 문서는 ngx_http_proxy_module 모듈이 요청을 다른 서버로 넘기게 해 준다고 적습니다. 문서가 싣고 있는 예제 설정 한 벌입니다.

nginx
location / {
    proxy_pass http://localhost:8000;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
}

proxy_pass 가 받은 요청을 넘길 곳을 정합니다. 여기서는 같은 기계의 8000 포트입니다. 이 한 줄이 리버스 프록시 배치의 최소 형태입니다. 나머지 두 줄은 proxy_set_header 입니다. nginx 공식 문서는 이 지시어가 프록시되는 서버로 넘길 요청 헤더 필드를 다시 정의하거나 덧붙이게 해 준다고 적습니다. 여기서 그 대상이 되는 필드가 Host 와 X-Real-IP 입니다.

여러 백엔드를 묶은 설정

nginx 공식 문서는 ngx_http_upstream_module 모듈이 proxy_pass, fastcgi_pass, uwsgi_pass, scgi_pass, memcached_pass, grpc_pass 지시어가 참조할 수 있는 서버 그룹을 정의하는 데 쓰인다고 적습니다.

nginx
upstream backend {
    server backend1.example.com weight=5;
    server backend2.example.com:8080;
    server unix:/tmp/backend3;

    server backup1.example.com:8080 backup;
    server backup2.example.com:8080 backup;
}

server {
    location / {
        proxy_pass http://backend;
    }
}

proxy_pass 가 가리키는 곳이 서버 하나가 아니라 backend 라는 이름의 그룹입니다. 그룹 안의 server 줄마다 주소가 다릅니다. 도메인 이름과 포트로 적은 것이 있습니다. 유닉스 소켓 경로로 적은 것도 있습니다. 이 그룹이 proxy_pass 가 참조하는 이름입니다.

경계

여러 백엔드로 나눠 보내면 그건 로드 밸런서지 리버스 프록시가 아닌 것 아닌가. 아닙니다. 여전히 리버스 프록시입니다.

근거는 정의 안에 이미 있습니다. RFC 9110 은 게이트웨이를 정의하면서 받은 요청을 안쪽의 다른 서버 하나 또는 여럿으로 전달한다고 적습니다. 여럿이 정의에 들어 있습니다. 같은 절은 게이트웨이가 쓰이는 자리를 들면서 HTTP 서비스를 여러 대의 기계에 걸쳐 분할하거나 부하를 나누는 것을 그중 하나로 꼽습니다. 부하 분산은 이 배치가 하는 일 중 하나이지, 이 배치와 다른 별개의 배치가 아닙니다.

제품 쪽 설정도 같은 선을 긋습니다. nginx 에서 upstream 은 독립된 기능이 아니라 proxy_pass 가 참조하는 서버 그룹의 이름입니다. 예시 절의 두 설정은 proxy_pass 뒤에 오는 값이 서버 하나인지 그룹 이름인지만 다릅니다.

가르는 선은 백엔드가 몇 대인지가 아닙니다. 바깥쪽 연결에 대해 오리진 서버로 동작하느냐입니다.

관련 항목

같은 사슬에 서는 중개자

프록시 · 게이트웨이 · 터널 · 인터셉션 프록시 · 트랜스페어런트 프록시 · 포워드 프록시 · 오리진 서버 · 사용자 에이전트 · 서로게이트 · 오리진 서버 가속기

이 자리를 맡는 소프트웨어

nginx · Squid · Apache httpd · HAProxy · Envoy · Caddy

원 요청의 정보를 나르는 헤더

Via · Forwarded · X-Forwarded-For · X-Real-IP · Host

리버스 프록시를 정의하는 표준

RFC 9110 · RFC 3040 · RFC 7239

헷갈리는 이웃

로드 밸런서 · API 게이트웨이(Application Programming Interface) · CDN(Content Delivery Network)

이 배치에 얹히는 기능

캐싱 · TLS 종료(Transport Layer Security) · 헬스 체크

다른 이름: reverse proxy · surrogate · 리버스프록시