카테고리 없음
(인프라) NGINX + CORS + Reverse Proxy 완전 정리
불광동 물주먹
2025. 6. 25. 18:51
🌐 NGINX + CORS + Reverse Proxy 완전 정리
이 글은 실무 개발자와 블로그 작성을 위해, **CSR (Client Side Rendering, React 등)**과 SSR (Server Side Rendering, JSP 등) 환경에서 발생할 수 있는 CORS 문제, Reverse Proxy의 필요성, 그리고 NGINX 설정과 역할에 대해 깊게 정리한 문서입니다.
1. CORS란?
- **CORS (Cross-Origin Resource Sharing)**는 브라우저 보안 정책 중 하나로, JS에서 API 요청 시 출처(origin)가 다르면 차단합니다.
- 출처는 프로토콜 + 도메인 + 포트 조합이 일치해야 동일 출처로 인정됩니다.
🔹 브라우저는 어떤 기준으로 CORS를 판단하는가?
- 오직 브라우저 주소창의 출처 기준으로 판단함
- 서버가 내부적으로 어디에서 응답을 생성했는지 (예: NGINX냐 톰캣이냐)는 브라우저가 알 수 없음
2. JSP (SSR) vs React (CSR) 비교 + CORS 발생 여부
항목 | JSP (SSR) | React (CSR) |
렌더링 위치 | 서버 (WAS, 톰캣) | 브라우저 (React 실행 시 JS가 API 요청) |
HTML 생성 | 서버가 요청 시점에 동적으로 생성 | React가 build된 정적 HTML+JS로 브라우저에 전달 |
API 요청 | 서버 내부에서 처리 (같은 출처) | 브라우저에서 별도 API 서버로 요청 (출처 다를 수 있음) |
CORS 발생 | ❌ 거의 없음 (동일 서버 내 처리) | ✅ 자주 발생함 (출처가 다를 가능성 높음) |
🔸 왜 JSP는 CORS가 안 나는가?
- 브라우저는 단순히 https://myapp.com/page.jsp에 요청하고, HTML을 응답 받음
- 이 HTML은 내부적으로 WAS가 만들든, 프론트 서버에서 받든 브라우저 기준으로는 같은 도메인에서 받은 것으로 간주
- 단, JSP 내에서 JS로 외부 API(fetch('https://api.other.com')) 요청 시에는 CORS 발생 가능
🔸 CSR은 왜 CORS가 나는가?
- 브라우저가 React 정적 파일을 NGINX로부터 받음 → JS가 실행되며 API 요청 발생
- API 서버 도메인이 다르면 브라우저는 출처 다름으로 간주 → CORS 차단
3. NGINX와 프록시 관련 개념들
🔹 React 배포 환경에서 NGINX는 어떤 역할을 하나?
- 정적 파일 (build 결과물: index.html, js, css 등)을 서빙
- /api 등의 경로로 오는 요청을 Spring Boot API 서버로 리버스 프록시 처리
- 브라우저 기준: 모든 요청은 https://myapp.com으로 보내므로 출처 같음 → CORS 발생 안 함
🔹 React 개발 환경에서는?
- React 개발 서버 (localhost:3000)
- Spring Boot 서버 (localhost:8080)
- 브라우저 기준: 출처 다름 → CORS 발생
- 해결: package.json에 proxy 속성으로 프록시 설정 (Forward Proxy처럼 동작)
{
"proxy": "http://localhost:8080"
}
4. 운영 환경에서 리버스 프록시로 CORS 회피하기
🔹 도메인 기반으로 경로 구분 규약 정의하기
프론트에서는 아래처럼 경로를 명확히 분리해서 요청:
fetch('/naver/search?query=cat')
fetch('/toss/pay')
NGINX에서는 이 요청을 실제 API 서버로 리버스 프록시:
location /naver/ {
proxy_pass https://openapi.naver.com/;
proxy_set_header Host openapi.naver.com;
}
location /toss/ {
proxy_pass https://api.tosspayments.com/;
proxy_set_header Host api.tosspayments.com;
}
🔹 proxy_pass 슬래시(/) 유무에 따른 경로 전달 차이
설정 | 실제 전달 경로 | 설명 |
proxy_pass https://api.com/; | /naver/query → https://api.com/query | ✅ prefix 제거됨 |
proxy_pass https://api.com; | /naver/query → https://api.com/naver/query | ❌ prefix 포함됨 |
→ 그래서 반드시 슬래시(/)를 붙여줘야 프록시 경로 앞에 붙인 /naver, /toss 등의 구분자가 API 서버로 전달되지 않음.
5. Reverse Proxy vs Forward Proxy 개념 차이
구분 | Forward Proxy (개발용) | Reverse Proxy (운영용) |
위치 | 클라이언트(브라우저) 앞단 | 서버(NGINX 등) 앞단 |
역할 | 브라우저 대신 요청을 백엔드로 전달 | 클라이언트 요청을 서버에서 받아 백엔드로 전달 |
예시 | React 개발 서버 proxy 설정 | NGINX의 proxy_pass 설정 |
사용 목적 | 개발 시 CORS 회피 | 배포 시 출처 일치 유지, 보안, 라우팅, 성능 분산 |
✅ 핵심 요약
- CORS는 브라우저 보안 정책: JS에서 요청 시 출처 다르면 차단
- JSP는 서버가 HTML을 만들어 주므로 출처가 같고 CORS 발생 안 함
- React는 클라이언트에서 API 서버로 요청하므로 CORS 발생 가능
- 개발 중엔 Forward Proxy (package.json의 proxy)
- 운영 환경에선 반드시 NGINX를 통한 Reverse Proxy로 CORS 우회
- proxy_pass 설정 시 슬래시(/) 유무로 경로 전달 방식 달라짐 → 잘못하면 /naver 포함돼 API 깨짐