와, 아키텍처 고민하는 거 자체가 벌써 실력 늘고 있다는 증거 같아요.
작은 프로젝트 여러 개 띄우는 단계에서 리버스 프록시로 묶으려는 거, 정말 표준적이고 현명한 접근입니다.
거의 모든 회사나 서비스들이 이 구조를 기본으로 깔고 가거든요.
질문 주신 내용이 '도메인 기반 요청 분기'와 '유지보수성' 두 가지 축으로 보이니까, 이 두 가지 관점에서 실질적으로 써보신 분들 위주로 경험 공유 드릴게요.
일단 결론부터 말씀드리면, Nginx의 server 블록과 location 블록을 조합해서 사용하시는 게 가장 일반적이고 강력한 방법입니다.
하지만 단순히 문법만 나열하기보다, '어떤 상황에서 어떻게 분기할지'에 초점을 맞춰서 설명드리는 게 실질적인 도움이 될 것 같네요.
--- ### 1.
도메인 기반 분기 (가장 흔한 시나리오: a.com vs b.com) 이건 Nginx가 가장 기본적으로 잘 처리해주는 부분이에요.
요청이 들어올 때 Host 헤더를 보고 어떤 server 블록을 사용할지 결정하거든요.
[기본 구조 예시] nginx server { listen 80; server_name api.myproject.com; # <-- 이 도메인으로 들어온 모든 요청 return 301 https://$host$request_uri; # HTTPS 강제 리다이렉트 (필수) } server { listen 80; server_name www.myproject.com; # <-- 이 도메인으로 들어온 모든 요청 # 웹 앱(예: React/Vue 빌드물)이 돌아가는 경우 root /var/www/web-app/html; index index.html; try_files $uri $uri/ /index.html; # SPA(Single Page Application) 처리에 필수 } server { listen 80; server_name api.myproject.com; # <-- API 전용 도메인 location / { # 백엔드 API 서버 (예: Node.js, Django 등)가 3000 포트로 돌아간다고 가정 proxy_pass http://backend_api_server: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; } } [실무 팁 및 주의사항] 1.
server_name의 중요성: server_name을 명확하게 지정하는 것이 핵심입니다.
만약 server_name을 안 적거나 너무 광범위하게 잡으면, 나중에 다른 서비스가 들어왔을 때 충돌하거나 예상치 못한 곳으로 트래픽이 갈 수 있어요.
2.
HTTPS/SSL: 이건 선택이 아니라 필수입니다.
무조건 80 포트에서 443 포트로 리다이렉트 처리하는 로직을 가장 상위 레벨에 하나 만들어 두는 걸 추천합니다.
(Let's Encrypt 같은 걸 사용하실 거라 생각합니다.) 3.
헤더 전달: proxy_set_header 설정은 절대 건너뛰지 마세요.
백엔드 서버가 요청의 실제 출처 IP(X-Real-IP)나 원본 호스트(Host)를 알 수 있게 해주려면 이 헤더들을 제대로 전달해줘야 합니다.
안 그러면 로그만 이상하게 찍힐 수 있습니다.
--- ### 2.
경로 기반 분기 (같은 도메인 내에서 분기: a.com/api vs a.com/web) 만약 도메인을 하나로 통일하고, 경로(Path)로 분기하고 싶을 때가 생길 거예요.
이게 질문자님이 생각하신 'API 서버'와 '웹 앱'이 같은 도메인 밑에 있을 때의 시나리오입니다.
[구조 예시] nginx server { listen 80; server_name myproject.com; # <-- 단일 도메인 # 1. API 요청 분기 (예: /api/v1/users) location /api/ { # /api/ 로 들어오는 모든 요청은 3000 포트의 API 서버로 보냄 proxy_pass http://backend_api_server:3000; proxy_set_header Host $host; # ... 기타 헤더들 } # 2. 웹 앱 요청 분기 (예: /dashboard, /about 등) location / { # 루트(/)로 들어오는 요청부터는 웹 앱의 정적 파일/SPA 라우팅 처리 root /var/www/web-app/html; index index.html; try_files $uri $uri/ /index.html; } } [유지보수성 관점에서의 팁] 1.
location 블록의 우선순위: Nginx는 location 블록을 매칭할 때 일종의 우선순위 규칙을 따릅니다.
- 가장 구체적인 매칭(
location = /api)이 가장 높은 우선순위를 가집니다.
- 특정 접두사 매칭(
location /api/)이 일반적인 매칭(location /)보다 우선합니다.
- 만약
location /api/를 먼저 정의하고, 그 뒤에 location /을 정의하면, /api/users 요청은 첫 번째 location에 걸리고, /about 요청은 두 번째 location에 걸리게 됩니다.
정리 원칙: 요청을 받으면 가장 특수하고 명확한 경로(API, 관리자 페이지 등)를 먼저 정의하고, 그 다음 **가장 일반적인 기본값(웹 앱의 루트)**을 마지막에 두는 것이 유지보수에 가장 좋습니다.
3.
경로 변환 문제 (Trailing Slash): 이게 제일 흔한 실수입니다.
- 만약
location /api/로 설정하고 proxy_pass http://backend_api_server:3000/v1/ 처럼 뒤에 슬래시를 붙이면, Nginx는 요청 경로의 나머지 부분(users 등)을 버리고 /v1/ 까지만 보내버릴 수 있어요.
- 가장 안전한 방법:
location /api/ 로 잡고, proxy_pass http://backend_api_server:3000; 처럼 백엔드 주소 끝에 슬래시를 붙이지 않는 것입니다.
이렇게 하면 요청 경로 전체(/api/users/123)가 그대로 백엔드로 전달됩니다.
--- ### 3.
아키텍처 설계 관점에서 고려할 점 (이게 중요!) 질문자님은 '게이트웨이 역할'을 염두에 두고 계시니, 이건 단순한 프록시를 넘어선 고민이 필요해요.
A.
API 게이트웨이 관점 (권장) 만약 나중에 서비스가 커지면, Nginx 레벨에서 단순 프록시를 넘어 API 게이트웨이의 역할을 고민해보시는 게 좋습니다.
- Nginx의 한계: Nginx는 기본적으로 '패스스루(Pass-through)' 역할에 강합니다.
요청을 받아서 -> 다른 곳으로 보내주는 역할이죠.
- 게이트웨이의 역할: 게이트웨이는 요청을 받아서 '요청 자체를 가로채서' 뭔가 처리할 수 있어야 해요.
예를 들어, 요청이 오기 전에 JWT 토큰 유효성 검사, 속도 제한(Rate Limiting), 로깅/모니터링 등을 추가할 수 있어야 하죠.
- 대안: 이 정도 수준의 복잡한 로직(토큰 검사 등)이 필요하다면, Nginx만 고집하기보다 Kong, Tyk, 혹은 Spring Cloud Gateway 같은 전용 게이트웨이 솔루션을 알아보시는 것도 방법입니다.
물론 당장 몇 개만 돌리신다면 Nginx의 http 블록 내에서 map이나 rewrite 지시자를 복잡하게 써서 어느 정도는 구현 가능하지만, 코드가 너무 지저분해지기 쉽습니다.
B.
환경 변수 및 설정 관리 (유지보수성 극대화) 여러 프로젝트를 돌릴 거면, 설정 파일이 너무 길어지거나 변수가 많아져서 관리하기 힘들 거예요.
- YAML/JSON 기반 설정 분리: 프로젝트별 설정을 Nginx 설정 파일 자체에 하드코딩하지 마시고, 별도의
config/ 디렉토리에 프로젝트명별로 YAML이나 JSON 파일로 관리하는 걸 추천합니다.
- 스크립트 활용: 배포 시, 이 설정 파일을 읽어서 Nginx의
server 블록 내용을 동적으로 생성하거나, nginx -t 검증 전에 템플릿 엔진(Jinja2 같은 거)을 이용해 최종 nginx.conf를 짜는 스크립트를 돌리는 것이 장기적으로 가장 깔끔합니다.
--- ### 요약 정리 및 체크리스트 1.
도메인 분기: server_name을 이용해 명확하게 분리하세요.
(가장 깔끔함) 2.
경로 분기: location 블록의 우선순위와 경로 변환(proxy_pass 끝 슬래시 유무)에 가장 유의하세요.
보안: HTTPS는 무조건 적용하고, proxy_set_header는 필수적으로 넣어주세요.
4.
확장성: 나중에 토큰 검사 같은 로직이 필요하다면, Nginx만으로는 한계가 오니 전용 게이트웨이 솔루션 도입을 염두에 두세요.
이 정도면 어느 정도 큰 그림을 잡으실 수 있을 거라고 봅니다.
일단 지금은 위에서 설명드린 도메인/경로 분기 구조로 시작하시면서, 트래픽이 늘어나거나 '이거 처리하는 게 너무 짜증 나네?' 싶은 지점이 생길 때마다 아키텍처를 한 단계 업그레이드한다고 생각하시면 됩니다.
궁금한 점 있으면 언제든지 다시 질문해주세요!
화이팅입니다!