Nginx 리버스 프록시 설정하는 법 5단계
- Nginx가 외부 요청을 내부 애플리케이션으로 전달합니다.
- proxy_pass 끝의 슬래시는 URL 경로 결과를 바꿉니다.
- 애플리케이션이 원본 요청 정보를 필요로 할 때 Host·X-Forwarded 헤더를 전달합니다.
- 설정 검사와 로그 확인으로 502 오류를 빠르게 좁힙니다.
Nginx 리버스 프록시는 사용자가 접속하는 도메인과 내부 애플리케이션 포트를 분리하는 설정입니다. 예를 들어 사용자는 https://example.com으로 접속하고, Nginx는 같은 서버 또는 내부 네트워크의 127.0.0.1:3000, Docker 서비스명, 다른 서버로 요청을 전달합니다. 핵심은 proxy_pass와 애플리케이션이 필요로 하는 원본 요청 정보의 전달이며, 설정을 바꾼 뒤에는 반드시 문법 검사 후 graceful reload를 수행하는 것입니다.
아래 예시는 Ubuntu·Debian 계열에서 흔한 사이트별 설정 구조를 기준으로 설명하지만, RHEL 계열처럼 설정 파일 위치가 다른 환경도 지시어의 의미는 같습니다. 운영 환경에서는 배포판 패키지가 사용하는 include 구조를 먼저 확인하세요.
리버스 프록시가 필요한 이유와 동작 방식

클라이언트와 업스트림의 역할
리버스 프록시는 클라이언트 요청을 먼저 받은 뒤 업스트림(upstream, 실제 응답을 만드는 뒤쪽 서버)에 전달하고 응답을 다시 돌려줍니다. 애플리케이션이 Node.js, Spring Boot, Python 등 무엇으로 실행되든 외부에는 Nginx의 80·443 포트만 노출할 수 있습니다. 따라서 애플리케이션 포트를 직접 공개하지 않고, 도메인·TLS 인증서·접근 제한을 입구에서 일관되게 처리할 수 있습니다.
포워드 프록시와 구분하기
포워드 프록시는 사용자를 대신해 외부 서버에 요청하는 중계 서버입니다. 반대로 리버스 프록시는 서버 측에 배치되어 여러 백엔드의 앞단 역할을 합니다. 경로별 라우팅, 정적 파일 처리, TLS 종료, 요청 크기 제한, 로드 밸런싱은 리버스 프록시에서 자주 함께 구성하는 기능입니다.
외부에는 Nginx만 공개하고 백엔드는 사설 네트워크 또는 localhost에 바인딩하는 구성이 일반적입니다. 단, Docker 환경에서는 Nginx 컨테이너가 백엔드에 접근할 수 있도록 서비스명·네트워크·애플리케이션 바인딩 주소를 함께 확인해야 합니다.
Nginx 리버스 프록시 설정 방법: 5단계

1단계: 백엔드가 실제로 응답하는지 확인합니다
먼저 Nginx를 거치지 않고 백엔드 자체가 정상인지 확인합니다. 같은 호스트에서 실행한다면 curl -i http://127.0.0.1:3000/처럼 점검합니다. 응답이 없거나 연결이 거부되면 Nginx 설정보다 애플리케이션 실행 상태, 리스닝 포트, 방화벽, 바인딩 주소를 먼저 해결해야 합니다.
- 애플리케이션 프로세스 또는 컨테이너가 실행 중인지 확인합니다.
- 백엔드 포트에서 HTTP 응답이 오는지 확인합니다.
- 다른 컨테이너가 접속해야 한다면
127.0.0.1전용 바인딩인지 점검합니다.
2단계: 서버 블록 파일을 만듭니다
Ubuntu·Debian에서는 보통 /etc/nginx/sites-available/example.com에 서버 블록을 만들고 sites-enabled에 심볼릭 링크로 활성화합니다. 이미 기본 사이트가 같은 listen 80과 도메인을 처리한다면 충돌하지 않도록 비활성화 또는 수정해야 합니다. RHEL 계열은 흔히 /etc/nginx/conf.d/ 아래의 .conf 파일을 사용합니다.
3단계: proxy_pass와 전달할 헤더를 설정합니다
다음은 한 도메인의 모든 요청을 로컬 3000번 포트로 전달하는 최소 구성입니다. Host는 사용자가 요청한 호스트명, X-Real-IP는 Nginx에 연결한 클라이언트 주소, X-Forwarded-For는 프록시를 거친 IP 목록, X-Forwarded-Proto는 Nginx가 받은 요청의 HTTP 또는 HTTPS 스킴을 백엔드에 알려 줍니다.
server {
listen 80;
server_name example.com www.example.com;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
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;
}
}
위 헤더가 모든 환경에서 필수라는 뜻은 아닙니다. 백엔드가 원본 호스트·클라이언트 IP·요청 스킴을 알아야 할 때 필요한 값을 선택해 전달하세요. 백엔드가 별도 서버 또는 Docker Compose 서비스라면 127.0.0.1:3000 대신 해당 서버의 사설 주소 또는 동일 Docker 네트워크의 서비스명과 포트를 사용합니다. 공식 지시어별 동작은 NGINX Proxy Module 문서에서 확인할 수 있습니다.
4단계: 문법을 검사하고 안전하게 반영합니다
설정 저장 뒤에는 즉시 재시작하지 말고 문법과 include된 전체 구성을 검사합니다. 검사가 성공하면 reload로 워커 프로세스가 새 구성을 적용하도록 합니다. 오류가 나온다면 표시된 파일과 줄 번호를 먼저 수정한 뒤 다시 검사합니다.
sudo nginx -t로 전체 설정 문법과 참조 파일을 검사합니다.- 성공 메시지를 확인한 뒤
sudo systemctl reload nginx를 실행합니다. - 도메인과 백엔드 경로를 각각 요청해 상태 코드와 응답 헤더를 확인합니다.
5단계: 외부 요청 기준으로 검증합니다
서버 안의 curl만 성공했다고 외부 공개가 완료된 것은 아닙니다. DNS가 올바른 서버를 가리키는지, 클라우드 보안 그룹·호스트 방화벽에서 80 또는 443 포트를 허용했는지, HTTPS를 쓴다면 인증서와 서버 블록이 도메인에 맞는지 확인합니다. 백엔드 포트는 가능하면 인터넷에 직접 열지 않는 편이 안전합니다.
경로 프록시에서 가장 많이 틀리는 슬래시 규칙

location과 proxy_pass의 조합을 먼저 계산합니다
location /api/에서 proxy_pass 마지막의 슬래시 하나는 요청 URI 전달 결과를 바꿉니다. 이 차이를 놓치면 백엔드가 기대하지 않은 경로를 받아 404가 나거나, API 접두사가 중복될 수 있습니다.
| Nginx 요청 경로 | proxy_pass 설정 | 백엔드에 전달되는 예 |
|---|---|---|
| /api/users | http://127.0.0.1:8080/ | /users |
| /api/users | http://127.0.0.1:8080 | /api/users |
| /app/users | http://127.0.0.1:8080/internal/ | /internal/users |
API와 화면 서비스를 분리하는 예시
프론트엔드는 루트로, API는 별도 백엔드로 전달하려면 location을 더 구체적으로 작성합니다. Nginx는 일반적으로 더 구체적인 접두사 location을 선택하므로 /api/ 규칙이 /보다 우선 적용됩니다.
location /api/ {
proxy_pass http://127.0.0.1:8080/;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
location / {
proxy_pass http://127.0.0.1:3000;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
}
백엔드 라우터가 /api 접두사까지 처리하도록 작성됐는지, 아니면 Nginx가 접두사를 제거해야 하는지를 먼저 정한 다음 슬래시 형태를 선택하세요. 설정을 추측으로 바꾸기보다 실제 요청 URL과 백엔드가 받은 URI를 로그로 비교하는 편이 빠릅니다.
HTTPS와 WebSocket을 함께 운영할 때

HTTPS 종료 뒤 원래 프로토콜을 전달합니다
TLS 종료는 브라우저와 Nginx 사이에서 HTTPS를 복호화하고, Nginx가 내부 백엔드에 요청을 전달하는 방식입니다. 이때 백엔드가 원래 요청을 HTTP로 오해하면 HTTPS 리다이렉트가 반복되거나 보안 쿠키가 제대로 설정되지 않을 수 있습니다. 따라서 X-Forwarded-Proto 전달과 애플리케이션의 프록시 신뢰 설정을 함께 검토해야 합니다.
인증서 발급·갱신은 사용하는 인증기관 도구의 공식 문서를 기준으로 진행하고, 갱신 뒤에는 테스트 환경에서 Nginx 설정 충돌 여부를 확인하세요. 인증서 파일 경로와 갱신 방식은 운영체제·배포 방식에 따라 달라질 수 있습니다.
WebSocket은 Upgrade 헤더가 필요합니다
채팅, 실시간 알림, 개발 서버 등 WebSocket 연결은 HTTP 연결을 업그레이드합니다. 일반 프록시 헤더만으로 연결이 끊긴다면 아래처럼 Upgrade와 Connection 헤더를 전달합니다. 아래 예시는 WebSocket 전용 경로에 적용하는 구성입니다.
location /socket/ {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
일반 HTTP 요청과 WebSocket을 같은 location에서 처리해야 한다면 Connection 값을 무조건 upgrade로 고정하지 말고, NGINX 공식 예시처럼 $http_upgrade 값을 map으로 검사해 조건부로 설정하세요.
HTTPS 환경에서 리다이렉트가 반복되면 Nginx의
X-Forwarded-Proto와 애플리케이션의 프록시 신뢰 설정을 함께 점검하세요. WebSocket 오류는proxy_http_version 1.1및 Upgrade 관련 헤더 누락이 원인일 수 있습니다.
502 Bad Gateway와 운영 점검 방법

502는 Nginx와 업스트림 사이를 우선 확인합니다
502 Bad Gateway는 Nginx가 업스트림으로부터 유효한 응답을 받지 못했을 때 주로 나타납니다. 브라우저 캐시를 먼저 의심하기보다 Nginx 오류 로그와 백엔드 로그의 같은 시각을 비교하세요. 대표적으로 연결 거부는 백엔드 미실행·잘못된 포트·localhost 바인딩 문제와 연관되고, 연결 시간 초과는 네트워크 경로·과부하·응답 지연을 점검해야 합니다.
sudo nginx -t로 적용 대상 설정에 문법 오류가 없는지 확인합니다.sudo tail -f /var/log/nginx/error.log로 upstream 연결 오류를 확인합니다.- Nginx 실행 위치에서 백엔드 주소로 curl 요청을 보내 네트워크 경로를 검증합니다.
- Docker라면 포트 공개 여부보다 Nginx와 백엔드가 같은 네트워크에서 서비스명으로 통신 가능한지 확인합니다.
타임아웃과 업로드 제한은 서비스 특성에 맞춥니다
파일 업로드나 오래 걸리는 응답이 있다면 기본값을 무작정 크게 늘리기보다 요청 유형별 location에서 필요한 범위만 조정합니다. client_max_body_size는 허용 업로드 크기, proxy_read_timeout은 업스트림에서 연속된 두 read 사이에 데이터를 기다리는 시간과 관계된 지시어입니다. 제한을 완화할 경우 메모리·연결 점유·악성 대용량 요청 위험도 같이 고려해야 하며, 요청 제한과 접근 제어도 함께 검토하세요.
배포 전 점검 체크리스트

설정 파일과 프로세스를 분리해 확인합니다
리버스 프록시 변경은 한 줄의 경로 차이로도 로그인, 정적 파일, 콜백 URL에 영향을 줄 수 있습니다. 운영 반영 전에는 백엔드 헬스 체크 URL, 대표 API, 로그인 후 리다이렉트, WebSocket 기능처럼 서비스에서 실제 사용하는 경로를 목록으로 검증하세요.
- 도메인별
server_name과 기본 서버 충돌 여부를 확인합니다. - 백엔드가 기대하는 경로와
proxy_pass의 슬래시 규칙을 대조합니다. - 원본 Host, 클라이언트 IP, HTTPS 스킴 헤더가 전달되는지 확인합니다.
nginx -t성공 후 reload하고, 오류 로그와 액세스 로그를 관찰합니다.- 비밀키·환경 변수·관리용 백엔드 포트가 외부에 노출되지 않았는지 확인합니다.
자주 묻는 질문
Q. Nginx 리버스 프록시와 로드 밸런서는 같은 기능인가요?
리버스 프록시는 요청을 백엔드로 전달하는 역할이며, 그 대상이 여러 대일 때 요청을 나누는 기능이 로드 밸런싱입니다. 한 대의 백엔드만 연결해도 리버스 프록시는 유효하게 사용할 수 있습니다.
Q. proxy_pass 뒤에 슬래시를 꼭 붙여야 하나요?
꼭 붙이는 것은 아닙니다. 슬래시 유무에 따라 location 접두사를 제거할지 여부가 달라지므로, 백엔드가 받아야 할 최종 URI를 기준으로 선택해야 합니다.
Q. Docker Compose에서는 localhost를 upstream으로 써도 되나요?
Nginx와 백엔드가 서로 다른 컨테이너라면 Nginx 컨테이너의 localhost는 백엔드 컨테이너가 아닙니다. 보통 같은 Compose 네트워크의 서비스명과 컨테이너 포트를 사용하며, 백엔드가 외부 인터페이스에서 수신하도록 바인딩됐는지도 확인해야 합니다.
Q. 설정을 수정한 뒤 restart 대신 reload를 써도 되나요?
문법 검사에 성공한 정상적인 설정 변경이라면 일반적으로 reload로 새 구성을 반영할 수 있습니다. Nginx는 reload 과정에서 새 설정을 검사하고 적용에 실패하면 기존 워커를 계속 실행하므로, 실패 여부와 오류 메시지를 확인한 뒤 운영 절차에 따라 점검하세요.
