Skip to content

nginx location 테스터 — 그 블록이 이기는 이유

어떤 nginx location 블록이 이기고 나머지는 왜 졌는지 보여줍니다. =, ^~, ~, ~* 매칭을 브라우저 안에서 처리하는 무료 온라인 테스터입니다.

트래킹 없음 브라우저 실행 무료
설정은 브라우저 안에서 로컬로 분석되며 업로드되지 않습니다. 서버 설정에는 업스트림 호스트명과 인증 블록이 담기므로 Network 패널을 열어 조용한지 확인하거나 아예 오프라인으로 전환해 보세요.
실제 설정 오류 사례 열어보기
선택된 location
~* \.(gif|jpg|jpeg)$

설정 순서상 가장 먼저 매칭된 정규식입니다. 길이는 무관합니다.

nginx가 실제로 매칭하는 대상
요청 대상
/documents/1.jpg
정규화된 $uri
/documents/1.jpg
쿼리 문자열 $args

매칭은 정규화된 경로만을 대상으로 수행됩니다. 쿼리 문자열은 먼저 분리되며 전혀 관여하지 않습니다.

그 블록이 이긴 이유
그 블록이 이긴 이유
location 단계 결과 이유
2 = / 정확 일치 매칭 없음 = location은 URI가 이것으로 시작하는 게 아니라 전체가 같아야 합니다.
3 / 접두사 매칭됐지만 더 짧음 매칭은 되지만 다른 접두사가 더 많은 문자를 매칭했습니다.
4 /documents/ 접두사 매칭됐지만 더 짧음 매칭은 되지만 다른 접두사가 더 많은 문자를 매칭했습니다.
5 ^~ /images/ 접두사 매칭 없음 URI가 이 접두사로 시작하지 않습니다.
6 ~* \.(gif|jpg|jpeg)$ 정규식 선택됨 설정 순서상 가장 먼저 매칭된 정규식입니다. 길이는 무관합니다.

nginx location 수식자 비교: =, ^~, ~, ~*

nginx location 수식자 비교: =, ^~, ~, ~*
수식자 문법 매칭 기준 순서 정규식 중단 일반적인 용도
= location = /path 동등성 1 / 같은 핫 패스 — 가능한 가장 빠른 매칭.
^~ location ^~ /path 시작 문자열 2 업로드처럼 정규식에 절대 넘겨서는 안 되는 디렉터리.
~ location ~ regex PCRE 정규식 3 아니요 대소문자가 중요한 확장자 라우팅.
~* location ~* regex PCRE 정규식 3 아니요 대소문자가 중요하지 않은 확장자 라우팅.
(없음) location /path 시작 문자열 4 아니요 경로 기반의 일반 라우팅.
@ location @name 내부 전용 아니요 error_page 와 try_files 의 폴백.

순서 열은 단순한 순위표가 아닙니다. 접두사 location은 ^~ 를 달고 있으면서 스스로 가장 긴 매칭일 때에만 정규식 평가를 중단시킵니다 — ^~ 블록이 때때로 아무것도 안 하는 것처럼 보이는 이유가 정확히 이것입니다.

nginx location 우선순위: 해석 순서

nginx location 우선순위: 해석 순서
# 단계 탐색 종료 무슨 일이 일어나나
1 정규화 아니요 퍼센트 디코딩, . 과 .. 해석, 반복 슬래시 합치기. 쿼리 문자열은 여기서 분리되며 매칭에 전혀 참여하지 않습니다.
2 정확 일치 location = /path 를 동등성으로 비교합니다. 적중하면 탐색이 즉시 끝납니다.
3 자동 리다이렉트 이름이 URI에 슬래시를 더한 형태인 프록시 location입니다. nginx가 301을 응답하고 정규식에는 도달하지 않습니다.
4 접두사 아니요 매칭되는 모든 접두사를 비교해 가장 긴 것을 기억합니다. 설정 순서는 무시됩니다.
5 중첩 아니요 이긴 접두사 안으로 내려갑니다. 중첩된 정규식이 부모 레벨보다 먼저 시도됩니다.
6 정규식 정규식은 설정 순서대로 시도되고 첫 매칭이 이깁니다. 뒤에 쓴 더 길거나 더 구체적인 정규식은 실행되지 않습니다.
7 폴백 매칭된 정규식이 없으므로 앞서 기억해 둔 접두사가 쓰입니다.
매칭 순서, ^~ 단락, 중첩 location 하강, 자동 리다이렉트 동작, URI 정규화를 nginx 자체 소스 코드에 대고 확인했고 해당 설정을 nginx 1.27.5에서 실행해 확정했습니다. — Go Tools 엔지니어링 팀 · Jul 22, 2026

이 페이지의 선택 규칙은 2차 자료를 옮겨 적은 것이 아니라 실제로 돌아가는 nginx 1.27.5에 대고 검증했으며, 엔진은 그 실행 결과에서 도출한 단위 테스트로 덮여 있습니다.

nginx location 매칭: 빠른 답변

nginx는 접두사 매칭보다 정규식 location을 먼저 처리하나요?

아니요 — 접두사 location을 먼저 검사하지만, 매칭된 정규식이 그래도 이깁니다. nginx는 먼저 모든 접두사 location을 검사해 가장 긴 매칭을 기억해 두고, 그다음 파일에 나온 순서대로 정규식 location을 평가합니다. 가장 먼저 매칭된 정규식이 이깁니다. 매칭되는 정규식이 없으면 기억해 둔 접두사 location이 쓰입니다. 유일한 예외는 ^~ 입니다. 가장 긴 매칭 접두사가 이 수식자를 달고 있으면 정규식 단계는 통째로 건너뜁니다.

nginx에서 location 블록의 순서가 중요한가요?

정규식 location에만 중요합니다. 접두사 location은 — =^~ 를 포함해 — 가장 긴 매칭으로 선택되므로 파일 안의 순서는 무관합니다. 정규식 location은 위에서 아래로 검사되고 첫 매칭이 이기므로, 정규식 블록을 옮기면 어느 것이 실행되는지가 달라집니다. 더 구체적인 정규식을 더 넓은 정규식 아래에 두면 절대 실행되지 않습니다.

^~ 수식자는 실제로 무슨 일을 하나요?

우선순위를 올리는 게 아니라, 접두사 매칭 뒤에서 nginx를 멈춥니다. 가장 긴 매칭 접두사 location이 ^~ 를 달고 있으면 nginx는 정규식 단계를 건너뛰고 그 블록을 씁니다. 접두사 매칭을 더 길게 만들지도, 다른 접두사보다 위로 올리지도 않습니다. 정규식 평가를 억제할 뿐입니다. 더 긴 일반 접두사도 함께 매칭될 때 ^~ 블록이 아무것도 안 하는 것처럼 보이는 이유가 이것입니다. 더 긴 쪽이 대신 기억되고, 그쪽은 아무것도 억제하지 않습니다.

location /static 과 location /static/ 은 같은가요?

아니요 — /static 은 /staticfoo 도 매칭합니다. 접두사 매칭은 경로 세그먼트 경계가 아니라 단순한 문자열 비교이므로 location /static/staticfiles/static-backup 도 서비스합니다. 별개로, /static/proxy_pass 와 함께 쓰면 끝 슬래시 없는 /static 요청은 정규식을 따지기도 전에 /static/ 으로 301 리다이렉트를 받습니다.

nginx는 매칭 전에 %2F를 디코딩하고 이중 슬래시를 합치나요?

예 — 매칭은 원본 요청이 아니라 정규화된 URI를 대상으로 수행됩니다. nginx는 location을 고르기 전에 %XX 를 디코딩하고 ... 를 해석하며 반복된 슬래시를 압축합니다. 디코딩된 %2F 는 진짜 구분자가 되어 그 해석에 참여하므로 /a/b%2F..%2Fzz/a/zz 로 매칭됩니다. 쿼리 문자열은 가장 먼저 분리되며 매칭에는 전혀 관여하지 않습니다.

nginx location 블록이란?

location 블록은 URI가 패턴과 매칭되는 요청을 어떻게 처리할지 nginx에 알려 줍니다. 하나의 server 블록에는 보통 여러 개가 들어 있는데, 흥미로운 대목은 각 블록이 무엇을 하느냐가 아니라 nginx가 어느 블록을 고르느냐입니다. 선택 규칙이 대부분의 사람이 짐작하는 것과 다르기 때문입니다.

형태는 다섯 가지입니다. location = /path 는 URI 전체가 같을 때만 매칭됩니다. location /path 는 그 문자들로 시작하는 모든 URI에 매칭됩니다. location ^~ /path 는 같은 접두사 비교에 한 가지 효과가 더해진 것입니다. location ~ regexlocation ~* regex 는 각각 대소문자를 구분하거나 구분하지 않고 PCRE 패턴을 적용합니다. location @name 은 URI 매칭에 전혀 참여하지 않고 try_fileserror_page 의 대상으로만 존재합니다.

선택은 단계별로 진행됩니다. 먼저 URI가 정규화됩니다. 퍼센트 디코딩, ... 해석, 반복 슬래시 합치기, 쿼리 문자열 분리가 이뤄집니다. 그다음 URI와 같은 = location이 있으면 탐색이 즉시 끝납니다. 이어서 매칭된 모든 접두사를 비교해 가장 긴 것을 기억해 둡니다 — 여기서 설정 순서는 아무 역할도 하지 않습니다. 기억해 둔 접두사가 ^~ 를 달고 있으면 nginx는 멈추고 그 블록을 씁니다. 그렇지 않으면 정규식 location을 파일에 나온 순서대로 시도하고, 뒤에 오는 것이 아무리 구체적이어도 가장 먼저 매칭된 것이 이깁니다. 어느 것도 매칭되지 않으면 기억해 둔 접두사가 쓰입니다.

이 규칙 중 둘은 서로 반대 방향으로 당깁니다. 혼란이 사는 자리가 바로 거기입니다. 접두사는 순서와 무관하게 길이로, 정규식은 길이와 무관하게 순서로 선택됩니다. 위에서 아래로 읽었을 때 멀쩡해 보이는 설정도 의도하지 않은 곳으로 요청을 보낼 수 있고, 아무리 다시 읽어도 그 사실은 드러나지 않습니다. 이 페이지는 그 전체 순서를 여러분의 설정에 대고 다시 재생하며 각 블록이 어디서 탈락했는지 보여 줍니다.

# From the nginx documentation. Which block serves each request?
server {
    location = /                   { }   # A
    location /                     { }   # B
    location /documents/           { }   # C
    location ^~ /images/           { }   # D
    location ~* \.(gif|jpg|jpeg)$  { }   # E
}

#   /                        -> A   exact match, search ends here
#   /index.html              -> B   no regex matched, longest prefix used
#   /documents/document.html -> C   longer prefix than B
#   /images/1.gif            -> D   ^~ won the prefix stage, regex skipped
#   /documents/1.jpg         -> E   regex beats the longer prefix C

# The last two lines are the whole lesson: identical-looking prefixes
# behave differently because only one of them carries ^~.

주요 기능

진 블록마다 탈락한 단계까지 함께

직접 작성한 각 location이 한 줄씩 나옵니다. 매칭됐지만 더 짧음, ^~ 접두사가 이겨서 건너뜀, 앞선 정규식이 매칭돼 도달 불가, 또는 그냥 매칭 없음. 나머지가 왜 졌는지 아는 것이 대개 질문을 실제로 해결해 줍니다.

네 단계 판정 사슬의 재생

정규화, 정확 일치, 가장 긴 접두사 기억, ^~ 단락, 파일 순서대로의 정규식, 그리고 폴백이 추상적인 설명이 아니라 여러분의 설정에 대고 개별 단계로 표시됩니다.

눈에 보이게 만든 ^~ 단락

^~ 접두사가 정규식 단계를 억제하면 건너뛴 정규식이 조용히 사라지지 않고 건너뜀으로 표시됩니다 — 더 긴 일반 접두사가 이겨서 ^~ 가 적용되지 못한 경우도 함께 보여 줍니다.

평탄화하지 않고 해석하는 중첩 location

nginx는 이긴 접두사 안으로 내려가 그 자식들을 탐색하므로 중첩된 정규식이 부모 레벨보다 먼저 실행됩니다. 중첩 블록은 표에서도 들여쓰기를 유지해 구조가 읽히도록 합니다.

미리 감지하는 PCRE 전용 문법

브라우저는 PCRE가 아니라 ECMAScript 정규식을 돌립니다. 아토믹 그룹, 소유 수량자, POSIX 클래스, \A 와 \K 같은 이스케이프는 조용히 잘못 평가되는 대신 표시되므로, 확신에 찬 틀린 답이 사실처럼 제시되는 일이 없습니다.

아무것도 업로드하지 않음 — 브라우저에서 실행

서버 설정에는 업스트림 호스트명, 내부 포트, 인증 규칙이 담깁니다. 구문 분석은 의존성도 네트워크 호출도 없는 평범한 문자열 작업이며, 빌드마다 도는 자동 계약 테스트로 검증됩니다.

이 질문에 답하는 다른 방법

nginx -T

명령줄

완전히 해석된 설정을 덤프하므로 실제로 무엇이 로드됐는지 확인할 때 매우 유용합니다. 다만 특정 URI가 어느 location을 선택하는지는 알려 주지 않습니다 — 이 페이지가 메우는 빈틈이 그것입니다.

error_log ... debug

운영 중인 서버

얻을 수 있는 가장 권위 있는 답입니다. "using configuration" 줄이 nginx가 실제로 고른 블록을 알려 줍니다. 다만 root 권한과 리로드, 접근 가능한 서버가 필요하므로 배포 전이 아니라 배포 후에야 답합니다.

설정 문법 검사기

호스팅 서비스

파일 전체 린팅과 보안 규칙에 강합니다. 대체로 서버 측에서 돌기 때문에 내부 호스트명과 인증서 경로가 담긴 설정을 업로드해야 한다는 뜻이기도 합니다.

공식 문서 읽기

레퍼런스

nginx 문서는 알고리즘을 정확하게 서술하고 있어 한 번은 읽어 볼 값어치가 있습니다. 다만 블록 여덟 개와 URI 하나에 그 알고리즘을 손으로 적용하는 지점에서 오류가 스며듭니다. 규칙 둘이 서로 반대 방향을 가리키기 때문입니다.

nginx location 매칭 예제

정규식이 더 긴 접두사를 이긴다

location /documents/  ·  location ~* \.(gif|jpg|jpeg)$  ·  GET /documents/1.jpg
~* \.(gif|jpg|jpeg)$ wins

접두사 /documents/ 는 매칭되고 파일 안에서 가장 긴 접두사이므로 nginx가 기억해 둡니다 — 그러고도 정규식을 계속 평가해 가장 먼저 매칭되는 쪽에 요청을 넘깁니다. 길이는 정규식 단계에 집니다. 그 접두사를 ^~ /documents/ 로 썼다면 정규식은 아예 실행되지 않았을 것입니다. nginx 공식 문서에 나오는 예시이며, 몸에 익혀 둘 가치가 가장 큰 하나입니다.

PHP를 실행해 버리는 업로드 디렉터리

location /uploads/  ·  location ~ \.php$ { fastcgi_pass ... }  ·  GET /uploads/evil.php
~ \.php$ wins — the upload lands in the interpreter

접두사 /uploads/ 는 매칭되지만 일반 접두사는 정규식 단계를 멈추지 않으므로, 누군가 올린 파일이 곧장 PHP-FPM으로 넘어갑니다. location ^~ /uploads/ 로 쓰면 정규식 단계가 끊기고 그 통로가 닫힙니다. 가정이 아닙니다. 오랜 기간 이어진 업로드-투-RCE 제보들의 형태가 바로 이것이고, 취약과 안전을 가르는 차이는 두 글자입니다.

조용히 아무 일도 하지 않는 ^~

location ^~ /a/  ·  location /a/b/  ·  location ~ \.php$  ·  GET /a/b/x.php
~ \.php$ wins — the ^~ never applied

^~ 는 그 자신이 매칭된 접두사 중 가장 길 때에만 정규식 단계를 억제합니다. 여기서는 /a/b/ 가 더 길어서 nginx가 기억하는 쪽이 그것이고, 이 블록의 일반 수식자는 정규식 단계를 그대로 돌게 둡니다. ^~ 블록은 여전히 파일에 남아 있고 여전히 보호하는 것처럼 보이지만, 이 요청에는 아무런 영향이 없습니다. 설정을 위에서 아래로 읽어서는 이 사실이 드러나지 않습니다. 접두사 길이를 비교해야 드러납니다.

/static 은 /staticfoo 까지 잡는다

location /static  ·  location /static/  ·  GET /staticfoo
/static wins

접두사 매칭은 경로 세그먼트가 아니라 문자를 비교합니다. /staticfoo 는 /static 으로 시작하므로 매칭되고, /static/ 은 해당 위치에 슬래시가 없으므로 전혀 매칭되지 않습니다. 같은 글자로 시작하기만 하면 그 아래 도달 가능한 모든 경로가 그 블록에서 서비스됩니다 — /static 규칙이 /static-backup 까지 서비스하게 되는 경위가 이것입니다.

가장 나은 정규식이 아니라 첫 번째 정규식이 이긴다

location ~ ^/a  ·  location ~ ^/a/b/c$  ·  GET /a/b/c
~ ^/a wins; ~ ^/a/b/c$ is unreachable

정규식은 파일에 나온 순서대로 평가되며 첫 매칭에서 탐색이 끝납니다. 두 번째 블록이 더 구체적이고 이 URI와 정확히 맞아떨어지지만, 어떤 요청에 대해서도 실행되지 않습니다. 접두사 location은 순서와 무관하게 길이로 선택되고, 정규식 location은 구체성과 무관하게 순서로 선택됩니다. 이 두 규칙을 뒤섞는 것이, 누군가 파일을 정리한 뒤 규칙이 "동작을 멈추는" 흔한 이유입니다.

인코딩된 경로 이동은 매칭 전에 해석된다

location /a/  ·  location /b/  ·  GET /a/b%2F..%2Fzz
$uri becomes /a/zz, so /a/ wins

nginx는 어떤 location도 살펴보기 전에 퍼센트 디코딩을 하고 . 과 .. 를 해석하며 반복된 슬래시를 합칩니다. %2F 는 진짜 구분자로 디코딩되어 그 해석에 참여하므로, 이 대상은 /a/b/ 안에 머무르지 않고 /a/zz 로 떨어집니다. 정규화된 $uri 가 아니라 입력한 대상 그대로 매칭하면 여기서 틀린 답을 얻습니다.

nginx location 테스터 사용법

  1. 1

    server 블록 붙여넣기

    server 블록 전체를 넣어도 되고, 따져 보려는 location 블록만 넣어도 됩니다. 중첩 location도 인식하며 원래 줄 번호를 유지하므로 표가 내 파일과 맞아떨어집니다.

  2. 2

    요청 URI 입력하기

    퍼센트 인코딩과 쿼리 문자열을 포함해 네트워크로 들어오는 그대로의 경로를 입력하세요. 표 위의 세 줄이 매칭 전에 어떻게 정규화되는지 보여줍니다.

  3. 3

    승자를 읽고, 그다음 패자를 읽기

    판정 카드가 선택된 블록과 한 줄짜리 이유를 알려 줍니다. 그 아래 판정 표는 나머지 모든 블록에 대해 어느 단계에서 왜 탈락했는지 설명합니다.

  4. 4

    진단 확인하기

    앵커가 없는 정규식, 끝 슬래시가 빠진 접두사, 정규식 패턴을 달고 있는 ^~, 도달 불가한 중복, PHP 정규식으로 도달 가능한 업로드 디렉터리가 모두 보고됩니다.

  5. 5

    정확한 상태 공유하기

    링크 복사는 설정과 URI를 URL 프래그먼트에 인코딩하므로 동료가 내가 보고 있는 화면을 그대로 엽니다. 프래그먼트는 서버로 전송되지 않습니다.

흔한 nginx location 실수

^~ 가 더 긴 접두사를 제칠 것이라 기대하기

^~ 는 이미 길이로 이긴 접두사에 대해서만 확인됩니다. 더 긴 일반 접두사가 먼저 이기고, 그다음 정규식 단계는 ^~ 가 없는 것처럼 돌아갑니다.

✗ 오류
location ^~ /a/ { }
location /a/b/ { }
location ~ \.php$ { }
# /a/b/x.php -> ~ \.php$
✓ 정상
location ^~ /a/ { }
location ^~ /a/b/ { }
location ~ \.php$ { }
# /a/b/x.php -> ^~ /a/b/

끝 슬래시 없는 접두사가 형제 경로까지 잡기

접두사 매칭은 경로 세그먼트가 아니라 문자를 비교하므로, 같은 글자로 시작하는 모든 형제 경로도 그 블록이 서비스합니다.

✗ 오류
location /static { root /var/www; }
# also serves /staticfoo and /static-backup
✓ 정상
location /static/ { root /var/www; }
location = /static { return 301 /static/; }

구체적인 정규식을 넓은 정규식 아래에 두기

정규식은 파일 순서대로 시도되고 첫 매칭이 탐색을 끝내므로, 더 정밀한 블록은 어떤 요청에 대해서도 실행되지 않습니다.

✗ 오류
location ~ ^/api { }
location ~ ^/api/v2/users$ { }
# the second is unreachable
✓ 정상
location ~ ^/api/v2/users$ { }
location ~ ^/api { }

^~ 뒤에 정규식 쓰기

^~ 는 리터럴 접두사를 받습니다. nginx는 아무 불평 없이 파일을 로드하고 그 블록은 그냥 아무것도 매칭하지 않으므로, 리뷰에서 알아채기 어렵습니다.

✗ 오류
location ^~ "\.php$" { deny all; }
✓ 정상
location ~ \.php$ { deny all; }

쿼리 문자열이 매칭에 참여한다고 가정하기

쿼리 문자열은 정규화 과정에서 분리되므로 location이 그것으로 매칭할 방법은 없습니다. 대신 블록 안에서 $arg_name 을 읽으세요.

✗ 오류
location /search?q= { }
# never matches anything
✓ 정상
location /search {
    if ($arg_q = "") { return 400; }
}

nginx location 테스터로 할 수 있는 일

운영에 나가기 전에 설정 점검하기
수정했지만 아직 배포하지 않은 server 블록의 라우팅을 따져 보세요. 여기서 잡히는 장애는 특정한 형태의 URI에서만 드러나는 종류이고, 리로드 후 스모크 테스트가 놓치기 딱 좋은 종류이기도 합니다.
규칙이 왜 멈췄는지 알아내기
돌던 정규식이 이제 돌지 않는다면 거의 항상 순서의 피해자입니다. 무언가가 먼저 매칭됐거나 그 위에 ^~ 가 생겼습니다. 표는 그 블록을 도달 불가로 표시하고 요청을 가져간 블록의 이름을 알려 줍니다.
업로드나 미디어 디렉터리 감사하기
업로드 실행 형태를 재현하는 프리셋을 불러온 다음 자신의 경로를 넣어 보세요. 쓰기가 허용된 디렉터리 안에서 PHP 정규식이 요청을 가져가고 있다면 진단이 그 사실과 두 블록의 이름을 알려 줍니다.
리뷰 코멘트를 근거로 마무리하기
링크 복사는 정확한 설정과 URI를 URL 프래그먼트에 담습니다. 그것을 풀 리퀘스트에 넣으면 우선순위를 둘러싼 말싸움이 누구나 다시 돌려볼 수 있는 판정 표로 바뀝니다.
선택 알고리즘 가르치기
두 개의 레퍼런스 표는 가리켜 보일 수 있는 정적이고 크롤링 가능한 자료이며, 프리셋 칩은 서버를 망가뜨리지 않고도 각 함정을 보여 줍니다. 특히 ^~ 예제는 논쟁을 빠르게 끝내는 편입니다.

nginx location 선택은 어떻게 이뤄지나

정규화는 어떤 location을 살펴보기도 전에 일어난다
URI는 퍼센트 디코딩되고 ... 세그먼트가 해석되며 반복된 슬래시가 합쳐지고, 그러고 나서야 location이 선택됩니다. 디코딩된 %2F 는 진짜 구분자가 되어 그 해석에 참여하므로 /a/b%2F..%2Fzz/a/zz 로 매칭됩니다. 디코딩된 문자 셋은 예외로 문자 그대로 남습니다. %25, %23, %3F 이며, /a%3Fx=1 의 경로에 물음표가 있고 쿼리 문자열이 비는 이유가 이것입니다. 여기서 + 는 공백이 아닙니다. %20 만 공백입니다. 루트 위로 올라가는 경로 이동과 잘못된 이스케이프는 둘 다 매칭이 시작되기 전에 400으로 거부됩니다.
접두사 길이가 결정하고, 설정 순서는 결정하지 않는다
매칭되는 모든 접두사 location을 비교해 가장 긴 것이 이깁니다. 파일에서 처음에 나오든 마지막에 나오든 상관없습니다. 비교는 경로 세그먼트가 아니라 문자 단위이므로 /static/staticfoo 에 매칭됩니다. 승자는 곧바로 쓰이지 않고 기억됩니다. 정규식 단계가 아직 그것을 뒤집을 수 있기 때문입니다.
^~ 는 정규식을 억제할 뿐, 우선순위를 올리지 않는다
이 수식자는 이미 길이로 이긴 접두사에 대해서만 확인됩니다. 더 긴 일반 접두사도 매칭된다면 그쪽이 대신 기억되고 정규식 단계는 평소대로 돕니다 — ^~ 블록은 그 요청에 아무런 영향이 없습니다. 중첩된 location에 ^~ 를 두어도 바깥 레벨에 선언된 정규식으로부터 보호되지 않으며, 자기 블록 안에 중첩된 정규식은 결코 억제하지 않습니다.
정규식은 파일 순서로 돌고 첫 매칭이 탐색을 끝낸다
nginx는 정규식 location을 작성된 순서대로 유지하며 정렬하지 않습니다. 구체성, 길이, 앵커링은 어느 것이 먼저 시도되는지에 아무 영향도 주지 않으므로, 넓은 패턴 아래에 놓인 정밀한 패턴은 죽은 설정입니다. 매칭된 정규식 location 안으로도 내려가므로 그 안에 중첩된 location은 그다음에 탐색됩니다.
PCRE와 ECMAScript는 같은 언어가 아니다
nginx는 UTF 모드도 멀티라인 모드도 없이 PCRE로 location 정규식을 컴파일하므로, 패턴은 바이트 단위로 동작하고 ^ 는 URI 시작에만 앵커됩니다. 한 가지 차이는 보안 무게가 있습니다. PCRE의 $ 는 끝에 붙은 개행 바로 앞에서도 매칭되므로, %0A 로 끝나는 URI는 JavaScript 엔진이라면 거부했을 상황에서도 여전히 \.php$ 를 만족합니다. 이 동작은 여기서 그대로 흉내 내어 보고됩니다. 파일 확장자에 기댄 규칙을 빠져나가는 알려진 수법이기 때문입니다.

nginx location 모범 사례

쓰기 가능한 디렉터리는 일반 접두사가 아니라 ^~ 로 보호하기
업로드를 받는 디렉터리에는 location ^~ /uploads/ 가 필요합니다. 그래야 정규식 단계가 저장된 파일을 인터프리터에 넘길 수 없습니다. 일반 접두사는 같아 보이지만 같지 않습니다.
디렉터리 접두사에는 끝 슬래시 붙이기
/staticfoo/static-backup 까지 같은 블록이 서비스하기를 일부러 원하는 게 아니라면 location /static 대신 location /static/ 로 쓰세요. 슬래시 없는 경로도 처리해야 한다면 location = /static 을 따로 추가하면 됩니다.
정규식은 구체적인 것부터 넓은 것 순으로 배치하기
첫 매칭이 이기므로 넓은 패턴이 정밀한 패턴 위에 있으면 정밀한 쪽은 도달 불가가 됩니다. 정규식 수를 적게 유지하고 순서를 의도적으로 두는 편이, 나중에 겹침을 따지는 것보다 유지보수가 쉽습니다.
경로 접두사를 매칭하려는 정규식에는 앵커 붙이기
location ~ /admin 은 URI 안 어디에서든 찾으므로 /public/admin/x 에도 매칭됩니다. 시작을 뜻한다면 ~ ^/admin 이라고 쓰세요. 끝에만 앵커를 두는 것은 확장자 라우팅에서는 정상이고 올바릅니다.
순서를 바꿨다면 라우팅을 다시 확인하기
블록을 옮기는 일은 접두사에는 안전하지만 정규식의 동작은 바꿉니다. 줄 순서만 바꾼 diff는 리뷰에서 무해해 보이므로, 영향받는 URI를 다시 돌려보는 것이 가장 값싼 확인 방법입니다.

nginx location 테스터 자주 묻는 질문

nginx가 어떤 location을 선택했는지 어떻게 디버깅하나요?
설정과 요청 URI를 이 테스터에 넣으면 이긴 블록과 나머지 블록이 탈락한 이유를 볼 수 있습니다. 실행 중인 서버라면 error_log /var/log/nginx/debug.log debug; 를 추가하고 선택된 location 이름이 담긴 "using configuration" 줄을 찾으세요. 두 방법은 서로 다른 질문에 답합니다. 로그는 살아 있는 서버가 무엇을 했는지 알려주고, 이 페이지는 아직 배포하지 않은 설정이 무엇을 할지 알려줍니다.
nginx location 정규식이 왜 동작하지 않나요?
보통 세 가지 이유 중 하나이며, 판정 표가 어느 쪽인지 짚어 줍니다. 앞선 정규식이 이미 매칭돼서 내 정규식은 실행조차 되지 않았거나 — 정규식은 파일 순서대로 시도되고 첫 매칭이 이깁니다. 아니면 가장 긴 매칭 접두사가 ^~ 를 달고 있어 정규식 단계를 통째로 건너뛰었거나. 아니면 정규식은 멀쩡한데 URI가 생각과 다른 경우입니다. 매칭은 퍼센트 디코딩과 .. 해석을 거치고 쿼리 문자열이 제거된 정규화된 경로를 대상으로 수행됩니다.
정확 일치가 왜 걸리지 않나요?
= location은 URI가 패턴으로 시작하는 게 아니라 전체가 같아야 합니다. location = /a//a 와 매칭되지 않고, location = /a/a/b 와 매칭되지 않습니다. 여기서 끝 슬래시는 평범한 문자이므로 두 형태는 서로 다른 문자열입니다. 정확 일치 location이 매칭되면 탐색은 즉시 끝나고 나머지는 비교조차 되지 않습니다.
nginx는 location 블록에서 쿼리 문자열을 매칭하나요?
아니요. 쿼리 문자열은 정규화 과정에서 분리되고 location 선택은 경로만 대상으로 수행됩니다. location = /a/a?x=/b 요청에 매칭되는 이유가 이것입니다. 파라미터로 분기하려면 블록 안에서 $arg_name 이나 $args 를 읽어야 합니다. 알아 둘 만한 미묘한 점이 하나 있습니다. %3F 는 경로에 그대로 남는 물음표 문자로 디코딩되므로, /a%3Fx=1 은 쿼리 문자열이 비어 있고 경로에 ? 가 들어 있습니다.
nginx location에 JavaScript 정규식 문법을 쓸 수 있나요?
아니요 — nginx는 PCRE를 쓰고, 그 차이가 실제로 문제가 됩니다. 이 페이지는 ECMAScript 정규식만 존재하는 브라우저에서 돌아가므로, PCRE 전용 구문은 조용히 잘못 평가되는 대신 감지되어 표시됩니다. 아토믹 그룹, 소유 수량자, (?i) 같은 인라인 수식자, [[:alpha:]] 같은 POSIX 클래스, 그리고 JavaScript가 아무 말 없이 평범한 글자로 읽어 버리는 \A, \K 같은 이스케이프가 여기에 해당합니다. 어떤 location이 표시되면 나머지 후보는 그대로 nginx 순서대로 평가되지만, 그 블록의 판정은 실제 서버에서 확인해야 합니다. 패턴 자체를 작성하는 중이라면 정규식 테스터가 ECMAScript 문법을 깊이 다룹니다.
nginx location 접두사 매칭은 대소문자를 구분하나요?
Linux에서는 구분합니다 — location /Static//static/x 와 매칭되지 않습니다. macOS나 Cygwin처럼 대소문자를 구분하지 않는 파일 시스템에서는 nginx가 접두사를 대소문자 구분 없이 비교하고, 나아가 모든 정규식 location이 ~* 처럼 동작하도록 강제합니다. 이 페이지는 운영 서버가 거의 항상 돌리는 Linux 동작을 모델링합니다. Mac에서 개발하고 Linux에 배포한다면 이 차이가 배포 전까지 깨진 규칙을 가려 줄 수 있습니다.
try_files가 선택된 location 블록을 바꾸나요?
아니요. location 선택이 먼저 끝나고, try_files 는 이미 이긴 블록 안에서 그다음에 실행됩니다. 요청이 내 try_files 가 든 블록에 아예 도달하지 못한다면 그 지시어는 무의미합니다 — 흔한 원인은 폴백을 가진 접두사 블록이 손쓰기 전에 ~ \.php$ 정규식이 요청을 가져가는 것입니다. 나중에 발생하는 내부 리다이렉트는 매칭을 다시 시작하므로, 재작성된 URI는 location 목록의 맨 위부터 다시 해석됩니다.
슬래시 없이 디렉터리를 요청하면 nginx가 왜 301을 반환하나요?
서로 다른 두 가지 메커니즘이 그 결과를 냅니다. 이름이 / 로 끝나는 location이 proxy_pass 나 다른 *_pass 지시어를 달고 있으면, 슬래시 없는 같은 경로 요청은 정규식이 평가되기도 전에 location 선택 도중 301로 응답됩니다. 별개로, 정적 파일 모듈은 경로가 디스크의 실제 디렉터리로 해석될 때 301을 냅니다. 첫 번째는 여기서 보이고, 두 번째는 파일 시스템에 달려 있습니다. location = /path 를 추가하면 첫 번째가 억제됩니다.
중첩된 location 블록이 결과를 바꾸나요?
바꿉니다. 그것도 놓치기 쉬운 방식으로 바꿉니다. nginx는 이긴 접두사 location 안으로 내려가 그 자식들을 탐색하므로, 중첩된 정규식이 부모 레벨의 정규식보다 먼저 시도됩니다. 바깥 블록의 ^~ 는 그 블록 자신의 중첩 정규식으로부터 스스로를 지켜 주지 못하고, 바깥 레벨의 형제가 먼저 이기면 중첩 때문에 전역적으로 더 긴 접두사가 도달 불가가 될 수도 있습니다. 중첩 블록은 작성한 그대로의 들여쓰기로 여기서 모델링됩니다.
제 nginx 설정이 어딘가로 업로드되나요?
아니요. 구문 분석과 매칭은 평범한 문자열 연산으로 브라우저 안에서 처리됩니다 — 서버 호출이 없고 남기는 것도 없습니다. 실제 server 블록에는 업스트림 호스트명, 내부 포트, 인증서 경로, 인증 규칙이 들어 있으므로 이 점은 대부분의 도구보다 여기서 더 중요합니다. 말만 믿을 필요는 없습니다. 브라우저 개발자 도구를 열고 입력하는 동안 Network 패널이 조용한지 확인하거나, 아예 네트워크를 끊고 계속 테스트해 보세요. 외부 요청이 하나도 없다는 사실은 빌드마다 도는 자동 계약 테스트로도 강제되므로 조용히 되돌아갈 수 없습니다.

cURL 명령어 생성기 & 빌더

웹 & API

온라인 curl 명령어 생성기. 메서드·헤더·인증·바디를 설정하면 즉시 복사 가능한 명령어가 생성됩니다. Bearer·POST JSON·파일 업로드 프리셋. 무료, 서버 전송 없음.

htpasswd 생성기 — bcrypt, Apache MD5 (apr1) & Basic Auth

웹 & API

bcrypt, Apache MD5 (apr1), SHA-1 등으로 htpasswd 항목을 생성하는 웹 도구. Apache, nginx, Docker 설정 스니펫 포함. 100% 브라우저에서 처리 — 업로드 없음.

Open Graph 메타 태그 생성기

웹 & API

Open Graph, Twitter Card, SEO 메타 태그를 생성하고 Google·Facebook·X 실시간 미리보기로 확인하세요. 100% 무료 웹 도구, 가입 없이 코드를 복사·붙여넣기.

traceparent 디코더 — W3C Trace Context

웹 & API

16진수 세기는 그만. 무료 온라인 traceparent 디코더 — 브라우저에서 실행, 업로드 없음. trace ID·span ID·trace-flags 8비트·tracestate 검사·Datadog/X-Ray/B3 변환.

AES 복호화 도구 — OpenSSL·CryptoJS 호환

보안 도구

온라인 AES 복호화 — GCM/CBC/CTR, 암호 문구 또는 원시 키, OpenSSL·CryptoJS "U2FsdGVkX1" 형식 자동 인식. 브라우저에서만 실행되며 키는 유출되지 않습니다.

AES 암호화 도구 — GCM, CBC, CTR 모드

보안 도구

무료 온라인 AES 암호화 도구 — AES-128/192/256, GCM/CBC/CTR, 암호 문구(PBKDF2) 또는 원시 키. 브라우저에서만 실행되고 서버 업로드는 없습니다.