From fdabba020fd6af218c4ce078c93ef4b75af34283 Mon Sep 17 00:00:00 2001 From: Gabor Javorszky Date: Tue, 26 May 2026 15:11:25 +0100 Subject: [PATCH 1/4] docs: Add NIC multiple regex paths to vsr NIC 5.5.0 will support adding multiple regex paths to a single VSR. This will cut down on maintenance costs for customers who have split deployment responsibilities. --- .../configuration/multiple-regex-routes.md | 266 ++++++++++++++++++ ...server-and-virtualserverroute-resources.md | 2 +- 2 files changed, 267 insertions(+), 1 deletion(-) create mode 100644 content/nic/configuration/multiple-regex-routes.md diff --git a/content/nic/configuration/multiple-regex-routes.md b/content/nic/configuration/multiple-regex-routes.md new file mode 100644 index 000000000..bf58c94a6 --- /dev/null +++ b/content/nic/configuration/multiple-regex-routes.md @@ -0,0 +1,266 @@ +--- +title: Multiple regex routes in a VirtualServerRoute +toc: true +weight: 760 +f5-content-type: reference +f5-product: INGRESS +f5-docs: DOCS-XXXX +--- + +F5 NGINX Ingress Controller lets you reference the same VirtualServerRoute from multiple regex routes in a VirtualServer. This means you can group related regex paths by concern — for example, all `/api` paths go to one team's VirtualServerRoute and all `/images` paths go to another. + +## How it works + +When NGINX Ingress Controller processes a VirtualServer, it collects every regex route (`~` or `~*`) that references the same VirtualServerRoute. It then validates the collected VirtualServer paths against the VirtualServerRoute's subroutes as a single set. Each subroute produces a separate NGINX `location` block in the generated configuration. + +## Set match requirement + +The VirtualServer paths and VirtualServerRoute subroutes must form a **bidirectional set match**: + +- Every VirtualServer regex path that references the VirtualServerRoute must have a corresponding subroute. +- Every subroute in the VirtualServerRoute must be referenced by a VirtualServer regex path. + +If either side has a path the other doesn't, NGINX Ingress Controller rejects the VirtualServerRoute and the VirtualServer enters a warning state. + +{{< table >}} + +| Direction | Rule | Error if violated | +| --- | --- | --- | +| VirtualServer → VirtualServerRoute | Every VirtualServer regex path must appear as a subroute | "subroute with path '...' is missing" | +| VirtualServerRoute → VirtualServer | Every subroute must be referenced by a VirtualServer regex path | "subroute path '...' is not referenced by any VS route" | + +{{< /table >}} + +## Configure multiple regex routes + +The following example shows a VirtualServer with five routes. Two case-sensitive regex routes delegate to `vsr-api`, and two case-insensitive regex routes delegate to `vsr-media`. The `/health` route is handled directly by the VirtualServer. + +### VirtualServer + +```yaml +apiVersion: k8s.nginx.org/v1 +kind: VirtualServer +metadata: + name: api-gateway +spec: + host: api-gateway.example.com + routes: + - path: /health + action: + return: + code: 200 + type: text/plain + body: "OK" + - path: "~/api/v1" + route: vsr-api + - path: "~/api/v2" + route: vsr-api + - path: "~*/images/jpg" + route: vsr-media + - path: "~*/images/png" + route: vsr-media +``` + +### VirtualServerRoute for API routes + +```yaml +apiVersion: k8s.nginx.org/v1 +kind: VirtualServerRoute +metadata: + name: vsr-api +spec: + host: api-gateway.example.com + subroutes: + - path: "~/api/v1" + action: + pass: api-v1 + - path: "~ /api/v2" + action: + pass: api-v2 +``` + +Notice that the second subroute uses `"~ /api/v2"` (with a space) while the VirtualServer declares `"~/api/v2"` (without a space). NGINX Ingress Controller normalizes both to the same value, so the configuration is valid. See [Path normalization](#path-normalization) for details. + +### VirtualServerRoute for media routes + +```yaml +apiVersion: k8s.nginx.org/v1 +kind: VirtualServerRoute +metadata: + name: vsr-media +spec: + host: api-gateway.example.com + subroutes: + - path: "~*/images/jpg" + action: + pass: images-jpg + - path: "~*/images/png" + action: + pass: images-png +``` + +### Generated NGINX configuration + +Each subroute produces a separate `location` block. The generated NGINX configuration for the four regex subroutes looks like this: + +```nginx +location ~ "/api/v1" { + ... +} + +location ~ "/api/v2" { + ... +} + +location ~* "/images/jpg" { + ... +} + +location ~* "/images/png" { + ... +} +``` + +### Request routing + +{{< table >}} + +| Request URI | Matching location | VirtualServerRoute | +| --- | --- | --- | +| `/health` | `/health` (prefix, direct VirtualServer action) | None | +| `/api/v1` | `~ "/api/v1"` | `vsr-api` | +| `/api/v2` | `~ "/api/v2"` | `vsr-api` | +| `/images/jpg` | `~* "/images/jpg"` | `vsr-media` | +| `/images/png` | `~* "/images/png"` | `vsr-media` | + +{{< /table >}} + +## Path normalization + +NGINX Ingress Controller strips whitespace between the regex modifier (`~` or `~*`) and the path before comparing values. This means `"~/api/v1"` and `"~ /api/v1"` normalize to the same value. + +Normalization applies to all path comparisons: + +- **Set match validation**: A VirtualServer path `"~/api/v2"` matches a VirtualServerRoute subroute `"~ /api/v2"` because both normalize to `"~/api/v2"`. +- **Duplicate detection**: If a single VirtualServerRoute contains both `"~*/images/jpg"` and `"~* /images/jpg"` as subroutes, they normalize to the same value and NGINX Ingress Controller rejects the VirtualServerRoute with a duplicate path error. + +{{< call-out "important" >}} +Using `"~ /api/v1"` in a VirtualServerRoute to match `"~/api/v1"` in a VirtualServer is valid — the paths are in different resources and represent the same logical route. Having both `"~/api/v1"` and `"~ /api/v1"` as separate subroutes in the **same** VirtualServerRoute is invalid — they resolve to the same normalized path and are treated as duplicates. +{{< /call-out >}} + +## Validation rules + +NGINX Ingress Controller enforces the following rules for regex route delegation: + +- Every VirtualServer regex path referencing a VirtualServerRoute must have a matching subroute in that VirtualServerRoute. +- Every subroute in the VirtualServerRoute must be referenced by a VirtualServer regex path. +- Subroute paths must be unique after normalization. Paths that differ only in whitespace between the modifier and the URI are treated as duplicates. +- All VirtualServer routes referencing the same VirtualServerRoute must use the same modifier category. You can't have a regex route (`~`) and a prefix route (`/`) both referencing the same VirtualServerRoute. +- Case-sensitive (`~`) and case-insensitive (`~*`) modifiers can reference the same VirtualServerRoute because both are in the regex category. +- Exact match routes (`=`) still require exactly one subroute. Only regex routes support multiple subroutes per VirtualServerRoute. + +## Validation errors + +When NGINX Ingress Controller detects a validation failure, it rejects the VirtualServerRoute and the VirtualServer enters a warning state. Other VirtualServerRoutes and direct VirtualServer routes continue to serve traffic normally. + +### Missing subroute + +This error occurs when the VirtualServer references a regex path through a VirtualServerRoute, but the VirtualServerRoute doesn't have a subroute for that path. + +For example, the VirtualServer references both `~/api/v1` and `~/api/v2` through `vsr-api`, but the VirtualServerRoute only defines `~/api/v1`: + +```yaml +apiVersion: k8s.nginx.org/v1 +kind: VirtualServerRoute +metadata: + name: vsr-api +spec: + host: api-gateway.example.com + subroutes: + - path: "~/api/v1" + action: + pass: api-v1 +``` + +NGINX Ingress Controller rejects the VirtualServerRoute with the following error: + +```text +VirtualServerRoute default/vsr-api is invalid: spec.subroutes: Invalid value: +"subroutes": subroute with path '~/api/v2' is missing; all VS route paths must +be covered by VSR subroutes +``` + +To fix this, add the missing subroute (`~/api/v2`) to the VirtualServerRoute, or remove the VirtualServer route that references it. + +### Extra subroute + +This error occurs when the VirtualServerRoute has a subroute that no VirtualServer route references. + +For example, the VirtualServerRoute defines `~/api/v1`, `~/api/v2`, and `~/api/v3`, but the VirtualServer only references `~/api/v1` and `~/api/v2`: + +```yaml +apiVersion: k8s.nginx.org/v1 +kind: VirtualServerRoute +metadata: + name: vsr-api +spec: + host: api-gateway.example.com + subroutes: + - path: "~/api/v1" + action: + pass: api-v1 + - path: "~/api/v2" + action: + pass: api-v2 + - path: "~/api/v3" + action: + pass: api-v3 +``` + +NGINX Ingress Controller rejects the VirtualServerRoute with the following error: + +```text +VirtualServerRoute default/vsr-api is invalid: spec.subroutes[2].path: Invalid +value: "~/api/v3": subroute path '~/api/v3' is not referenced by any VS route; +all VSR subroutes must be referenced +``` + +To fix this, remove the extra subroute from the VirtualServerRoute, or add a corresponding regex route in the VirtualServer. + +### Duplicate paths after normalization + +This error occurs when two subroutes in the same VirtualServerRoute resolve to the same path after normalization. Because NGINX Ingress Controller strips whitespace between the modifier and the URI, paths that appear different in YAML can be identical after normalization. + +For example, the following VirtualServerRoute has `"~/api/v1"` and `"~ /api/v1"` as separate subroutes: + +```yaml +apiVersion: k8s.nginx.org/v1 +kind: VirtualServerRoute +metadata: + name: vsr-api +spec: + host: api-gateway.example.com + subroutes: + - path: "~/api/v1" + action: + pass: api-v1 + - path: "~ /api/v1" + action: + pass: api-v1-alt +``` + +Both paths normalize to `"~/api/v1"`. NGINX Ingress Controller rejects the VirtualServerRoute: + +```text +VirtualServerRoute default/vsr-api is invalid: spec.subroutes[0].path: +Duplicate value: "~/api/v1", spec.subroutes[1].path: Duplicate value: +"~ /api/v1" +``` + +To fix this, remove the duplicate subroute. If you need to match the same pattern, use a single subroute. + +## See also + +- [VirtualServer and VirtualServerRoute resources]({{< ref "/nic/configuration/virtualserver-and-virtualserverroute-resources.md" >}}) for the full field reference. +- NGINX [location directive documentation](https://nginx.org/en/docs/http/ngx_http_core_module.html#location) for how NGINX evaluates regex locations. +- [Multiple regex routes examples](https://github.com/nginx/kubernetes-ingress/tree/v{{< nic-version >}}/examples/custom-resources/vsr-multiple-regex-routes) on GitHub for runnable manifests and additional error case examples. diff --git a/content/nic/configuration/virtualserver-and-virtualserverroute-resources.md b/content/nic/configuration/virtualserver-and-virtualserverroute-resources.md index 07ed69fd4..ff5d47380 100644 --- a/content/nic/configuration/virtualserver-and-virtualserverroute-resources.md +++ b/content/nic/configuration/virtualserver-and-virtualserverroute-resources.md @@ -377,7 +377,7 @@ action: |Field | Description | Type | Required | | ---| ---| ---| --- | -|``path`` | The path of the subroute. NGINX will match it against the URI of a request. Possible values are: a prefix ( ``/`` , ``/path`` ), an exact match ( ``=/exact/match`` ), a case insensitive regular expression ( ``~*^/Bar.*\.jpg`` ) or a case sensitive regular expression ( ``~^/foo.*\.jpg`` ). In the case of a prefix, the path must start with the same path as the path of the route of the VirtualServer that references this resource. In the case of an exact or regex match, the path must be the same as the path of the route of the VirtualServer that references this resource. A matching path of the route of the VirtualServer but in different type is not accepted, e.g. a regex path (`~/match`) cannot be used with a prefix path in VirtualServer (`/match`) In the case of a prefix or an exact match, the path must not include any whitespace characters, ``{`` , ``}`` or ``;``. In the case of the regex matches, all double quotes ``"`` must be escaped and the match can't end in an unescaped backslash ``\``. The path must be unique among the paths of all subroutes of the VirtualServerRoute. | ``string`` | Yes | +|``path`` | The path of the subroute. NGINX will match it against the URI of a request. Possible values are: a prefix ( ``/`` , ``/path`` ), an exact match ( ``=/exact/match`` ), a case insensitive regular expression ( ``~*^/Bar.*\.jpg`` ) or a case sensitive regular expression ( ``~^/foo.*\.jpg`` ). In the case of a prefix, the path must start with the same path as the path of the route of the VirtualServer that references this resource. In the case of an exact match, the path must be the same as the path of the route of the VirtualServer that references this resource. In the case of regex matches, multiple VirtualServer regex routes (``~`` or ``~*``) can reference the same VirtualServerRoute; the subroutes must form an exact set match with those VirtualServer paths. See [Multiple regex routes in a VirtualServerRoute]({{< ref "/nic/configuration/multiple-regex-routes.md" >}}) for details. A matching path of the route of the VirtualServer but in different type is not accepted, e.g. a regex path (``~/match``) cannot be used with a prefix path in VirtualServer (``/match``). In the case of a prefix or an exact match, the path must not include any whitespace characters, ``{`` , ``}`` or ``;``. In the case of the regex matches, all double quotes ``"`` must be escaped and the match can't end in an unescaped backslash ``\``. Whitespace between the regex modifier and the path is stripped before comparison, so ``~/api`` and ``~ /api`` are treated as the same path. The path must be unique among the paths of all subroutes of the VirtualServerRoute after normalization. | ``string`` | Yes | |``policies`` | A list of policies. The policies override *all* policies defined in the route of the VirtualServer that references this resource. The policies also override the policies of the same type defined in the ``spec`` of the VirtualServer. See [Applying Policies]({{< ref "/nic/configuration/policy-resource.md#applying-policies" >}}) for more details. | [[]policy](#virtualserverpolicy) | No | |``action`` | The default action to perform for a request. | [action](#action) | No | |``dos`` | A reference to a DosProtectedResource, setting this enables DOS protection of the VirtualServerRoute subroute. | ``string`` | No | From 91b31ebcc6bc141099b9c1276fa821eb79a068de Mon Sep 17 00:00:00 2001 From: Gabor Javorszky Date: Tue, 26 May 2026 15:52:27 +0100 Subject: [PATCH 2/4] chore: move multi regex docs into vs/vsr docs --- .../configuration/multiple-regex-routes.md | 266 ------------------ ...server-and-virtualserverroute-resources.md | 262 ++++++++++++++++- 2 files changed, 261 insertions(+), 267 deletions(-) delete mode 100644 content/nic/configuration/multiple-regex-routes.md diff --git a/content/nic/configuration/multiple-regex-routes.md b/content/nic/configuration/multiple-regex-routes.md deleted file mode 100644 index bf58c94a6..000000000 --- a/content/nic/configuration/multiple-regex-routes.md +++ /dev/null @@ -1,266 +0,0 @@ ---- -title: Multiple regex routes in a VirtualServerRoute -toc: true -weight: 760 -f5-content-type: reference -f5-product: INGRESS -f5-docs: DOCS-XXXX ---- - -F5 NGINX Ingress Controller lets you reference the same VirtualServerRoute from multiple regex routes in a VirtualServer. This means you can group related regex paths by concern — for example, all `/api` paths go to one team's VirtualServerRoute and all `/images` paths go to another. - -## How it works - -When NGINX Ingress Controller processes a VirtualServer, it collects every regex route (`~` or `~*`) that references the same VirtualServerRoute. It then validates the collected VirtualServer paths against the VirtualServerRoute's subroutes as a single set. Each subroute produces a separate NGINX `location` block in the generated configuration. - -## Set match requirement - -The VirtualServer paths and VirtualServerRoute subroutes must form a **bidirectional set match**: - -- Every VirtualServer regex path that references the VirtualServerRoute must have a corresponding subroute. -- Every subroute in the VirtualServerRoute must be referenced by a VirtualServer regex path. - -If either side has a path the other doesn't, NGINX Ingress Controller rejects the VirtualServerRoute and the VirtualServer enters a warning state. - -{{< table >}} - -| Direction | Rule | Error if violated | -| --- | --- | --- | -| VirtualServer → VirtualServerRoute | Every VirtualServer regex path must appear as a subroute | "subroute with path '...' is missing" | -| VirtualServerRoute → VirtualServer | Every subroute must be referenced by a VirtualServer regex path | "subroute path '...' is not referenced by any VS route" | - -{{< /table >}} - -## Configure multiple regex routes - -The following example shows a VirtualServer with five routes. Two case-sensitive regex routes delegate to `vsr-api`, and two case-insensitive regex routes delegate to `vsr-media`. The `/health` route is handled directly by the VirtualServer. - -### VirtualServer - -```yaml -apiVersion: k8s.nginx.org/v1 -kind: VirtualServer -metadata: - name: api-gateway -spec: - host: api-gateway.example.com - routes: - - path: /health - action: - return: - code: 200 - type: text/plain - body: "OK" - - path: "~/api/v1" - route: vsr-api - - path: "~/api/v2" - route: vsr-api - - path: "~*/images/jpg" - route: vsr-media - - path: "~*/images/png" - route: vsr-media -``` - -### VirtualServerRoute for API routes - -```yaml -apiVersion: k8s.nginx.org/v1 -kind: VirtualServerRoute -metadata: - name: vsr-api -spec: - host: api-gateway.example.com - subroutes: - - path: "~/api/v1" - action: - pass: api-v1 - - path: "~ /api/v2" - action: - pass: api-v2 -``` - -Notice that the second subroute uses `"~ /api/v2"` (with a space) while the VirtualServer declares `"~/api/v2"` (without a space). NGINX Ingress Controller normalizes both to the same value, so the configuration is valid. See [Path normalization](#path-normalization) for details. - -### VirtualServerRoute for media routes - -```yaml -apiVersion: k8s.nginx.org/v1 -kind: VirtualServerRoute -metadata: - name: vsr-media -spec: - host: api-gateway.example.com - subroutes: - - path: "~*/images/jpg" - action: - pass: images-jpg - - path: "~*/images/png" - action: - pass: images-png -``` - -### Generated NGINX configuration - -Each subroute produces a separate `location` block. The generated NGINX configuration for the four regex subroutes looks like this: - -```nginx -location ~ "/api/v1" { - ... -} - -location ~ "/api/v2" { - ... -} - -location ~* "/images/jpg" { - ... -} - -location ~* "/images/png" { - ... -} -``` - -### Request routing - -{{< table >}} - -| Request URI | Matching location | VirtualServerRoute | -| --- | --- | --- | -| `/health` | `/health` (prefix, direct VirtualServer action) | None | -| `/api/v1` | `~ "/api/v1"` | `vsr-api` | -| `/api/v2` | `~ "/api/v2"` | `vsr-api` | -| `/images/jpg` | `~* "/images/jpg"` | `vsr-media` | -| `/images/png` | `~* "/images/png"` | `vsr-media` | - -{{< /table >}} - -## Path normalization - -NGINX Ingress Controller strips whitespace between the regex modifier (`~` or `~*`) and the path before comparing values. This means `"~/api/v1"` and `"~ /api/v1"` normalize to the same value. - -Normalization applies to all path comparisons: - -- **Set match validation**: A VirtualServer path `"~/api/v2"` matches a VirtualServerRoute subroute `"~ /api/v2"` because both normalize to `"~/api/v2"`. -- **Duplicate detection**: If a single VirtualServerRoute contains both `"~*/images/jpg"` and `"~* /images/jpg"` as subroutes, they normalize to the same value and NGINX Ingress Controller rejects the VirtualServerRoute with a duplicate path error. - -{{< call-out "important" >}} -Using `"~ /api/v1"` in a VirtualServerRoute to match `"~/api/v1"` in a VirtualServer is valid — the paths are in different resources and represent the same logical route. Having both `"~/api/v1"` and `"~ /api/v1"` as separate subroutes in the **same** VirtualServerRoute is invalid — they resolve to the same normalized path and are treated as duplicates. -{{< /call-out >}} - -## Validation rules - -NGINX Ingress Controller enforces the following rules for regex route delegation: - -- Every VirtualServer regex path referencing a VirtualServerRoute must have a matching subroute in that VirtualServerRoute. -- Every subroute in the VirtualServerRoute must be referenced by a VirtualServer regex path. -- Subroute paths must be unique after normalization. Paths that differ only in whitespace between the modifier and the URI are treated as duplicates. -- All VirtualServer routes referencing the same VirtualServerRoute must use the same modifier category. You can't have a regex route (`~`) and a prefix route (`/`) both referencing the same VirtualServerRoute. -- Case-sensitive (`~`) and case-insensitive (`~*`) modifiers can reference the same VirtualServerRoute because both are in the regex category. -- Exact match routes (`=`) still require exactly one subroute. Only regex routes support multiple subroutes per VirtualServerRoute. - -## Validation errors - -When NGINX Ingress Controller detects a validation failure, it rejects the VirtualServerRoute and the VirtualServer enters a warning state. Other VirtualServerRoutes and direct VirtualServer routes continue to serve traffic normally. - -### Missing subroute - -This error occurs when the VirtualServer references a regex path through a VirtualServerRoute, but the VirtualServerRoute doesn't have a subroute for that path. - -For example, the VirtualServer references both `~/api/v1` and `~/api/v2` through `vsr-api`, but the VirtualServerRoute only defines `~/api/v1`: - -```yaml -apiVersion: k8s.nginx.org/v1 -kind: VirtualServerRoute -metadata: - name: vsr-api -spec: - host: api-gateway.example.com - subroutes: - - path: "~/api/v1" - action: - pass: api-v1 -``` - -NGINX Ingress Controller rejects the VirtualServerRoute with the following error: - -```text -VirtualServerRoute default/vsr-api is invalid: spec.subroutes: Invalid value: -"subroutes": subroute with path '~/api/v2' is missing; all VS route paths must -be covered by VSR subroutes -``` - -To fix this, add the missing subroute (`~/api/v2`) to the VirtualServerRoute, or remove the VirtualServer route that references it. - -### Extra subroute - -This error occurs when the VirtualServerRoute has a subroute that no VirtualServer route references. - -For example, the VirtualServerRoute defines `~/api/v1`, `~/api/v2`, and `~/api/v3`, but the VirtualServer only references `~/api/v1` and `~/api/v2`: - -```yaml -apiVersion: k8s.nginx.org/v1 -kind: VirtualServerRoute -metadata: - name: vsr-api -spec: - host: api-gateway.example.com - subroutes: - - path: "~/api/v1" - action: - pass: api-v1 - - path: "~/api/v2" - action: - pass: api-v2 - - path: "~/api/v3" - action: - pass: api-v3 -``` - -NGINX Ingress Controller rejects the VirtualServerRoute with the following error: - -```text -VirtualServerRoute default/vsr-api is invalid: spec.subroutes[2].path: Invalid -value: "~/api/v3": subroute path '~/api/v3' is not referenced by any VS route; -all VSR subroutes must be referenced -``` - -To fix this, remove the extra subroute from the VirtualServerRoute, or add a corresponding regex route in the VirtualServer. - -### Duplicate paths after normalization - -This error occurs when two subroutes in the same VirtualServerRoute resolve to the same path after normalization. Because NGINX Ingress Controller strips whitespace between the modifier and the URI, paths that appear different in YAML can be identical after normalization. - -For example, the following VirtualServerRoute has `"~/api/v1"` and `"~ /api/v1"` as separate subroutes: - -```yaml -apiVersion: k8s.nginx.org/v1 -kind: VirtualServerRoute -metadata: - name: vsr-api -spec: - host: api-gateway.example.com - subroutes: - - path: "~/api/v1" - action: - pass: api-v1 - - path: "~ /api/v1" - action: - pass: api-v1-alt -``` - -Both paths normalize to `"~/api/v1"`. NGINX Ingress Controller rejects the VirtualServerRoute: - -```text -VirtualServerRoute default/vsr-api is invalid: spec.subroutes[0].path: -Duplicate value: "~/api/v1", spec.subroutes[1].path: Duplicate value: -"~ /api/v1" -``` - -To fix this, remove the duplicate subroute. If you need to match the same pattern, use a single subroute. - -## See also - -- [VirtualServer and VirtualServerRoute resources]({{< ref "/nic/configuration/virtualserver-and-virtualserverroute-resources.md" >}}) for the full field reference. -- NGINX [location directive documentation](https://nginx.org/en/docs/http/ngx_http_core_module.html#location) for how NGINX evaluates regex locations. -- [Multiple regex routes examples](https://github.com/nginx/kubernetes-ingress/tree/v{{< nic-version >}}/examples/custom-resources/vsr-multiple-regex-routes) on GitHub for runnable manifests and additional error case examples. diff --git a/content/nic/configuration/virtualserver-and-virtualserverroute-resources.md b/content/nic/configuration/virtualserver-and-virtualserverroute-resources.md index ff5d47380..eeef6aa17 100644 --- a/content/nic/configuration/virtualserver-and-virtualserverroute-resources.md +++ b/content/nic/configuration/virtualserver-and-virtualserverroute-resources.md @@ -377,7 +377,7 @@ action: |Field | Description | Type | Required | | ---| ---| ---| --- | -|``path`` | The path of the subroute. NGINX will match it against the URI of a request. Possible values are: a prefix ( ``/`` , ``/path`` ), an exact match ( ``=/exact/match`` ), a case insensitive regular expression ( ``~*^/Bar.*\.jpg`` ) or a case sensitive regular expression ( ``~^/foo.*\.jpg`` ). In the case of a prefix, the path must start with the same path as the path of the route of the VirtualServer that references this resource. In the case of an exact match, the path must be the same as the path of the route of the VirtualServer that references this resource. In the case of regex matches, multiple VirtualServer regex routes (``~`` or ``~*``) can reference the same VirtualServerRoute; the subroutes must form an exact set match with those VirtualServer paths. See [Multiple regex routes in a VirtualServerRoute]({{< ref "/nic/configuration/multiple-regex-routes.md" >}}) for details. A matching path of the route of the VirtualServer but in different type is not accepted, e.g. a regex path (``~/match``) cannot be used with a prefix path in VirtualServer (``/match``). In the case of a prefix or an exact match, the path must not include any whitespace characters, ``{`` , ``}`` or ``;``. In the case of the regex matches, all double quotes ``"`` must be escaped and the match can't end in an unescaped backslash ``\``. Whitespace between the regex modifier and the path is stripped before comparison, so ``~/api`` and ``~ /api`` are treated as the same path. The path must be unique among the paths of all subroutes of the VirtualServerRoute after normalization. | ``string`` | Yes | +|``path`` | The path of the subroute. NGINX will match it against the URI of a request. Possible values are: a prefix ( ``/`` , ``/path`` ), an exact match ( ``=/exact/match`` ), a case insensitive regular expression ( ``~*^/Bar.*\.jpg`` ) or a case sensitive regular expression ( ``~^/foo.*\.jpg`` ). In the case of a prefix, the path must start with the same path as the path of the route of the VirtualServer that references this resource. In the case of an exact match, the path must be the same as the path of the route of the VirtualServer that references this resource. In the case of regex matches, multiple VirtualServer regex routes (``~`` or ``~*``) can reference the same VirtualServerRoute; the subroutes must form an exact set match with those VirtualServer paths. See [Multiple regex routes in a VirtualServerRoute]({{< ref "#multiple-regex-routes-in-a-virtualserverroute" >}}) for details. A matching path of the route of the VirtualServer but in different type is not accepted, e.g. a regex path (``~/match``) cannot be used with a prefix path in VirtualServer (``/match``). In the case of a prefix or an exact match, the path must not include any whitespace characters, ``{`` , ``}`` or ``;``. In the case of the regex matches, all double quotes ``"`` must be escaped and the match can't end in an unescaped backslash ``\``. Whitespace between the regex modifier and the path is stripped before comparison, so ``~/api`` and ``~ /api`` are treated as the same path. The path must be unique among the paths of all subroutes of the VirtualServerRoute after normalization. | ``string`` | Yes | |``policies`` | A list of policies. The policies override *all* policies defined in the route of the VirtualServer that references this resource. The policies also override the policies of the same type defined in the ``spec`` of the VirtualServer. See [Applying Policies]({{< ref "/nic/configuration/policy-resource.md#applying-policies" >}}) for more details. | [[]policy](#virtualserverpolicy) | No | |``action`` | The default action to perform for a request. | [action](#action) | No | |``dos`` | A reference to a DosProtectedResource, setting this enables DOS protection of the VirtualServerRoute subroute. | ``string`` | No | @@ -1117,6 +1117,266 @@ NGINX Ingress Controller validates VirtualServerRoute resources in a similar way **Note**: If you make an existing resource invalid, NGINX Ingress Controller will reject it and remove the corresponding configuration from NGINX. +## Multiple regex routes in a VirtualServerRoute + +F5 NGINX Ingress Controller lets you reference the same VirtualServerRoute from multiple regex routes in a VirtualServer. This means you can group related regex paths by concern — for example, all `/api` paths go to one team's VirtualServerRoute and all `/images` paths go to another. + +### How it works + +When NGINX Ingress Controller processes a VirtualServer, it collects every regex route (`~` or `~*`) that references the same VirtualServerRoute. It then validates the collected VirtualServer paths against the VirtualServerRoute's subroutes as a single set. Each subroute produces a separate NGINX `location` block in the generated configuration. + +### Set match requirement + +The VirtualServer paths and VirtualServerRoute subroutes must form a **bidirectional set match**: + +- Every VirtualServer regex path that references the VirtualServerRoute must have a corresponding subroute. +- Every subroute in the VirtualServerRoute must be referenced by a VirtualServer regex path. + +If either side has a path the other doesn't, NGINX Ingress Controller rejects the VirtualServerRoute and the VirtualServer enters a warning state. + +{{< table >}} + +| Direction | Rule | Error if violated | +| --- | --- | --- | +| VirtualServer → VirtualServerRoute | Every VirtualServer regex path must appear as a subroute | "subroute with path '...' is missing" | +| VirtualServerRoute → VirtualServer | Every subroute must be referenced by a VirtualServer regex path | "subroute path '...' is not referenced by any VS route" | + +{{< /table >}} + +### Configure multiple regex routes + +The following example shows a VirtualServer with five routes. Two case-sensitive regex routes delegate to `vsr-api`, and two case-insensitive regex routes delegate to `vsr-media`. The `/health` route is handled directly by the VirtualServer. + +#### VirtualServer + +```yaml +apiVersion: k8s.nginx.org/v1 +kind: VirtualServer +metadata: + name: api-gateway +spec: + host: api-gateway.example.com + routes: + - path: /health + action: + return: + code: 200 + type: text/plain + body: "OK" + - path: "~/api/v1" + route: vsr-api + - path: "~/api/v2" + route: vsr-api + - path: "~*/images/jpg" + route: vsr-media + - path: "~*/images/png" + route: vsr-media +``` + +#### VirtualServerRoute for API routes + +```yaml +apiVersion: k8s.nginx.org/v1 +kind: VirtualServerRoute +metadata: + name: vsr-api +spec: + host: api-gateway.example.com + subroutes: + - path: "~/api/v1" + action: + pass: api-v1 + - path: "~ /api/v2" + action: + pass: api-v2 +``` + +Notice that the second subroute uses `"~ /api/v2"` (with a space) while the VirtualServer declares `"~/api/v2"` (without a space). NGINX Ingress Controller normalizes both to the same value, so the configuration is valid. See [Path normalization](#path-normalization) for details. + +#### VirtualServerRoute for media routes + +```yaml +apiVersion: k8s.nginx.org/v1 +kind: VirtualServerRoute +metadata: + name: vsr-media +spec: + host: api-gateway.example.com + subroutes: + - path: "~*/images/jpg" + action: + pass: images-jpg + - path: "~*/images/png" + action: + pass: images-png +``` + +#### Generated NGINX configuration + +Each subroute produces a separate `location` block. The generated NGINX configuration for the four regex subroutes looks like this: + +```nginx +location ~ "/api/v1" { + ... +} + +location ~ "/api/v2" { + ... +} + +location ~* "/images/jpg" { + ... +} + +location ~* "/images/png" { + ... +} +``` + +#### Request routing + +{{< table >}} + +| Request URI | Matching location | VirtualServerRoute | +| --- | --- | --- | +| `/health` | `/health` (prefix, direct VirtualServer action) | None | +| `/api/v1` | `~ "/api/v1"` | `vsr-api` | +| `/api/v2` | `~ "/api/v2"` | `vsr-api` | +| `/images/jpg` | `~* "/images/jpg"` | `vsr-media` | +| `/images/png` | `~* "/images/png"` | `vsr-media` | + +{{< /table >}} + +### Path normalization + +NGINX Ingress Controller strips whitespace between the regex modifier (`~` or `~*`) and the path before comparing values. This means `"~/api/v1"` and `"~ /api/v1"` normalize to the same value. + +Normalization applies to all path comparisons: + +- **Set match validation**: A VirtualServer path `"~/api/v2"` matches a VirtualServerRoute subroute `"~ /api/v2"` because both normalize to `"~/api/v2"`. +- **Duplicate detection**: If a single VirtualServerRoute contains both `"~*/images/jpg"` and `"~* /images/jpg"` as subroutes, they normalize to the same value and NGINX Ingress Controller rejects the VirtualServerRoute with a duplicate path error. + +{{< call-out "important" >}} +Using `"~ /api/v1"` in a VirtualServerRoute to match `"~/api/v1"` in a VirtualServer is valid — the paths are in different resources and represent the same logical route. Having both `"~/api/v1"` and `"~ /api/v1"` as separate subroutes in the **same** VirtualServerRoute is invalid — they resolve to the same normalized path and are treated as duplicates. +{{< /call-out >}} + +### Validation rules + +NGINX Ingress Controller enforces the following rules for regex route delegation: + +- Every VirtualServer regex path referencing a VirtualServerRoute must have a matching subroute in that VirtualServerRoute. +- Every subroute in the VirtualServerRoute must be referenced by a VirtualServer regex path. +- Subroute paths must be unique after normalization. Paths that differ only in whitespace between the modifier and the URI are treated as duplicates. +- All VirtualServer routes referencing the same VirtualServerRoute must use the same modifier category. You can't have a regex route (`~`) and a prefix route (`/`) both referencing the same VirtualServerRoute. +- Case-sensitive (`~`) and case-insensitive (`~*`) modifiers can reference the same VirtualServerRoute because both are in the regex category. +- Exact match routes (`=`) still require exactly one subroute. Only regex routes support multiple subroutes per VirtualServerRoute. + +### Validation errors + +When NGINX Ingress Controller detects a validation failure, it rejects the VirtualServerRoute and the VirtualServer enters a warning state. Other VirtualServerRoutes and direct VirtualServer routes continue to serve traffic normally. + +#### Missing subroute + +This error occurs when the VirtualServer references a regex path through a VirtualServerRoute, but the VirtualServerRoute doesn't have a subroute for that path. + +For example, the VirtualServer references both `~/api/v1` and `~/api/v2` through `vsr-api`, but the VirtualServerRoute only defines `~/api/v1`: + +```yaml +apiVersion: k8s.nginx.org/v1 +kind: VirtualServerRoute +metadata: + name: vsr-api +spec: + host: api-gateway.example.com + subroutes: + - path: "~/api/v1" + action: + pass: api-v1 +``` + +NGINX Ingress Controller rejects the VirtualServerRoute with the following error: + +```text +VirtualServerRoute default/vsr-api is invalid: spec.subroutes: Invalid value: +"subroutes": subroute with path '~/api/v2' is missing; all VS route paths must +be covered by VSR subroutes +``` + +To fix this, add the missing subroute (`~/api/v2`) to the VirtualServerRoute, or remove the VirtualServer route that references it. + +#### Extra subroute + +This error occurs when the VirtualServerRoute has a subroute that no VirtualServer route references. + +For example, the VirtualServerRoute defines `~/api/v1`, `~/api/v2`, and `~/api/v3`, but the VirtualServer only references `~/api/v1` and `~/api/v2`: + +```yaml +apiVersion: k8s.nginx.org/v1 +kind: VirtualServerRoute +metadata: + name: vsr-api +spec: + host: api-gateway.example.com + subroutes: + - path: "~/api/v1" + action: + pass: api-v1 + - path: "~/api/v2" + action: + pass: api-v2 + - path: "~/api/v3" + action: + pass: api-v3 +``` + +NGINX Ingress Controller rejects the VirtualServerRoute with the following error: + +```text +VirtualServerRoute default/vsr-api is invalid: spec.subroutes[2].path: Invalid +value: "~/api/v3": subroute path '~/api/v3' is not referenced by any VS route; +all VSR subroutes must be referenced +``` + +To fix this, remove the extra subroute from the VirtualServerRoute, or add a corresponding regex route in the VirtualServer. + +#### Duplicate paths after normalization + +This error occurs when two subroutes in the same VirtualServerRoute resolve to the same path after normalization. Because NGINX Ingress Controller strips whitespace between the modifier and the URI, paths that appear different in YAML can be identical after normalization. + +For example, the following VirtualServerRoute has `"~/api/v1"` and `"~ /api/v1"` as separate subroutes: + +```yaml +apiVersion: k8s.nginx.org/v1 +kind: VirtualServerRoute +metadata: + name: vsr-api +spec: + host: api-gateway.example.com + subroutes: + - path: "~/api/v1" + action: + pass: api-v1 + - path: "~ /api/v1" + action: + pass: api-v1-alt +``` + +Both paths normalize to `"~/api/v1"`. NGINX Ingress Controller rejects the VirtualServerRoute: + +```text +VirtualServerRoute default/vsr-api is invalid: spec.subroutes[0].path: +Duplicate value: "~/api/v1", spec.subroutes[1].path: Duplicate value: +"~ /api/v1" +``` + +To fix this, remove the duplicate subroute. If you need to match the same pattern, use a single subroute. + +### See also + +- [VirtualServer and VirtualServerRoute resources]({{< ref "/nic/configuration/virtualserver-and-virtualserverroute-resources.md" >}}) for the full field reference. +- NGINX [location directive documentation](https://nginx.org/en/docs/http/ngx_http_core_module.html#location) for how NGINX evaluates regex locations. +- [Multiple regex routes examples](https://github.com/nginx/kubernetes-ingress/tree/v{{< nic-version >}}/examples/custom-resources/vsr-multiple-regex-routes) on GitHub for runnable manifests and additional error case examples. + ## Customization using ConfigMap You can customize the NGINX configuration for VirtualServer and VirtualServerRoutes resources using the [ConfigMap]({{< ref "/nic/configuration/global-configuration/configmap-resource.md" >}}). Most of the ConfigMap keys are supported, with the following exceptions: From 31a66eac7144bd9e2995eb5f631aba9c462969e5 Mon Sep 17 00:00:00 2001 From: Gabor Javorszky Date: Wed, 27 May 2026 15:06:20 +0100 Subject: [PATCH 3/4] chore: Remove unneeded mention of F5 again --- .../virtualserver-and-virtualserverroute-resources.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/nic/configuration/virtualserver-and-virtualserverroute-resources.md b/content/nic/configuration/virtualserver-and-virtualserverroute-resources.md index eeef6aa17..6790e3fd9 100644 --- a/content/nic/configuration/virtualserver-and-virtualserverroute-resources.md +++ b/content/nic/configuration/virtualserver-and-virtualserverroute-resources.md @@ -1119,7 +1119,7 @@ NGINX Ingress Controller validates VirtualServerRoute resources in a similar way ## Multiple regex routes in a VirtualServerRoute -F5 NGINX Ingress Controller lets you reference the same VirtualServerRoute from multiple regex routes in a VirtualServer. This means you can group related regex paths by concern — for example, all `/api` paths go to one team's VirtualServerRoute and all `/images` paths go to another. +NGINX Ingress Controller lets you reference the same VirtualServerRoute from multiple regex routes in a VirtualServer. This means you can group related regex paths by concern — for example, all `/api` paths go to one team's VirtualServerRoute and all `/images` paths go to another. ### How it works From c551ba434b2bc50cd2e7354a9cdde2ce511f8a38 Mon Sep 17 00:00:00 2001 From: Gabor Javorszky Date: Wed, 27 May 2026 15:28:10 +0100 Subject: [PATCH 4/4] fix: wording on vs/vsr bidirectional set --- .../virtualserver-and-virtualserverroute-resources.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/nic/configuration/virtualserver-and-virtualserverroute-resources.md b/content/nic/configuration/virtualserver-and-virtualserverroute-resources.md index 6790e3fd9..3ec663f4d 100644 --- a/content/nic/configuration/virtualserver-and-virtualserverroute-resources.md +++ b/content/nic/configuration/virtualserver-and-virtualserverroute-resources.md @@ -1132,7 +1132,7 @@ The VirtualServer paths and VirtualServerRoute subroutes must form a **bidirecti - Every VirtualServer regex path that references the VirtualServerRoute must have a corresponding subroute. - Every subroute in the VirtualServerRoute must be referenced by a VirtualServer regex path. -If either side has a path the other doesn't, NGINX Ingress Controller rejects the VirtualServerRoute and the VirtualServer enters a warning state. +If a VirtualServer has a path that the referenced VirtualServerRoute does not, or if a VirtualServerRoute has a subpath that isn't present in the VirtualServer, NGINX Ingress Controller rejects the VirtualServerRoute and the VirtualServer enters a warning state. {{< table >}}