서버를 대신해 요청을 받는 중계자.
-
포워드 프록시 — 클라이언트를 대신한다
- 사내망에서 외부로 나갈 때 거치는 것
- 서버는 진짜 클라이언트가 누군지 모른다
-
리버스 프록시 — 서버를 대신한다
- 클라이언트는 진짜 서버가 누군지 모른다
- 우리가 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 맨 앞이 실제 클라이언트" → 위조 가능하다. 신뢰 프록시 기준으로 센다.