NGINX Unit – Routes(라우트) 매뉴얼

Routes

config/routes 구성 엔터티는 내부 요청 라우팅을 정의합니다. Listener로부터 요청을 수신하고 앱에서 처리할 조건 세트를 통해 요청을 필터링하고, 외부 서버에 프록시하거나 서버 간에 로드 밸런싱하고, 정적 콘텐츠를 제공하고, 임의의 상태 코드로 응답하거나 리디렉션합니다.

가장 간단한 형태의 경로는 단일 경로를 정의하는 배열입니다.

{
     "listeners": {
         "*:8300": {
             "pass": "routes"
         }
     },

     "routes": [
         "..."
     ]
}

또 다른 형태는 하나 이상의 명명된 경로 배열을 구성원으로 포함하는 객체입니다.

{
     "listeners": {
         "*:8300": {
             "pass": "routes/main"
         }
     },

     "routes": {
         "main": [
             "..."
         ],

         "route66": [
             "..."
         ]
     }
}

Route Steps

route 배열에는 단계 개체가 요소로 포함됩니다. 다음 옵션을 수락합니다.

OptionDescription
action(required)객체(Object); 일치(Matching)하는 요청(Request)을 처리하는 방법을 정의합니다.
match객체(Object); 일치(Matching)시킬 단계의 조건(condition)을 정의합니다.

route에 전달된 요청은 해당 단계를 순차적으로 순회(traverses)합니다.

  • 단계의 모든 일치(match) 조건이 충족되면 순회(traversal)가 종료(end)되고 단계의 작업(action)이 수행됩니다.
  • 단계의 조건이 충족되지 않으면 장치는 경로(route)의 다음 단계로 진행합니다.
  • 경로(route)의 단계가 일치하지 않으면 404 “Not Found” 응답이 반환(return)됩니다.

Warning

단계(step)에서 일치(match) 옵션을 생략하면 해당 작업(action)이 자동으로 발생합니다. 따라서 경로당(per route) 이러한 단계를 하나만 사용하고 잠재적인 라우팅 문제를 방지하기 위해 항상 마지막에 배치하십시오.

임시 예

기본적인 것:

{
    "routes": [
        {
            "match": {
                "host": "example.com",
                "scheme": "https",
                "uri": "/php/*"
            },

            "action": {
                "pass": "applications/php_version"
            }
        },
        {
            "action": {
                "share": "/www/static_version$uri"
            }
        }
    ]
}

이 경로(route)는 HTTPS를 통해 example.com 웹사이트의 /php/ 하위 섹션에 대한 모든 요청을 php_version 앱으로 전달합니다. 다른 모든 요청은 /www/static_version/ 디렉토리의 정적 콘텐츠와 함께 제공됩니다. 일치(matching)하는 콘텐츠가 없으면 404 “Not Found” 응답이 반환됩니다.

연결된 경로(chained route)와 proxying을 사용한 보다 정교한 예:

{
    "routes": {
        "main": [
            {
                "match": {
                    "scheme": "http"
                },

                "action": {
                    "pass": "routes/http_site"
                }
            },
            {
                "match": {
                    "host": "blog.example.com"
                },

                "action": {
                    "pass": "applications/blog"
                }
            },
            {
                "match": {
                    "uri": [
                        "*.css",
                        "*.jpg",
                        "*.js"
                    ]
                },

                "action": {
                    "share": "/www/static$uri"
                }
            }
        ],

        "http_site": [
            {
                "match": {
                    "uri": "/v2_site/*"
                },

                "action": {
                    "pass": "applications/v2_site"
                }
            },
            {
                "action": {
                    "proxy": "http://127.0.0.1:9000"
                }
            }
        ]
    }
}

여기서는 main이라는 경로(routes)가 명시적으로 정의되어 있으므로 경로는 배열이 아닌 객체입니다. 경로의 첫 번째 단계는 HTTP를 통해 도착하는 모든 요청을 http_site 앱으로 전달합니다. 두 번째 단계는 blog.example.com을 대상으로 하는 모든 요청을 블로그 앱으로 전달합니다. 마지막 단계는 /www/static/ 디렉토리에서 특정 파일 유형에 대한 요청을 처리합니다. 일치하는 단계가 없으면 404 “Not Found” 응답이 반환됩니다.

매칭 조건(Matching Conditions)

경로 단계(route step)의 일치(match) 객체에 있는 조건은 요청 속성(properties)과 비교할 패턴(pattern)을 정의합니다.

PropertyPatterns Are Matched AgainstCase-Sensitive
arguments요청의 query string과 함께 제공된 인수입니다. 이러한 이름과 값 쌍은 공백으로 대체된 더하기 기호(+)로 디코딩된(decoded) 퍼센트(percent)입니다.
cookies요청과 함께 제공된 쿠키.
destination대상(Target) IP 주소 및 요청의 선택적(optional) 포트.
headers요청과 함께 제공된 헤더 필드.
host소문자로 변환되고 포트 번호와 후행(trailing) 마침표(있는 경우)를 제거하여 정규화된 Host 헤더 필드(header field)입니다.
method대문자로 변환된 요청 줄의 메서드입니다.
queryquery string, 더하기 기호(+)로 디코딩된(decoded) 백분율이 공백으로 대체되었습니다.
schemeURI scheme. http 또는 https의 두 가지 패턴(pattern)만 허용합니다.
sourceSource IP 주소 및 요청(request)의 선택적 포트(optional port).
uri요청 대상(Request target), query string을 제거하고 상대 참조(“.” 및 “..”, “//”)를 해결하여 디코딩(decoded) 및 정규화된 비율.

Arguments vs. Query

인수(arguments)와 쿼리(query)는 모두 쿼리 문자열(query string)에서 작동하지만 쿼리는 전체 문자열과 일치하지만 인수는 key1=4861&key2=a4f3과 같은 key-value 쌍만 고려합니다.

인수(argument)를 사용하여 쿼리 문자열의 key-value 쌍을 기반으로 조건을 정의합니다.

"arguments": {
   "key1": "4861",
   "key2": "a4f3"
}

인수(Argument) 순서는 관련이 없습니다. key1=4861&key2=a4f3key2=a4f3&key1=4861은 동일한 것으로 간주됩니다. 또한 인수가 여러 번 발생하면 모두 일치해야 하므로 key=4861&key=a4f3이 다음과 일치합니다.

"arguments":{
    "key": "*"
}

그러나 이것은 아닙니다:

"arguments":{
    "key": "a*"
}

반대로 조건이 쿼리 문자열과 관련되지만 key-value 쌍에 의존하지 않는 경우 쿼리(query)를 사용하십시오.

"query": [
    "utf8",
    "utf16"
]

이는 https://example.com?utf8 또는 https://example.com?utf16 형식의 쿼리 문자열(query string)과만 일치합니다.

Match Resolution

일치하려면 속성이 다음 두 가지 요구 사항을 충족해야 합니다.

  • 부정(! prefix)이 없는 패턴이 있으면 그 중 하나 이상이 속성 값과 일치합니다.
  • 속성 값과 일치하는 부정 패턴(negated pattern)이 없습니다.

공식적인 설명

이 논리(logic)는 설정 작업으로 설명할 수 있습니다. 집합 U가 속성의 모든 가능한 값을 포함한다고 가정합니다. 집합 P는 부정 없이 모든 패턴과 일치하는 문자열로 구성됩니다. 집합 N은 부정 기반 패턴과 일치하는 문자열로 구성됩니다. 이 체계에서 매칭 세트는 다음과 같습니다.

U ∩ P \ N if P ≠ ∅

U \ N if P = ∅

여기에서 요청의 URI는 pattern3에 맞아야 하지만 pattern1 또는 pattern2에 맞지 않아야 합니다.

{
    "match": {
        "uri": [
            "!pattern1",
            "!pattern2",
            "pattern3"
        ]
    },

    "action": {
        "pass": "..."
    }
}

또한 특수 일치 논리(special matching logic)가 인수(arguments), 쿠키(cookies) 및 헤더(headers)에 적용됩니다. 이들 각각은 사용자 지정 속성과 해당 패턴을 나열하는 단일 개체이거나 이러한 개체의 배열일 수 있습니다.

단일 개체를 일치시키려면 요청이 개체에 명명된 모든 속성과 일치해야 합니다. 개체 배열을 일치시키려면 해당 항목 개체 중 하나를 일치시키는 것으로 충분합니다. 다음 조건은 요청 인수에 arg1arg2가 포함되고 둘 다 해당 패턴과 일치하는 경우에만 일치합니다.

{
    "match": {
        "arguments": {
            "arg1": "pattern",
            "arg2": "pattern"
        }
    },

    "action": {
        "pass": "..."
    }
}

개체 배열을 사용하면 요청의 인수(arguments)에 각 패턴과 일치하는 arg1 또는 arg2(또는 둘 다)가 포함되는 경우 조건이 일치합니다.

{
    "match": {
        "arguments": [
            {
                "arg1": "pattern"
            },
            {
                "arg2": "pattern"
            }
        ]
    },

    "action": {
        "pass": "..."
    }
}

다음 예제에서는 일치하는 모든 유형을 결합합니다. 여기에서 host, method, uri, arg1 및 arg2, cookie1 또는 cookie2, header1 또는 header2 및 header3 중 하나는 수행할 작업에 대해 일치해야 합니다(host & method & uri & arg1 & arg2 & (cookie1 | cookie2) & (header1 | (header2 및 header3))):

{
    "match": {
        "host": "pattern",
        "method": "!pattern",
        "uri": [
            "pattern",
            "!pattern"
        ],

        "arguments": {
            "arg1": "pattern",
            "arg2": "!pattern"
        },

        "cookies": [
            {
                "cookie1": "pattern",
            },
            {
                "cookie2": "pattern",
            }
        ],

        "headers": [
            {
                "header1": "pattern",
            },
            {
                "header2": "pattern",
                "header3": "pattern"
            }
        ]
    },

    "action": {
        "pass": "..."
    }
}

Object Pattern Examples

이를 위해서는 URI 쿼리에서 mode=strict 및 access=full 이외의 모든 액세스 인수가 필요합니다.

{
    "match": {
        "arguments": {
            "mode": "strict",
            "access": "!full"
        }
    },

    "action": {
        "pass": "..."
    }
}

이는 gzip을 사용하고 Mozilla/5.0으로 식별하거나 curl을 사용자 에이전트로 나열하는 요청과 일치합니다.

{
    "match": {
        "headers": [
            {
                "Accept-Encoding": "*gzip*",
                "User-Agent": "Mozilla/5.0*"
            },
            {
                "User-Agent": "curl*"
            }
        ]
    },

    "action": {
        "pass": "..."
    }
}

Pattern Syntax

개별 패턴(Individual patterns)은 주소 기반(source 및 destination) 또는 문자열 기반(기타 properties)일 수 있습니다.

문자열 기반 패턴은 속성과 문자가 일치해야 합니다. 와일드카드 또는 정규식은 이 동작을 수정합니다.

  • 와일드카드 패턴에는 와일드카드(*)의 모든 조합이 포함될 수 있으며 각각은 임의의 수의 문자를 나타냅니다: Howsthatto*you.
  • 정규식 패턴은 물결표(~)로 시작합니다: ~^\d+.\d+.\d+.\d+ (백슬래시 이스케이프는 JSON 요구 사항입니다). 정규식은 PCRE 맛입니다.

인수(Arguments), 쿼리(Query) 및 URI 패턴의 백분율 인코딩

인수 이름, 인수(argument), 쿼리(query) 및 uri의 비정규 문자열 패턴은 퍼센트 인코딩되어 특수 문자(!는 %21, ~는 %7E, *는 %2A, %는 %25)를 마스킹하거나 단일 바이트를 대상으로 할 수도 있습니다. 예를 들어 UTF-8에서 시작 바이트 0xC3으로 Ö 또는 Å와 같은 분음 부호를 선택할 수 있습니다.

{
    "match": {
        "arguments": {
            "word": "*%C3*"
        }
    },

    "action": {
        "pass": "..."
    }
}

Unit은 이러한 문자열을 디코딩(decode)하고 각 요청 엔터티(entities)와 일치(match)시켜 이들도 디코딩(decoding)합니다.

{
    "routes": [
        {
            "match": {
                "query": "%7Efuzzy word search"
            },

            "action": {
                "return": 200
            }
        }
    ]
}

이 조건은 다음 백분율 인코딩 요청과 일치합니다.

curl http://127.0.0.1/?~fuzzy%20word%20search -v

  > GET /?~fuzzy%20word%20search HTTP/1.1
      ...
      < HTTP/1.1 200 OK
      ...

요청의 인코딩된 공백(%20)은 패턴의 인코딩되지 않은 해당 부분과 일치합니다. 반대로 조건의 인코딩된 물결표(%7E)는 요청의 ~와 일치합니다.

문자열 패턴(String Pattern) 예

/data/www/ 디렉토리 및 해당 하위 디렉토리 내의 모든 .php 파일과 일치하는 정규식입니다. 백슬래시에 유의하십시오. 이스케이프는 JSON 관련 요구 사항입니다.

{
    "match": {
        "uri": "~^/data/www/.*\\.php(/.*)?$"
    },

    "action": {
        "pass": "..."
    }
}

example.com의 하위 도메인만 일치합니다.

{
    "match": {
        "host": "*.example.com"
    },

    "action": {
        "pass": "..."
    }
}

/admin/의 하위 디렉토리에 있는 .php 파일에 대한 요청만 일치합니다.

{
    "match": {
        "uri": "/admin/*/*.php"
    },

    "action": {
        "pass": "..."
    }
}

여기서는 eu-5.example.com을 제외하고 example.com의 모든 eu- 하위 도메인이 일치합니다.

{
    "match": {
        "host": [
            "eu-*.example.com",
            "!eu-5.example.com"
        ]
    },

    "action": {
        "pass": "..."
    }
}

HEAD 및 GET을 제외한 모든 메서드가 일치합니다.

{
    "match": {
        "method": [
            "!HEAD",
            "!GET"
        ]
    },

    "action": {
        "pass": "..."
    }
}

특정 특수 문자를 패턴에 결합할 수도 있습니다. 여기에서 /api/를 포함하는 URI를 제외한 모든 URI가 일치합니다.

{
    "match": {
        "uri": "!*/api/*"
    },

    "action": {
        "pass": "..."
    }
}

여기에서 YYYY-MM-DD 날짜가 일치하지 않는 기사의 URI가 일치합니다. 다시 말하지만 백슬래시에 유의하십시오. 이것은 JSON 요구 사항입니다.

{
    "match": {
        "uri": [
            "/articles/*",
            "!~/articles/\\d{4}-\\d{2}-\\d{2}"
        ]
    },

    "action": {
        "pass": "..."
    }
}

주소 기반(address-based) 패턴은 속성과 정확히 일치해야 하는 개별 IPv4(점 십진수 또는 CIDR), IPv6(16진수 또는 CIDR) 또는 모든 UNIX 도메인 소켓 주소를 정의합니다. 와일드카드와 범위는 이 동작을 수정합니다.

  • 와일드카드(*)는 임의의 IP(:)만 일치시킬 수 있습니다.
  • 범위(-)는 IP(해당 표기법) 및 포트(-) 모두에서 작동합니다.

주소 기반 허용-거부 목록(Address-Based Allow-Deny Lists)

주소는 예를 들어 다음과 같이 경로로 허용-거부 메커니즘을 구현할 때 유용합니다.

"routes": [
    {
        "match": {
            "source": [
                "192.168.1.0/24",
                "2001:0db8::/32",
                "!192.168.1.1",
                "!10.1.1.0/16"
            ]
        },

        "action": {
            "share": "/www/data$uri"
        }
    }
]

이는 다음 nginx 지시문에 해당합니다.

location / {
    deny  10.1.1.0/16;
    deny  192.168.1.1;
    allow 192.168.1.0/24;
    allow 2001:0db8::/32;
    deny  all;

    root /www/data;
}

주소 패턴 예(Address Pattern Examples)

이것은 와일드카드 및 범위와 함께 IPv4 기반 일치를 사용합니다.

{
    "match": {
        "source": [
            "192.0.2.1-192.0.2.200",
            "198.51.100.1-198.51.100.200:8000",
            "203.0.113.1-203.0.113.200:8080-8090",
            "*:80"
        ],

        "destination": [
            "192.0.2.0/24",
            "198.51.100.0/24:8000",
            "203.0.113.0/24:8080-8090",
            "*:80"
        ]
    },

    "action": {
        "pass": "..."
    }
}

이것은 와일드카드 및 범위와 함께 IPv6 기반 일치를 사용합니다.

{
    "match": {
        "source": [
             "2001:0db8::-2001:0db8:aaa9:ffff:ffff:ffff:ffff:ffff",
             "[2001:0db8:aaaa::-2001:0db8:bbbb::]:8000",
             "[2001:0db8:bbbb::1-2001:0db8:cccc::]:8080-8090",
             "*:80"
        ],

        "destination": [
             "2001:0db8:cccd::/48",
             "[2001:0db8:ccce::/48]:8000",
             "[2001:0db8:ccce:ffff::/64]:8080-8090",
             "*:80"
        ]
    },

    "action": {
        "pass": "..."
    }
}

나열된 IPv4 또는 IPv6 주소와 일치합니다.

{
    "match": {
        "destination": [
            "127.0.0.1",
            "192.168.0.1",
            "::1",
            "2001:0db8:1::c0a8:1"
        ]
    },

    "action": {
        "pass": "..."
    }
}

여기서 192.0.2.9를 제외하고 범위 일치의 모든 IP는 다음과 같습니다.

{
    "match": {
        "source": [
            "192.0.2.1-192.0.2.10",
            "!192.0.2.9"
        ]
    },

    "action": {
        "pass": "..."
    }
}

이것은 모든 IP와 일치하지만 허용 가능한 포트를 제한합니다.

{
    "match": {
        "source": [
            "*:80",
            "*:443",
            "*:8000-8080"
        ]
    },

    "action": {
        "pass": "..."
    }
}

이는 모든 UNIX 도메인 소켓과 일치합니다.

{
    "match": {
        "source": "unix"
    },

    "action": {
        "pass": "..."
    }
}

Handling Actions

요청이 경로 단계의 모든 조건과 일치하거나 단계 자체에서 일치 개체를 생략하는 경우 장치는 해당 작업을 사용하여 요청을 처리합니다. 상호 배타적인 작업 유형은 다음과 같습니다.

OptionDescriptionDetails
pass리스너(listener)의 전달(pass) 옵션과 동일한 요청 대상.Listeners
proxy요청(request)이 프록시(proxvied)되는 HTTP 서버의 소켓 주소(Socket Address)입니다.Proxying
returncontext-dependent redirect location가 있는 HTTP 상태 코드(status code)입니다.Instant Response, Redirects
share정적 콘텐츠로 요청을 제공하는 파일 경로(path).Static File

An example:

{
    "routes": [
        {
            "match": {
                "uri": "/pass/*"
            },

            "action": {
                "pass": "applications/app"
            }
        },
        {
            "match": {
                "uri": "~\\.jpe?g$"
            },

            "action": {
                "share": [
                    "/var/www/static$uri",
                    "/var/www/static/assets$uri"
                 ],

                "fallback": {
                     "pass": "upstreams/cdn"
                }
            }
        },
        {
            "match": {
                "uri": "/proxy/*"
            },

            "action": {
                "proxy": "http://192.168.0.100:80"
            }
        },
        {
            "match": {
                "uri": "/return/*"
            },

            "action": {
                "return": 301,
                "location": "https://www.example.com"
            }
        }
    ]
}