개발자라면 한 번쯤 Nginx 설정 파일을 다뤄봤을 것이다. 대부분은 튜토리얼이나 기존 프로젝트의 nginx.conf를 복사해 약간 수정하는 방식으로 시작한다. 설정이 왜 그렇게 동작하는지 깊이 이해하기보다는, “일단 되니까” 넘어가는 경우가 많다.
하지만 이 설정들에는 애플리케이션의 안정성, 성능, 장애 가능성을 좌우하는 중요한 원리가 숨어 있다. 특히 몇몇 지시어는 아주 작은 차이로 전혀 다른 결과를 만든다. 이 글에서는 실무에서 가장 자주 문제가 되는 Nginx 설정 5가지를 정리한다. 끝까지 읽고 나면 Nginx 설정 파일을 바라보는 시선이 달라질 것이다.
1. 슬래시(/) 하나가 모든 것을 바꾼다: proxy_pass
proxy_pass 끝의 슬래시(/) 유무는 백엔드로 전달되는 요청 경로를 완전히 바꾼다. 이는 추측이 아니라 Nginx에 명확히 정의된 동작 규칙이다.
결론부터 정리
| 설정 | 백엔드로 전달되는 경로 |
| proxy_pass http://api:3000; | /api/foo → /api/foo |
| proxy_pass http://api:3000/; | /api/foo → /foo |
왜 중요한가
슬래시 유무에 따라 백엔드의 라우팅 설계 자체가 달라진다. 슬래시가 없으면 백엔드는 /api 경로를 포함해 처리해야 한다. 슬래시가 있으면 백엔드는 /api를 전혀 모른 채 /foo만 처리하면 된다. 이 둘을 맞추지 않으면 모든 API 요청이 404를 반환하는 문제가 발생한다.
핵심 원리 (공식 규칙)
proxy_pass에 URI가 포함되면, location에서 매칭된 URI를 해당 값으로 대체한다.
proxy_pass http://api:3000/;에서 끝의 /는 URI로 간주된다. 그 결과 /api/가 /로 치환되어 /foo만 백엔드로 전달된다.
도식으로 보면

2. SPA 배포의 핵심: try_files
SPA(React, Vue 등)를 배포할 때 try_files $uri $uri/ /index.html;은 거의 필수 설정이다.
SPA에서 발생하는 문제
SPA는 라우팅을 서버가 아니라 브라우저의 자바스크립트가 처리한다. /dashboard로 직접 접근하거나 새로고침하면 서버는 해당 파일을 찾지 못해 404를 반환한다.
try_files 동작 순서
- 요청한 파일이 있는지 확인
- 디렉터리가 있는지 확인
- 모두 없으면 index.html 반환
왜 이게 동작하는가
서버는 index.html만 내려준다. 주소창은 /dashboard 그대로 유지된다. 이후 SPA 라우터가 경로를 읽어 화면을 그린다. 즉, 서버의 404를 막고 라우팅 권한을 클라이언트로 넘긴다.
실무에서 가장 위험한 실수
try_files와 API 프록시를 같은 location /에 두는 경우다.
# ❌ 잘못된 예
location / {
try_files $uri $uri/ /index.html;
}
이 상태에서 /api/users를 요청하면 API가 아니라 index.html이 반환될 수 있다.
안전한 구조 예제
location /api/ {
proxy_pass http://api:3000/;
}
location / {
try_files $uri $uri/ /index.html;
}
3. server_name localhost는 보안 설정이 아니다
많은 개발자가 server_name localhost;를 “로컬에서만 접근 가능하다”라고 오해한다. 이는 사실이 아니다.
정확한 의미
- server_name은 Host 헤더 기준의 라우팅 규칙
- IP 접근 제어 기능이 아니다
왜 헷갈릴까
80 포트를 사용하는 서버 블록이 하나뿐이면 Host 값과 상관없이 그 서버가 모든 요청을 처리한다.
진짜 접근 제한 방법
| 목적 | 설정 |
| 로컬만 허용 | listen 127.0.0.1:80; |
| IP 제한 | allow 127.0.0.1; deny all; |
4. 백엔드 문맥을 지키는 한 줄: proxy_set_header Host $host
이 설정은 관습적인 코드가 아니라 필수 설정이다.
이 설정이 없으면
Host: api:3000
백엔드는 클라이언트가 어떤 도메인으로 접근했는지 알 수 없다.
발생 가능한 문제
- 잘못된 리다이렉트 URL 생성
- 도메인 기반 인증·보안 정책 실패
- 멀티 도메인 서비스 불가
기본 세트로 함께 쓰는 헤더
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;
이 헤더들은 백엔드가 리버스 프록시 뒤에 있다는 사실을 인지하게 해준다.
5. 같은 백엔드, 다른 목적: /api/와 /preview/
같은 백엔드 서버라도 트래픽 성격에 따라 프록시 설정은 달라져야 한다.
설정 목적 비교
| 항목 | /api/ | /preview/ |
| 용도 | REST API, WebSocket | 실시간 스트리밍 |
| WebSocket | 지원 | 미지원 |
| Buffering | 기본값 | 비활성화 |
| 응답 지연 | 일부 허용 | 최소화 |
왜 나눴을까
- /api/ : 일반 API와 WebSocket용. 기본 버퍼링이 성능에 유리하다.
- /preview/ : SSE, 로그 스트리밍용. 데이터가 생성되는 즉시 전달되어야 한다.
이처럼 경로별로 통신 특성에 맞춰 설정을 분리하는 것이 고급 Nginx 운영 방식이다.
실제 설정 예시
① /api/ – 일반 API + WebSocket용
location /api/ {
proxy_pass http://api: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;
# WebSocket 지원
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
# 기본 버퍼링 사용 (응답을 모아서 전달)
proxy_buffering on;
}
이 설정의 의도
- REST API 응답은 모두 준비된 후 전달되어도 문제가 없다.
- WebSocket 연결이 필요하므로 Upgrade, Connection 헤더를 허용한다.
기본 버퍼링은 응답 처리 효율과 성능에 도움이 된다.
② /preview/ – 실시간 스트리밍(SSE, 로그 스트림 등)
location /preview/ {
proxy_pass http://api: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;
# 실시간 전송을 위한 핵심 설정
proxy_buffering off;
proxy_cache off;
# WebSocket 의도적 비활성화
proxy_set_header Connection "";
# 응답 지연 최소화
chunked_transfer_encoding off;
}
이 설정의 의도
- SSE나 로그 스트리밍은 데이터가 생성되는 즉시 클라이언트로 전달되어야 한다.
- proxy_buffering off는 Nginx가 데이터를 모으지 않고 바로 흘려보내게 만든다.
WebSocket을 비활성화해 이 경로가 비-WebSocket 스트리밍 전용임을 명확히 한다.
왜 이렇게 나누는가
같은 백엔드 서버라도 트래픽 성격은 완전히 다를 수 있다.
- API 요청은 “빠른 응답”이 중요하다.
- 스트리밍 요청은 “지연 없는 전달”이 핵심이다.
이를 하나의 location에서 처리하면 API는 불필요하게 느려지고 스트리밍은 심각한 지연이 발생한다.
경로별로 프록시 전략을 분리하는 것이 안정적인 설계 방법이다.
마무리
Nginx 설정은 복사해서 쓰는 마법 코드가 아니다. 슬래시 하나, 헤더 한 줄이 라우팅·보안·성능·장애 가능성을 바꾼다. 각 지시어의 역할을 이해하는 순간, Nginx는 단순한 웹 서버가 아니라 강력한 트래픽 제어 도구가 된다.
이젠 nginx.conf, 예전과 다르게 보이지 않는가?
'잡(job)기술' 카테고리의 다른 글
| 데이터베이스 성능의 핵심, 복합 인덱스를 이해하는 4가지 포인트 (1) | 2026.02.04 |
|---|---|
| 데이터 무결성을 지키는 마지막 방어선 - TypeORM Entity 설계의 5가지 핵심 포인트 (3) | 2026.02.03 |
| React 프로젝트를 200% 효율적으로 만드는 4가지 핵심 원칙 (0) | 2026.02.01 |
| 복사-붙여넣기 하던 NestJS 명령어 - 그 속에 숨겨진 5가지 의미 (0) | 2026.02.01 |
| 도커 헬스체크, Up 상태만 믿고 있지 않은가? (0) | 2026.02.01 |