본문으로 건너뛰기
개발 머꼬
개발 노트Nginx
hohyeon.dev17

proxy_pass 끝의 슬래시 하나 때문에 백엔드가 404를 돌려준 이유

  • #Common Pitfall
  • #Engineering Note
  • #Nginx

문제 발생

관리자 API를 프록시하는데 백엔드가 계속 404였습니다.

location /api/ {
    proxy_pass http://127.0.0.1:3000;      # 슬래시 없음
}

/api/posts 요청이 백엔드에 /api/posts로 도착했습니다. 백엔드는 /posts를 기대하고 있었습니다. 슬래시를 붙였더니 이번에는 다른 location에서 경로가 뭉개졌습니다.

원인 분석

proxy_pass에 URI가 있느냐 없느냐로 동작이 완전히 갈립니다. nginx 문서가 두 경우를 분명히 나눕니다.

URI가 있으면 치환됩니다 — 지시문에 URI가 지정되면 요청 URI 중 location과 일치한 부분이 지시문에 지정된 URI로 대체됩니다. 문서의 예시대로 location /name/ + proxy_pass http://127.0.0.1/remote/;에서 /name/test/remote/test가 됩니다.

URI가 없으면 원본이 그대로 갑니다클라이언트가 보낸 형태 그대로의 요청 URI가 전달됩니다. location /some/path/ + proxy_pass http://127.0.0.1;이 그 경우입니다.

http://127.0.0.1:3000은 "URI 없음"이라 /api/posts가 그대로 가고, http://127.0.0.1:3000/은 "URI 있음(/)"이라 /api/ 부분이 /로 치환되어 /posts가 갑니다. 슬래시 하나가 이 분기를 결정합니다.

문서는 예외도 명시합니다 — location이 정규식으로 지정된 경우와 named location 안에서는 대체할 부분을 결정할 수 없으므로 proxy_pass를 URI 없이 지정해야 합니다.

해결 방안

  1. 접두사를 떼고 넘기려면 양쪽 다 슬래시로 끝냅니다.
location /api/ {
    proxy_pass http://127.0.0.1:3000/;   # /api/posts → /posts
}
  1. 경로를 그대로 넘기려면 URI를 붙이지 않습니다.
location /api/ {
    proxy_pass http://127.0.0.1:3000;    # /api/posts → /api/posts
}
  1. 정규식 location에는 URI를 붙이지 않습니다. 문서가 금지하는 조합이고, 필요하면 rewrite ... break;로 URI를 먼저 바꾼 뒤 넘깁니다 — 이때는 지시문의 URI가 무시되고 변경된 전체 요청 URI가 전달됩니다.

  2. 헤더도 함께 챙깁니다. 경로만 맞추고 Host, X-Forwarded-For, X-Forwarded-Proto를 빠뜨리면 백엔드가 만드는 절대 URL과 클라이언트 IP가 전부 틀어집니다.

  3. 실제로 도착한 경로를 로그로 확인합니다. 추측하지 말고 백엔드 접근 로그를 봅니다 — 이 문제는 설정만 봐서는 양쪽 다 맞아 보입니다.

공식 문서

마지막 수정

좋아요북마크

댓글0

아직 댓글이 없어요. 첫 의견을 편하게 남겨 보세요.