
프록시 서버: 나 대신 심부름 다녀와
직접 가기 껄끄러울 때 프록시가 대신 갔다 옵니다. 내 정체를 숨기려면 Forward Proxy, 서버를 보호하려면 Reverse Proxy. 같은 대리인인데 누구 편이냐가 다릅니다.

직접 가기 껄끄러울 때 프록시가 대신 갔다 옵니다. 내 정체를 숨기려면 Forward Proxy, 서버를 보호하려면 Reverse Proxy. 같은 대리인인데 누구 편이냐가 다릅니다.
내 서버는 왜 걸핏하면 뻗을까? OS가 한정된 메모리를 쪼개 쓰는 처절한 사투. 단편화(Fragmentation)와의 전쟁.

미로를 탈출하는 두 가지 방법. 넓게 퍼져나갈 것인가(BFS), 한 우물만 팔 것인가(DFS). 최단 경로는 누가 찾을까?

프론트엔드 개발자가 알아야 할 4가지 저장소의 차이점과 보안 이슈(XSS, CSRF), 그리고 언제 무엇을 써야 하는지에 대한 명확한 기준.

이름부터 빠릅니다. 피벗(Pivot)을 기준으로 나누고 또 나누는 분할 정복 알고리즘. 왜 최악엔 느린데도 가장 많이 쓰일까요?

제가 처음 클라이언트 회사 내부망에서 개발할 때, 외부 API를 호출하려고 하면 막혔습니다. "Connection timed out"만 뜨고 아무것도 안 됐죠. 커뮤니티 선배한테 물어봤더니 "프록시 설정 안 했지?" 하더라고요. 그래서 회사에서 알려준 http_proxy 환경변수를 설정했더니 갑자기 잘 됐습니다.
그때까지만 해도 "프록시가 뭔지는 모르겠지만 어쨌든 이걸 써야 외부 연결이 되는구나" 정도만 알았습니다. 제대로 이해하게 된 건 나중에 Nginx를 써보고 나서였습니다. 그 전까지는 그냥 "환경변수에 이 URL 넣으면 되는구나" 수준이었거든요.
사실 처음 스타트업 시작했을 때는 프록시 같은 거 신경도 안 썼습니다. 내 노트북에서 서버 하나 띄워서 개발하는데 무슨 프록시가 필요하겠어요. 그런데 사용자가 늘면서 서버를 여러 대로 늘리고, HTTPS를 적용하고, CDN을 붙이면서 Reverse Proxy라는 개념을 마주하게 됐습니다. 그리고 깨달았죠. "아, 이게 다 프록시였구나."
"Forward Proxy"와 "Reverse Proxy"라는 단어를 봤을 때 혼란스러웠습니다. Forward는 "앞으로"라는 뜻인가? 그럼 Reverse는 "뒤로"? 둘 다 중간에서 요청을 전달하는 건 똑같은데 뭐가 다르지?
그리고 VPN이랑도 헷갈렸습니다. VPN도 내 IP를 숨겨주는데, 프록시랑 뭐가 다른 거지? 심지어 회사에서는 "VPN 켜고 프록시 설정해야 된다"고 하더라고요. 그럼 VPN이랑 프록시는 별개인가? 같이 쓰는 건가?
또 하나 헷갈렸던 게 Transparent Proxy였습니다. 통신사(ISP) 레벨에서 프록시를 끼워 넣는다는데, 내가 설정한 적도 없는데 어떻게 프록시를 거치는 거지? 이게 뭔 소리인지 처음엔 전혀 감이 안 왔습니다.
핵심이 뭔지 감이 안 왔습니다. 그냥 "프록시 = 중간에 있는 뭔가"라는 막연한 이미지만 있었어요.
그러다가 이 비유를 듣고 확 이해했습니다.
"프록시는 대리인입니다. 백화점 명품 매장에 가기 껄끄러울 때, 대리 구매자를 보내는 것과 같죠.
- Forward Proxy: 당신(클라이언트)의 대리인. 당신이 누군지 숨겨주고 대신 물건을 사옵니다.
- Reverse Proxy: 백화점(서버)의 대리인. 백화점이 바쁘니까 입구에서 대신 응대합니다."
핵심은 "누구를 위해 일하느냐"였습니다. 이 비유가 머릿속에 확 와닿았습니다. 똑같이 중간에서 전달하는 역할이지만, 누구의 이익을 대변하느냐가 다른 거였어요.
명품 매장 비유를 조금 더 확장하면 이렇습니다. 내가 직접 명품 매장에 가면 점원이 내 얼굴을 보고, 내가 뭘 샀는지 다 알게 됩니다. 그런데 대리 구매자를 보내면? 점원은 대리인의 얼굴만 보고, 진짜 구매자가 누군지 모릅니다. 이게 Forward Proxy입니다.
반대로 백화점 입장에서는 손님이 너무 많아서 VIP 고객만 안쪽 매장으로 안내하고, 일반 고객은 입구에서 응대합니다. 손님 입장에선 백화점 내부가 어떻게 생겼는지, 창고가 어디 있는지 모릅니다. 이게 Reverse Proxy입니다.
이 비유를 받아들인 순간부터 프록시 개념이 머릿속에서 정리되기 시작했습니다.
Forward Proxy는 클라이언트(나) 앞에 있는 프록시입니다.
나 → Forward Proxy → 인터넷 → 네이버
내가 네이버에 접속하려고 하면, Forward Proxy가 대신 가서 페이지를 가져옵니다. 네이버 입장에선 프록시의 IP만 보입니다. 내 진짜 IP는 숨겨집니다.
카페에서 공용 WiFi 쓸 때 내 IP를 숨기고 싶을 때 씁니다. 프록시 서버를 경유하면 웹사이트는 프록시의 IP만 보게 됩니다. 예를 들어 토르(Tor) 브라우저가 바로 이런 방식으로 작동합니다. 여러 프록시를 거쳐서 내 IP를 추적할 수 없게 만드는 거죠.
회사에서 유튜브를 막아놨다? Forward Proxy를 통하면 우회할 수 있습니다. (물론 회사 규정 위반일 수 있으니 하지 마세요.) 해외에서 한국 IP가 필요할 때도 한국에 있는 프록시 서버를 쓰면 됩니다. 넷플릭스 지역 제한 우회할 때도 이런 방식을 씁니다.
회사 전체가 같은 프록시를 쓰면, 자주 가는 사이트는 프록시가 캐시해둡니다. 100명이 다 네이버 메인을 보는데, 100번 네이버에 요청 보낼 필요 없이 프록시가 한 번만 가져와서 나눠줍니다. 대역폭도 절약되고 속도도 빨라집니다.
처음엔 프록시가 다 똑같은 줄 알았는데, 알고 보니 여러 종류가 있더라고요.
HTTP Proxy는 HTTP/HTTPS 트래픽만 처리합니다. 웹 브라우징용이죠. http_proxy 환경변수로 설정하는 게 바로 이겁니다.
SOCKS Proxy는 더 low-level에서 작동합니다. HTTP뿐만 아니라 FTP, SMTP, 심지어 게임 트래픽까지 다 프록시를 거칠 수 있습니다. SSH 터널링할 때 많이 씁니다.
# SSH SOCKS Proxy 설정 (내가 실제로 쓰는 방법)
ssh -D 1080 user@remote-server
# 그러면 localhost:1080이 SOCKS5 프록시가 됩니다
이렇게 하면 브라우저나 애플리케이션을 localhost:1080으로 설정하면 SSH 서버를 거쳐서 인터넷에 나갑니다. 회사 방화벽 뚫을 때 유용했습니다. (합법적인 용도로만 쓰세요.)
제가 프로젝트에서 겪었던 케이스입니다.
# 환경변수 설정
export http_proxy=http://proxy.company.com:8080
export https_proxy=http://proxy.company.com:8080
# 이제 curl이나 npm이 프록시를 거쳐서 외부로 나갑니다
curl https://api.github.com
회사 방화벽(Firewall)은 직접 외부 접속을 막지만, 프록시를 통한 접속은 허용합니다. 프록시가 로그를 남기고 필터링할 수 있으니까요.
그런데 문제는 모든 프로그램이 환경변수를 존중하는 건 아니라는 겁니다. Git은 따로 설정해줘야 합니다.
git config --global http.proxy http://proxy.company.com:8080
git config --global https.proxy http://proxy.company.com:8080
Python pip도 마찬가지입니다.
pip install --proxy http://proxy.company.com:8080 requests
매번 이렇게 하기 귀찮아서 결국 .bashrc에 다 박아뒀습니다.
통신사(ISP)가 프록시를 중간에 끼워 넣을 수 있습니다. 내가 프록시 설정을 안 했는데도 말이죠. 이게 Transparent Proxy입니다.
예를 들어 통신사가 트래픽을 모니터링하거나, 특정 사이트를 차단하거나, 캐싱해서 대역폭을 절약하려고 쓰는 겁니다. 사용자 입장에선 프록시가 있는지도 모릅니다. 그래서 "Transparent(투명한)"라는 이름이 붙었습니다.
저도 한국에서 어떤 사이트 접속이 막혔는데, VPN 켜니까 되더라고요. 나중에 알고 보니 통신사가 Transparent Proxy로 특정 사이트를 필터링하고 있었던 겁니다. VPN을 쓰면 암호화되어서 통신사가 내가 어디 접속하는지 못 보니까 우회가 된 거죠.
이게 와닿은 이유는, "프록시는 반드시 내가 설정하는 것"이라는 고정관념이 깨졌기 때문입니다. 네트워크 중간 어디서든 프록시를 끼워 넣을 수 있더라고요.
Reverse Proxy는 서버 앞에 있는 프록시입니다.
나 → 인터넷 → Reverse Proxy → 네이버 실제 서버들
내가 네이버에 접속하면, 사실은 Reverse Proxy에 접속하는 겁니다. Reverse Proxy가 내 요청을 받아서 뒤의 실제 서버(여러 대)에 전달합니다.
나는 실제 서버가 어디 있는지, 몇 대인지 모릅니다.서버가 10대 있는데, 사용자는 "naver.com" 하나만 봅니다. Reverse Proxy(Nginx)가 10대에 적절히 분산해서 보내줍니다.
upstream backend {
server 192.168.1.10;
server 192.168.1.11;
server 192.168.1.12;
}
server {
location / {
proxy_pass http://backend;
}
}
이게 없었다면 사용자가 직접 "192.168.1.10"으로 접속하거나, DNS에서 round-robin으로 IP를 돌려가면서 줘야 합니다. 그러면 한 서버가 죽었을 때 사용자한테 에러가 나죠. Reverse Proxy가 health check 해서 살아있는 서버로만 보내줍니다.
HTTPS는 암호화/복호화 비용이 듭니다. 10대 서버가 각각 HTTPS를 처리하면 비효율적이니, Reverse Proxy가 한 번만 복호화하고 내부는 HTTP로 통신합니다.
사용자 ← HTTPS → Reverse Proxy ← HTTP → 실제 서버
SSL 인증서도 Reverse Proxy 하나에만 설치하면 됩니다. 내부 서버 10대에 각각 인증서 설치하고 갱신하는 건 관리 지옥입니다.
실제 서버의 IP를 숨깁니다. 공격자는 Reverse Proxy만 보게 되고, 뒤의 실제 서버는 보호됩니다. DDoS 공격도 Reverse Proxy에서 1차 방어할 수 있습니다. Cloudflare 같은 CDN도 사실 거대한 Reverse Proxy 네트워크입니다.
정적 파일(이미지, CSS)은 Reverse Proxy가 캐싱해서 빠르게 응답합니다. 실제 서버까지 갈 필요가 없죠. Nginx는 캐싱 기능이 뛰어나서 정적 파일 서빙을 Nginx에 맡기고, 동적 요청만 백엔드로 보내는 구조를 많이 씁니다.
Cloudflare나 AWS CloudFront 같은 CDN(Content Delivery Network)도 알고 보면 Reverse Proxy의 일종입니다. 내 서버가 한국에 있어도, 미국 사용자는 미국에 있는 CDN 서버(Reverse Proxy)에 접속합니다. CDN이 내 서버에서 콘텐츠를 가져와서 캐싱해두고 빠르게 응답하는 거죠.
결국 CDN도 "서버 앞에 있는 대리인"이라는 점에서 Reverse Proxy와 똑같습니다. 이걸 이해하고 나니까 CDN 설정할 때도 "아, 이건 Reverse Proxy 설정이랑 비슷하네"라는 생각이 들더라고요.
제 서비스에서 Nginx를 Reverse Proxy로 썼습니다.
server {
listen 80;
server_name myapp.com;
# 정적 파일은 Nginx가 직접 서빙
location /static/ {
alias /var/www/static/;
}
# API 요청은 백엔드로 전달
location /api/ {
proxy_pass http://localhost:3000;
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;
}
}
사용자는 myapp.com으로만 접근하지만, /static/ 요청은 Nginx가 직접 처리하고, /api/ 요청은 Node.js 서버(3000번 포트)로 전달합니다.
하나의 도메인으로 여러 서비스를 묶을 수 있습니다. 프론트엔드는 /, API는 /api/, 관리자 페이지는 /admin/ 이런 식으로 분리해서 각각 다른 서버로 보낼 수 있습니다.
X-Real-IP나 X-Forwarded-For 헤더를 넘겨주는 이유는, 백엔드 입장에선 모든 요청이 Nginx(localhost)에서 오는 것처럼 보이기 때문입니다. 실제 사용자의 IP를 알려면 이런 헤더를 봐야 합니다.
처음 MSA(Microservices Architecture)를 공부할 때 API Gateway라는 개념이 나왔습니다. "사용자 요청을 적절한 마이크로서비스로 라우팅한다"고 하더라고요. 그런데 이것도 결국 Reverse Proxy였습니다.
예를 들어 내 서비스에 인증 서버, 결제 서버, 상품 서버가 따로 있다면:
사용자 → API Gateway → /auth 요청 → 인증 서버
→ /payment 요청 → 결제 서버
→ /product 요청 → 상품 서버
API Gateway가 경로를 보고 적절한 서버로 요청을 보냅니다. 이게 바로 Reverse Proxy의 라우팅 기능입니다.
Kong, AWS API Gateway, Spring Cloud Gateway 같은 걸 공부할 때 "이게 Nginx랑 뭐가 다르지?"라고 생각했는데, 결국 핵심은 같더라고요. API Gateway는 Reverse Proxy에 인증, rate limiting, 로깅 같은 기능을 추가한 거였습니다.
| 항목 | Forward Proxy | Reverse Proxy |
|---|---|---|
| 위치 | 클라이언트 앞 | 서버 앞 |
| 보호 대상 | 클라이언트 | 서버 |
| 누가 설정 | 클라이언트가 설정 | 서버 관리자가 설정 |
| IP 숨김 | 클라이언트 IP 숨김 | 서버 IP 숨김 |
| 주요 용도 | 우회, 익명화, 캐싱 | 로드밸런싱, SSL, 보안 |
| 예시 | 회사 Proxy, VPN | Nginx, Cloudflare |
이 표를 정리해본 뒤로 헷갈리지 않게 됐습니다. "누가 설정하느냐"를 보면 금방 구분이 됩니다. 내가 설정하면 Forward, 서버 관리자가 설정하면 Reverse입니다.
둘 다 "내 IP를 숨긴다"는 점은 같지만, 작동 방식이 다릅니다.
VPN은 게임 트래픽, 이메일, 심지어 DNS 쿼리까지 다 VPN 서버를 거칩니다. 하지만 Forward Proxy는 웹 브라우저나 curl처럼 프록시를 지원하는 애플리케이션만 프록시를 씁니다.
VPN이 더 강력하지만 느릴 수 있고, Forward Proxy는 가볍지만 HTTP만 커버합니다. 저는 해외 출장 갈 때는 VPN 쓰고, 회사 내부망에서 개발할 때는 Forward Proxy 씁니다.
프로젝트에서 Docker 컨테이너 안에서 npm install이 안 됐습니다. 알고 보니 Docker는 호스트의 환경변수를 자동으로 안 가져가더라고요.
# Dockerfile에 명시해야 했습니다
ENV http_proxy=http://proxy.company.com:8080
ENV https_proxy=http://proxy.company.com:8080
이걸 몰라서 하루 종일 삽질했습니다. 호스트에서는 npm install이 잘 되는데 Docker 안에서만 안 되는 거예요. 결국 Docker 문서를 뒤져서 알아냈습니다.
Reverse Proxy로 쓰던 Nginx에서 502 에러가 났습니다. 알고 보니 백엔드 서버가 localhost:3000이 아니라 127.0.0.1:3000으로 올라가 있었습니다.
Docker 네트워크에서는 localhost가 컨테이너 자기 자신을 가리키므로, host.docker.internal:3000으로 바꿔야 했습니다.
# 이렇게 하면 안 됩니다 (Docker 환경에서)
proxy_pass http://localhost:3000;
# 이렇게 해야 합니다
proxy_pass http://host.docker.internal:3000;
이것도 한참 헤맸습니다. Nginx 로그를 봐도 "Connection refused"만 뜨고, 백엔드는 멀쩡히 돌아가고 있는데 왜 안 되는 건지 이해가 안 갔거든요.
회사 프록시를 거쳐서 다시 외부 프록시를 거쳐야 하는 경우가 있었습니다. 이걸 Proxy Chaining이라고 합니다.
내 PC → 회사 Proxy → 외부 Proxy → 인터넷
문제는 대부분의 프록시가 체인을 지원하지 않는다는 겁니다. 회사 프록시 설정에 외부 프록시를 넣으려고 했는데 안 되더라고요. 결국 SSH 터널링으로 우회했습니다.
# 회사 프록시를 거쳐서 외부 서버에 SSH 접속
ssh -o "ProxyCommand nc -X connect -x proxy.company.com:8080 %h %p" user@external-server
# 그리고 SOCKS 프록시 설정
ssh -D 1080 -o "ProxyCommand nc -X connect -x proxy.company.com:8080 %h %p" user@external-server
이렇게 하면 localhost:1080이 외부 서버를 거치는 SOCKS 프록시가 됩니다. 복잡하지만 어쩔 수 없었습니다.
프록시 서버가 인증을 요구할 때도 있습니다. 회사 프록시가 그랬습니다.
# 아이디/비밀번호가 필요한 경우
export http_proxy=http://username:password@proxy.company.com:8080
문제는 비밀번호에 특수문자가 들어가면 URL 인코딩을 해줘야 한다는 겁니다. 비밀번호가 P@ssw0rd!라면 P%40ssw0rd%21로 바꿔야 합니다. 이것도 몰라서 한참 헤맸습니다.
Nginx 말고 HAProxy도 많이 씁니다. 특히 로드 밸런싱과 health check 기능이 강력합니다.
frontend http_front
bind *:80
default_backend http_back
backend http_back
balance roundrobin
option httpchk GET /health
server server1 192.168.1.10:3000 check
server server2 192.168.1.11:3000 check
server server3 192.168.1.12:3000 check
option httpchk로 /health 엔드포인트를 주기적으로 체크해서, 응답이 없는 서버는 자동으로 제외합니다. Nginx도 Plus 버전에서는 되지만, 무료 버전에서는 안 됩니다. HAProxy는 무료입니다.
그리고 mTLS(Mutual TLS)를 Reverse Proxy에서 구현하는 경우도 있습니다. 클라이언트와 서버가 서로 인증서를 검증하는 거죠. 금융권에서 많이 씁니다.
server {
listen 443 ssl;
ssl_certificate /path/to/server.crt;
ssl_certificate_key /path/to/server.key;
# 클라이언트 인증서 요구
ssl_client_certificate /path/to/ca.crt;
ssl_verify_client on;
location / {
proxy_pass http://backend;
}
}
이렇게 하면 올바른 클라이언트 인증서를 가진 사람만 접근할 수 있습니다. 내부 API나 관리자 페이지 보호할 때 유용합니다.
프록시를 이해하면서 배운 핵심을 정리해봅니다.
이렇게 한 줄씩 정리해본다고 해서 당장 실제로 프록시를 완벽하게 설계할 수 있는 건 아닙니다. 하지만 적어도 "프록시는 뭐하는 거지?"라는 질문에는 명확히 답할 수 있게 됐습니다.
처음엔 "프록시 설정 안 하면 안 되는구나" 정도만 알았지만, 지금은 Nginx로 Reverse Proxy를 직접 운영하며 그 중요성을 체감하고 있습니다. 서버 여러 대를 하나의 도메인으로 묶고, HTTPS를 한 곳에서 관리하고, 정적 파일은 캐싱해서 빠르게 서빙하는 게 다 Reverse Proxy 덕분입니다.
결국 이거였다고 받아들였습니다. 프록시는 "대리인"이고, 그 대리인이 누구 편이냐에 따라 Forward와 Reverse로 나뉜다는 것. 이 개념을 이해하고 나니 네트워크 아키텍처 설계할 때 자연스럽게 프록시를 고려하게 됩니다.