웹 서버·WAS 용어 사전
구조reverse proxy · 포워드 프록시 · X-Forwarded-For · X-Forwarded-Proto

리버스 프록시

서버를 대신해 요청을 받는 중계자. 뒤에 몇 대가 있든 클라이언트에게는 한 대로 보인다.

서버를 대신해 요청을 받는 중계자.

  • 포워드 프록시 — 클라이언트를 대신한다

    • 사내망에서 외부로 나갈 때 거치는 것
    • 서버는 진짜 클라이언트가 누군지 모른다
  • 리버스 프록시 — 서버를 대신한다

    • 클라이언트는 진짜 서버가 누군지 모른다
    • 우리가 nginx 를 앞에 두는 것이 이것이다

뒤에 몇 대가 있든 클라이언트에게는 한 대로 보인다. 그래서 로드밸런싱·무중단 배포·A/B 라우팅이 전부 이 자리에서 가능해진다.

원래 정보를 잃지 않으려면

프록시를 거치면 WAS 입장에서 모든 요청이 프록시에서 온 것처럼 보인다.

location /api/ {
    proxy_pass http://backend;
    proxy_set_header Host              $host;
    proxy_set_header X-Real-IP         $remote_addr;
    proxy_set_header X-Forwarded-For   $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
}
  • Host — 안 넘기면 리다이렉트 URL 이 깨진다
  • X-Real-IP — 원래 클라이언트 IP
  • X-Forwarded-For — 경유 목록. proxy_add_x_forwarded_for 는
    • 기존 값 뒤에 현재 클라이언트를 덧붙인다
  • X-Forwarded-Proto — 안 넘기면 애플리케이션이 http 로 착각해
    • https 페이지에서 http 리다이렉트를 내보낸다
    • 혼합 콘텐츠 차단 · 무한 리다이렉트

XFF 는 위조된다

X-Forwarded-For 는 그냥 헤더다. 클라이언트가 아무 값이나 넣어 보낼 수 있다

  • X-Forwarded-For: 1.2.3.4 — ← 공격자가 직접 넣은 값 프록시가 덧붙임 → 1.2.3.4, 실제IP

맨 앞 값을 접속 IP 로 쓰면

  • IP 기반 접근 제한이 그대로 우회된다
  • 감사 로그가 조작된다
  • 레이트 리밋을 무한히 회피할 수 있다

규칙 — 신뢰할 수 있는 프록시가 덧붙인 '오른쪽에서부터' 센다

  • 신뢰 프록시 개수를 알고 그만큼 건너뛴 값을 쓴다
  • nginx 의 realip 모듈 · set_real_ip_from 으로 신뢰 대역을 못 박는다
set_real_ip_from 10.0.0.0/8;     # 신뢰하는 프록시 대역만
real_ip_header   X-Forwarded-For;
real_ip_recursive on;

계층이 여럿일 때

클라이언트 → CDN → 클라우드 LB → 인그레스 → nginx → 애플리케이션

  • 계층마다 타임아웃 · 버퍼 · 헤더 처리가 있다
  • 장애의 상당수가 '계층마다 값이 어긋나서' 생긴다

계층이 늘어도 하는 일은 셋뿐이다

  • 연결을 받고 · 어디로 보낼지 정하고 · 응답을 손봐 돌려준다

앞단이 있어서 가능해지는 것들

  • 무중단 배포 — 업스트림 목록만 바꿔 리로드

  • 카나리·A/B — 가중치나 헤더 기준으로 일부만 새 버전으로

  • 점검 페이지 — 백엔드가 전멸해도 안내를 띄운다

  • 레이트 리밋 — limit_req · limit_conn 을 애플리케이션 밖에서

  • 응답 캐시 — proxy_cache 로 백엔드 부하를 덜어낸다

  • 보안 헤더·WAF — 애플리케이션이 몰라도 되는 정책

  • '애플리케이션을 고치지 않고 할 수 있는 일' 의 목록이기도 하다

캐시를 앞단에 둘 때

proxy_cache_path /var/cache/nginx keys_zone=api:10m max_size=1g inactive=60m;

location /api/public/ {
    proxy_cache api;
    proxy_cache_valid 200 60s;
    proxy_cache_use_stale error timeout updating http_500 http_502 http_503;
    proxy_cache_lock on;          # 같은 키 동시 미스를 1건으로 (싱글플라이트)
    add_header X-Cache-Status $upstream_cache_status;
}
  • use_stale — 백엔드가 아플 때 만료된 캐시라도 내보낸다 (가용성 우선)
  • cache_lock — 캐시 만료 순간 요청이 몰려 백엔드를 때리는 것을 막는다
  • X-Cache-Status — HIT/MISS/EXPIRED/STALE 를 응답 헤더로 확인한다

면접 함정

  • "포워드와 리버스는 방향만 다르다" → 누구를 대신하느냐가 다르고, 그래서 신뢰 경계가 반대다.
  • "XFF 맨 앞이 실제 클라이언트" → 위조 가능하다. 신뢰 프록시 기준으로 센다.

함께 보면 좋은 용어

노트에서 맥락과 함께 보기 — 웹 서버란 무엇인가 — WAS와의 역할 분담