한준후블로그

nginx에서 /admin이 404가 났다 — 정규식 location이 먼저 잡히는 이유

·1분 읽기 ·745자

#서버#nginx#삽질

개인 사이트에 관리자 페이지를 붙이면서 하루를 날렸다. nginx 설정은 분명히 맞는데 CSS만 404가 났다. 원인은 nginx가 location을 매칭하는 순서였고, 알고 나면 허무하지만 모르면 계속 엉뚱한 곳을 고치게 된다.

상황

정적 사이트 하나를 nginx로 서빙하고 있었다. 여기에 Node로 만든 관리자 페이지를 /admin 경로에 붙이려 했다. 설정은 이랬다.

server {
    root /var/www/hanjunhu.com;

    location ~* \.(css|js)$ {
        expires 7d;
    }

    location /admin {
        proxy_pass http://127.0.0.1:4040;
    }

    location / {
        try_files $uri $uri.html $uri/index.html =404;
    }
}

/admin은 200으로 잘 떴다. 그런데 그 안에서 불러오는 /admin/admin.css만 404였다. 프록시 대상인 Node 앱에 직접 요청하면 파일은 멀쩡히 나왔다.

$ curl -o /dev/null -w "%{http_code}\n" http://127.0.0.1:4040/admin/admin.css
200

$ curl -o /dev/null -w "%{http_code}\n" https://hanjunhu.com/admin/admin.css
404

원인

nginx는 location을 설정 파일에 적힌 순서대로 찾지 않는다. 정해진 우선순위가 있다.

  1. location = /경로 — 정확히 일치. 찾으면 즉시 종료
  2. location ^~ /경로 — 접두사 일치 중 가장 긴 것. 찾으면 정규식을 건너뛴다
  3. location ~ / location ~* — 정규식. 위에서부터 순서대로, 처음 맞는 것
  4. 일반 접두사 location /경로 — 정규식이 하나도 안 맞았을 때만 쓰인다

/admin/admin.css 요청이 오면 nginx는 먼저 접두사 /admin을 기억만 해두고, 정규식부터 확인한다. 그런데 위 설정에는 location ~* \.(css|js)$가 있다. 이게 먼저 잡히고, 이 블록에는 proxy_pass가 없으니 상위의 root를 써서 /var/www/hanjunhu.com/admin/admin.css를 찾는다. 그런 파일은 없다. 그래서 404.

정규식 location은 일반 접두사 location보다 항상 먼저 평가된다. 순서를 바꿔 적어도 소용없다.

해결

접두사 앞에 ^~를 붙이면 된다. 이 접두사가 매칭되는 순간 nginx는 정규식 검사를 아예 하지 않는다.

location ^~ /admin {
    proxy_pass http://127.0.0.1:4040;
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-Proto $scheme;
}

한 글자 두 개 넣고 끝났다.

$ sudo nginx -t && sudo systemctl reload nginx
$ curl -o /dev/null -w "%{http_code} %{content_type}\n" https://hanjunhu.com/admin/admin.css
200 text/css

같은 실수를 피하려면

  • 캐시나 만료 설정용으로 location ~* \.(css|js|png)$ 같은 걸 쓰고 있다면, 프록시로 넘기는 경로에는 반드시 ^~를 붙인다.
  • 정적 파일 확장자 규칙은 되도록 프록시 경로 안쪽에 중첩해서 쓰거나, 특정 디렉터리로 좁힌다.
  • 디버깅할 때 error_log ... debug;를 켜면 어떤 location이 선택됐는지 로그에 직접 찍힌다. 추측보다 이게 빠르다.

공식 문서의 location 지시어 설명에 이 순서가 그대로 적혀 있다. 한 번 읽어두면 비슷한 삽질을 한 번은 덜 하게 된다.

한준후개발자 겸 창업가. 크리프트 대표, 주식회사 위트 최대주주.

소개 ↗

함께 읽기