nginxリバースプロキシを構成する
한국어 원문으로 표시합니다.
목표
nginx 를 리버스프록시로 구성하고, 전달 헤더·타임아웃·본문 크기·압축·정적 분리· 접근 차단·로그 포맷을 실무 기준으로 설정할 수 있게 됩니다.
왜 중요한가
프록시 설정 여섯 줄은 외우는 게 아니라 없을 때 무슨 일이 나는지로 기억해야 합니다.
Host 를 안 넘기면 애플리케이션이 만드는 절대 URL 이 127.0.0.1:8080 이 되어
결제 콜백이 안 돌아옵니다. X-Forwarded-For 가 없으면 접속 이력이 전부 프록시 IP 라
감사에서 답할 말이 없습니다. X-Forwarded-Proto 가 없으면 리다이렉트 무한 루프가 납니다.
그리고 client_max_body_size 기본값 1MB 를 모르면, 백엔드 로그에 아무것도 안 남는
파일 업로드 장애로 며칠을 씁니다.
단계
- 준비: Tomcat 을 기동하고
/opt/lab/samples/labhub-1.0.0.war를/opt/tomcat/webapps/labhub.war로 배포해 두세요. nginx 작업 디렉터리는/root/ng를 씁니다. /root/ng/nginx.conf를 작성하고 nginx 를 기동합니다. 8088 포트로 listen 하고/를http://127.0.0.1:8080으로 프록시합니다.http://127.0.0.1:8088/labhub/version이 200 이어야 합니다.- 프록시 헤더 네 개를 설정하고 reload 합니다.
Host,X-Real-IP,X-Forwarded-For,X-Forwarded-Proto. 확인:curl -s http://127.0.0.1:8088/labhub/echo의 JSON 에x-forwarded-for와x-forwarded-proto가 있어야 하고,host값이127.0.0.1:8080이 아니어야 합니다. proxy_connect_timeout 3s,proxy_send_timeout 30s,proxy_read_timeout 60s를 설정합니다.client_max_body_size를20m으로 설정하고 reload 합니다. 5MB 본문 POST 는 413 이 아니어야 하고, 25MB 본문 POST 는 413 이어야 합니다.gzip on,gzip_min_length 1000,gzip_vary on을 설정하고gzip_types에application/json을 포함시킵니다.curl -H 'Accept-Encoding: gzip' -I http://127.0.0.1:8088/labhub/big.html의 응답에Content-Encoding: gzip이 있어야 합니다./root/ng/static/app.js파일을 만들고(내용 자유),/assets/경로로 서비스되게 설정합니다. 즉http://127.0.0.1:8088/assets/app.js가 200 이어야 하며, 응답 헤더에Expires또는Cache-Control이 있어야 합니다./manager/로 시작하는 모든 요청이 403 을 반환하도록 설정합니다.http://127.0.0.1:8088/manager/html이 403 이어야 합니다.log_format을 정의해$upstream_addr,$upstream_status,$upstream_response_time,$request_time네 변수를 포함시키고, 액세스 로그를/root/ng/logs/access.log에 남깁니다. reload 후 요청을 한 번 보내 로그가 실제로 쌓여야 합니다.
참고
- 기동:
nginx -c /root/ng/nginx.conf -p /root/ng - 문법 검사:
nginx -t -c /root/ng/nginx.conf -p /root/ng - 재적용:
nginx -s reload -c /root/ng/nginx.conf -p /root/ng - 큰 본문 전송:
head -c 26000000 /dev/zero | curl -s -o /dev/null -w '%{http_code}' --data-binary @- <URL> - 흔한 실수 1:
proxy_pass뒤에 슬래시를 붙였다 뺐다 하며 404 를 만드는 것. URI 부분이 있으면 location 에 매칭된 부분이 잘립니다. - 흔한 실수 2:
events {}블록을 빼먹는 것. nginx.conf 에 필수입니다. - 흔한 실수 3: 로그 디렉터리를 안 만들어 두고 reload 해서 기동이 실패하는 것.
최소 프록시 설정과 기동
/root/ng/nginx.conf 를 작성하고 nginx 를 기동합니다.
8088 포트로 listen 하고 / 를 http://127.0.0.1:8080 으로 프록시합니다.
http://127.0.0.1:8088/labhub/version 이 200 이어야 합니다.
nginx 는 -c 로 설정 파일을, -p 로 prefix(상대 경로 기준)를 지정할 수 있습니다. 이 환경은 1024 미만 포트에 바인딩할 수 없다는 점을 기억하세요. 기동 전 -t 로 문법 검사부터 하는 습관을 들이세요.
전달 헤더 설정
프록시 헤더 네 개를 설정하고 reload 합니다.
Host, X-Real-IP, X-Forwarded-For, X-Forwarded-Proto.
확인: curl -s http://127.0.0.1:8088/labhub/echo 의 JSON 에
x-forwarded-for 와 x-forwarded-proto 가 있어야 하고,
host 값이 127.0.0.1:8080 이 아니어야 합니다.
백엔드가 실제로 무엇을 받는지 확인할 수 있는 엔드포인트가 있습니다. Host 를 안 넘기면 백엔드가 보는 Host 가 무엇이 되는지 직접 확인해 보세요.
프록시 타임아웃 3종
proxy_connect_timeout 3s, proxy_send_timeout 30s, proxy_read_timeout 60s
를 설정합니다.
연결·전송·읽기 타임아웃은 각각 다른 구간을 잽니다. 504 는 이 중 어느 것과 관련이 깊은지 생각해 보세요.
요청 본문 크기 제한
client_max_body_size 를 20m 으로 설정하고 reload 합니다.
5MB 본문 POST 는 413 이 아니어야 하고, 25MB 본문 POST 는 413 이어야 합니다.
이 제한을 넘으면 nginx 가 직접 응답하므로 백엔드 로그에는 아무 흔적도 남지 않습니다. 기본값이 얼마인지 알고 있어야 파일 업로드 장애를 빨리 잡습니다.
응답 압축
gzip on, gzip_min_length 1000, gzip_vary on 을 설정하고
gzip_types 에 application/json 을 포함시킵니다.
curl -H 'Accept-Encoding: gzip' -I http://127.0.0.1:8088/labhub/big.html 의
응답에 Content-Encoding: gzip 이 있어야 합니다.
최소 길이 기준보다 작은 응답은 압축되지 않습니다. 캐시 오동작을 막는 지시자도 하나 함께 켜야 합니다.
정적 파일 분리
/root/ng/static/app.js 파일을 만들고(내용 자유),
/assets/ 경로로 서비스되게 설정합니다. 즉
http://127.0.0.1:8088/assets/app.js 가 200 이어야 하며,
응답 헤더에 Expires 또는 Cache-Control 이 있어야 합니다.
location 경로와 실제 디렉터리 이름이 다를 때 쓰는 지시자가 있습니다. 캐시 만료 헤더도 함께 주세요.
관리자 경로 차단
/manager/ 로 시작하는 모든 요청이 403 을 반환하도록 설정합니다.
http://127.0.0.1:8088/manager/html 이 403 이어야 합니다.
프록시에서 막으면 애플리케이션을 배포하지 않고도 정책을 바꿀 수 있습니다. 정규식 location 과 접두 location 의 우선순위를 생각해 보세요.
장애 분석용 로그 포맷
log_format 을 정의해 $upstream_addr, $upstream_status,
$upstream_response_time, $request_time 네 변수를 포함시키고,
액세스 로그를 /root/ng/logs/access.log 에 남깁니다.
reload 후 요청을 한 번 보내 로그가 실제로 쌓여야 합니다.
백엔드가 쓴 시간과 전체 시간을 함께 남겨야 '백엔드가 느리다'와 '전송이 느리다'를 구분할 수 있습니다. 로그를 남기려면 요청을 실제로 보내야 합니다.