서버 운영
Nginx location 우선순위를 모르고 API 정적 파일을 가로챈 날
location / 설정 하나가 /api 요청까지 잡아버렸을 때, Nginx 매칭 순서를 확인해 해결한 기록.
증상은 API 오류가 아니라 HTML 응답이었다
관리자에서 저장 버튼을 눌렀는데 네트워크 탭에는 200이 찍혔다. 그런데 JSON을 기대한 코드에서 Unexpected token '<'가 났다. 처음에는 Next.js API가 죽었다고 생각했지만, 응답 첫 줄은 앱의 index.html이었다.
문제는 Nginx 설정에 넣은 정적 사이트용 fallback이었다. /api/health도 실제 API 서버가 아니라 try_files를 거쳐 HTML로 내려가고 있었다. 상태 코드만 보고 서버가 정상이라고 판단한 것이 헷갈린 지점이었다.
먼저 요청이 어디서 끝나는지 확인했다
브라우저 대신 헤더와 본문 앞부분을 분리해 확인했다.
curl -i https://example.com/api/health
sudo nginx -T | less
nginx -T는 include된 설정까지 펼쳐 보여 준다. 이때 location / 안의 try_files $uri $uri/ /index.html;가 넓게 적용된 것을 찾았다. location은 위에서 아래로 보이는 순서만으로 결정되지 않는다. 정확한 prefix, 가장 긴 prefix, 정규식의 관계를 같이 봐야 한다.
API를 명시적으로 분리했다
내 경우 API는 3000번 포트의 애플리케이션이 처리해야 했다. 그래서 fallback보다 앞에 보이도록 정리하는 대신, 경로 자체를 분명히 적었다.
location ^~ /api/ {
proxy_pass http://127.0.0.1:3000;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
location / {
try_files $uri $uri/ /index.html;
}
^~는 이 prefix가 맞으면 뒤의 정규식 location을 더 찾지 않게 한다. 무조건 붙이는 옵션은 아니지만, API와 정적 파일을 확실히 나눌 때는 의도를 드러내기 좋았다. 설정을 반영하기 전에는 문법 검사부터 했다.
sudo nginx -t && sudo systemctl reload nginx
curl -sS -D - https://example.com/api/health -o /tmp/health-body
다음부터 보는 기준
- 200 응답이라도
Content-Type과 본문 첫 글자를 확인한다. - fallback을 넣으면
/api,/assets,/.well-known처럼 예외 경로를 목록으로 적는다. - 설정 변경 뒤에는 성공 경로와 존재하지 않는 API 경로를 각각 호출한다.
이번 일 뒤로는 프록시 문제를 애플리케이션 로그부터 보지 않는다. 요청이 어느 location에 매칭됐는지 확인하는 편이 훨씬 빨랐다.