+```
+
+However, by explicitly configuring a Route with `preserve_host=true`:
+
+```json
+{
+ "hosts": ["service.com"],
+ "preserve_host": true,
+ "service": {
+ "id": "..."
+ }
+}
+```
+
+And assuming the same request from the client:
+
+```http
+GET / HTTP/1.1
+Host: service.com
+```
+
+{{site.base_gateway}} would preserve the Host on the client request and would send the following
+upstream request instead:
+
+```http
+GET / HTTP/1.1
+Host: service.com
+```
+
+
+
+#### path_handling
+
+
+
+The `path_handling` parameter accepts `v0` or `v1`.
+
+* `v0` is the behavior used in Kong 0.x, 2.x, and 3.x. It treats `service.path`, `route.path` and request path as *segments* of a URL. It will always join them via slashes. Given a service path `/s`, route path `/r` and request path `/re`, the concatenated path will be `/s/re`. If the resulting path is a single slash, no further transformation is done to it. If it's longer, then the trailing slash is removed.
+
+* `v1` is the behavior used in Kong 1.x. It treats `service.path` as a *prefix*, and ignores the initial slashes of the request and route paths. Given service path `/s`, route path `/r` and request path `/re`, the concatenated path will be `/sre`.
+
+{:.warning}
+> `path_handling` v1 is not supported in the `expressions` router and may be removed in a future version of {{ site.base_gateway }}. We **strongly** recommend using `v0`.
+
+Both versions of the algorithm detect "double slashes" when combining paths, replacing them by single
+slashes.
+
+
+
+Expand this block to see a table showing detailed v0
and v1
examples
+
+
+
+
+
+ service.path |
+ route.path |
+ request |
+ route.strip_path |
+ route.path_handling |
+ request path |
+ upstream path |
+
+
+
+
+ /s |
+ /fv0 |
+ req |
+ false |
+ v0 |
+ /fv0/req |
+ /s/fv0/req |
+
+
+ /s |
+ /fv0 |
+ blank |
+ false |
+ v0 |
+ /fv0 |
+ /s/fv0 |
+
+
+ /s |
+ /fv1 |
+ req |
+ false |
+ v1 |
+ /fv1/req |
+ /sfv1/req |
+
+
+ /s |
+ /fv1 |
+ blank |
+ false |
+ v1 |
+ /fv1 |
+ /sfv1 |
+
+
+ /s |
+ /tv0 |
+ req |
+ true |
+ v0 |
+ /tv0/req |
+ /s/req |
+
+
+ /s |
+ /tv0 |
+ blank |
+ true |
+ v0 |
+ /tv0 |
+ /s |
+
+
+ /s |
+ /tv1 |
+ req |
+ true |
+ v1 |
+ /tv1/req |
+ /s/req |
+
+
+ /s |
+ /tv1 |
+ blank |
+ true |
+ v1 |
+ /tv1 |
+ /s |
+
+
+ /s |
+ /fv0/ |
+ req |
+ false |
+ v0 |
+ /fv0/req |
+ /s/fv0/req |
+
+
+ /s |
+ /fv0/ |
+ blank |
+ false |
+ v0 |
+ /fv0/ |
+ /s/fv01/ |
+
+
+ /s |
+ /fv1/ |
+ req |
+ false |
+ v1 |
+ /fv1/req |
+ /sfv1/req |
+
+
+ /s |
+ /fv1/ |
+ blank |
+ false |
+ v1 |
+ /fv1/ |
+ /sfv1/ |
+
+
+ /s |
+ /tv0/ |
+ req |
+ true |
+ v0 |
+ /tv0/req |
+ /s/req |
+
+
+ /s |
+ /tv0/ |
+ blank |
+ true |
+ v0 |
+ /tv0/ |
+ /s/ |
+
+
+ /s |
+ /tv1/ |
+ req |
+ true |
+ v1 |
+ /tv1/req |
+ /sreq |
+
+
+ /s |
+ /tv1/ |
+ blank |
+ true |
+ v1 |
+ /tv1/ |
+ /s |
+
+
+
+
+
### Routing performance recommendations
diff --git a/app/_gateway_entities/service.md b/app/_gateway_entities/service.md
index 6b9673c52..097591108 100644
--- a/app/_gateway_entities/service.md
+++ b/app/_gateway_entities/service.md
@@ -4,7 +4,7 @@ content_type: reference
entities:
- service
-description: A Gateway Service is an abstraction of an upstream application that services requests.
+description: A Gateway Service represents your actual backend API or microservice.
related_resources:
- text: Routes entity
@@ -34,17 +34,15 @@ api_specs:
## What is a Gateway Service?
-A Gateway Service is an abstraction of an upstream application that services requests.
-Services can store collections of objects like plugin configurations, and policies, and they can be associated with routes.
+A Gateway Service represents your actual backend API or microservice.
-When defining a Service, the administrator provides a name and the upstream application connection information.
-The connection details can be provided in the URL field as a single string, or by providing individual values for protocol, host, port, and path individually.
+For simple deployments, the upstream URL can be provided directly in the Service. For sophisticated traffic management needs, a Service can point at an [Upstream](/gateway/entities/upstream/).
-Gateway Services have a one-to-many relationship with upstream applications, which allows administrators to create sophisticated traffic management behaviors.
+Gateway Services, in conjunction with [Routes](/gateway/entities/route/), let you expose your services to clients with {{site.base_gateway}}.
-Gateway Services, in conjunction with [Routes](/gateway/entities/route/), let you expose your services to clients with {{site.base_gateway}}.
-{{site.base_gateway}} abstracts the service from the clients by using Routes.
-Since the client always calls the Route, changes to the Services (like versioning) don't impact how clients make the call.
+[Plugins](/gateway/entities/plugin/) can be attached to a Service, and will run against every request that triggers a request to the Service that they're attached to.
+
+
{% mermaid %}
flowchart LR
@@ -70,6 +68,8 @@ flowchart LR
{% endmermaid %}
+
+
## Schema
{% entity_schema %}
diff --git a/app/_gateway_entities/target.md b/app/_gateway_entities/target.md
index ddf3d2f53..29db28136 100644
--- a/app/_gateway_entities/target.md
+++ b/app/_gateway_entities/target.md
@@ -28,12 +28,25 @@ schema:
## What is a Target?
A Target is an IP address/hostname with a port that identifies an instance of a backend service.
-Each [Upstream](/gateway/entities/upstream/) can have many Targets. Targets are used by Upstreams for [load balancing](https://docs.konghq.com/gateway/latest/how-kong-works/load-balancing/). For example, if you have an `example_upstream` Upstream, you can point it to two different Targets: `httpbin.konghq.com` and `httpbun.com`. This is so that if one of the servers (like `httpbin.konghq.com`) is unavailable, it automatically detects the problem and routes all traffic to the working server (`httpbun.com`).
+Each [Upstream](/gateway/entities/upstream/) can have many Targets. Targets are used by Upstreams for [load balancing](/gateway/entities/upstream/#load-balancing-algorithms). For example, if you have an `example_upstream` Upstream, you can point it to two different Targets: `httpbin.konghq.com` and `httpbun.com`. This is so that if one of the servers (like `httpbin.konghq.com`) is unavailable, it automatically detects the problem and routes all traffic to the working server (`httpbun.com`).
The following diagram illustrates how Targets are used by Upstreams for load balancing:
{% include entities/upstreams-targets-diagram.md %}
+## Using hostnames
+
+A `target` can also have a hostname instead of an IP address.
+In that case, the name is resolved and all entries found are individually added to the load balancer.
+
+For example, let's say you add `api.host.com:123` with `weight=100`:
+
+* If the hostname `api.host.com` resolves to an A record with 2 IP addresses, both IP addresses are added as a target, each with `weight=100` and port 123.
+* If the hostname resolves to an SRV record, then the `port` and `weight` fields from the DNS record are used, and override the port and weight set in the Target.
+
+The balancer honors the DNS record's `ttl` setting. Upon expiry, it queries the nameserver and updates the balancer.
+When a DNS record has `ttl=0`, the hostname is added as a single target, with the specified weight. The nameserver is queried for every request, adding latency to the request.
+
## Schema
{% entity_schema %}
diff --git a/app/_gateway_entities/upstream.md b/app/_gateway_entities/upstream.md
index 80ce4567e..a22e2b39f 100644
--- a/app/_gateway_entities/upstream.md
+++ b/app/_gateway_entities/upstream.md
@@ -26,6 +26,8 @@ related_resources:
url: /gateway/routing/
- text: Expressions router
url: /gateway/routing/expressions/
+ - text: Health checks and circuit breakers
+ url: /gateway/health-checks-circuit-breakers/
schema:
api: gateway/admin-ee
@@ -34,18 +36,19 @@ schema:
## What is an Upstream?
-An Upstream refers to the service applications sitting behind {{site.base_gateway}}, to which client requests are forwarded. In {{site.base_gateway}}, an Upstream represents a virtual hostname and can be used to [health check](https://docs.konghq.com/gateway/latest/how-kong-works/health-checks/#active-health-checks), [circuit break](https://docs.konghq.com/gateway/latest/how-kong-works/health-checks/#passive-health-checks-circuit-breakers), and [load balance](https://docs.konghq.com/gateway/latest/how-kong-works/load-balancing/) incoming requests over multiple [Gateway Services](/gateway/entities/service/). In addition, the Upstream entity has more advanced functionality algorithms like least-connections, consistent-hashing, and lowest-latency.
+An Upstream refers to the service applications sitting behind {{site.base_gateway}}, to which client requests are forwarded.
+In {{site.base_gateway}}, an Upstream represents a virtual hostname and can be used to [health check](/gateway/health-checks-circuit-breakers/), [circuit break](/gateway/health-checks-circuit-breakers/), and [load balance](#load-balancing-algorithms) incoming requests over multiple [Gateway Services](/gateway/entities/service/). In addition, the Upstream entity has more advanced functionality algorithms like least-connections, consistent-hashing, and lowest-latency.
## Upstream and Gateway Service interaction
-You can configure a Service to point to an Upstream instead of a host.
-For example, if you have a Service called `example_service` and an Upstream called `example_upstream`, you can point `example_service` to `example_upstream` instead of specifying a host.
-The `example_upstream` Upstream can then point to two different [Targets](/gateway/entities/target/): `httpbin.konghq.com` and `httpbun.com`.
+You can configure a Service to point to an Upstream instead of a host.
+For example, if you have a Service called `example_service` and an Upstream called `example_upstream`, you can point `example_service` to `example_upstream` instead of specifying a host.
+The `example_upstream` Upstream can then point to two different [Targets](/gateway/entities/target/): `httpbin.konghq.com` and `httpbun.com`.
In a real environment, the Upstream points to the same Service running on multiple systems.
-This setup allows you to load balance between upstream targets.
-For example, if an application is deployed across two different servers or upstream targets, {{site.base_gateway}} needs to load balance across both servers.
-If one of the servers (like `httpbin.konghq.com` in the previous example) is unavailable, it automatically detects the problem and routes all traffic to the working server (`httpbun.com`).
+This setup allows you to load balance between upstream targets.
+For example, if an application is deployed across two different servers or upstream targets, {{site.base_gateway}} needs to load balance across both servers.
+If one of the servers (like `httpbin.konghq.com` in the previous example) is unavailable, it automatically detects the problem and routes all traffic to the working server (`httpbun.com`).
The following diagram shows how Upstreams interact with other {{site.base_gateway}} entities:
@@ -55,11 +58,111 @@ The following diagram shows how Upstreams interact with other {{site.base_gatewa
The following are examples of common use cases for Upstreams:
-| Use case | Description |
-|----------|-------------|
-| Load balance | When an Upstream points to multiple upstream targets, you can configure the Upstream entity to load balance traffic between the targets. If you don't need to load balance, we recommend using the `host` header on a [Route](/gateway/entities/route/) as the preferred method for routing a request and proxying traffic.|
-| Health check | Configure Upstreams to dynamically mark a target as healthy or unhealthy. This is an active check where a specific HTTP or HTTPS endpoint in the target is periodically requested and the health of the target is determined based on its response. |
-| Circuit break | Configure Upstreams to allow {{site.base_gateway}} to passively analyze the ongoing traffic being proxied and determine the health of targets based on their behavior responding to requests.
**Note:** This feature is not supported in hybrid mode. |
+| Use case | Description |
+| ------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| Load balance | When an Upstream points to multiple upstream targets, you can configure the Upstream entity to load balance traffic between the targets. If you don't need to load balance, we recommend using the `host` header on a [Route](/gateway/entities/route/) as the preferred method for routing a request and proxying traffic. |
+| Health check | Configure Upstreams to dynamically mark a target as healthy or unhealthy. This is an active check where a specific HTTP or HTTPS endpoint in the target is periodically requested and the health of the target is determined based on its response. |
+| Circuit break | Configure Upstreams to allow {{site.base_gateway}} to passively analyze the ongoing traffic being proxied and determine the health of targets based on their behavior responding to requests.
**Note:** This feature is not supported in hybrid mode. |
+
+## Load balancing algorithms
+
+The load balancer supports the following load-balancing algorithms:
+
+- `round-robin`
+- `consistent-hashing`
+- `least-connections`
+- `latency`
+
+### Round-Robin
+
+The round-robin algorithm is done in a weighted manner. It provides identical
+results to the default DNS based load-balancing, but due to it being an `upstream`,
+the additional features for health-checks and circuit-breakers are also available.
+
+When choosing this algorithm, consider the following:
+
+- Provides good distribution of requests.
+- Remains fairly static, as only DNS updates or `target` updates can influence the distribution of traffic.
+- Doesn't improve cache-hit ratios.
+
+### Consistent-Hashing
+
+With the consistent-hashing algorithm, a configurable client input is used to
+calculate a hash value. This hash value is then tied to a specific backend
+server.
+
+A common example would be to use the `consumer` as a hash input. Since this ID is
+the same for every request from that user, it ensures that the same user is
+handled consistently by the same backend server. This allows for cache
+optimizations on the backend, since each of the servers only serves a fixed subset
+of the users, and can improve its cache-hit ratio for user-related data.
+
+This algorithm implements the [ketama principle](https://github.com/RJ/ketama) to
+maximize hashing stability and minimize consistency loss upon changes to the list
+of known backends.
+
+The input for the consistent-hashing algorithm can be one of the following options:
+
+| Option | Description |
+|--------|-------------|
+| `none` | Doesn't use `consistent-hashing`, uses `round-robin` instead (default). Hashing is disabled. |
+| `consumer` | Uses the Consumer ID as the hash input. If no Consumer ID is available, it will fall back on the Credential ID (for example, in case of an external authentication mechanism like LDAP). |
+| `ip` | Uses the originating IP address as the hash input. Review the configuration settings for [determining the real IP](/gateway/configuration/#real_ip_config) when using this option. |
+| `header` | Uses a specified header as the hash input. The header name is specified in either of the Upstream's `hash_on_header` or `hash_fallback_header` fields, depending on whether `header` is a primary or fallback attribute, respectively. |
+| `cookie` | Use a specified cookie with a specified path as the hash input. The cookie name is specified in the Upstream's `hash_on_cookie` field and the path is specified in the Upstream's `hash_on_cookie_path` field. If the specified cookie is not present in the request, it will be set by the response. The generated cookie will have a random UUID value, which is then preserved in the cookie.
The `hash_fallback` setting is invalid and can't be used if `cookie` is the primary hashing mechanism. |
+
+The `consistent-hashing` algorithm supports a primary and a fallback hashing attribute.
+If the primary fails (for example, if the primary is set to `consumer`, but no Consumer is authenticated),
+the fallback attribute is used. This maximizes upstream cache hits.
+
+The consistent-hashing balancer is designed to work both with a single node as well
+as in a cluster.
+
+When choosing this algorithm, consider the following:
+
+- Improves backend cache-hit ratios.
+- Requires enough cardinality in the hash inputs to distribute evenly. For example, hashing on a header that only has 2 possible values doesn't make sense.
+- The cookie-based approach works well for browser-based requests, but less so for machine-to-machine (M2M) clients, which will often omit the cookie.
+- When using the hashing approach in a Kong cluster, add `target` entities by their IP address, and avoid using hostnames in the balancer.
+ The balancers will slowly diverge, as the DNS TTL only has second precision, and renewal is determined by when a name is actually requested.
+ Additionally, some nameservers don't return all entries, which makes the problem worse.
+ This problem can be mitigated by balancer rebuilds and higher TTL settings.
+
+### Least-Connections
+
+The `least-connections` algorithm keeps track of the number of in-flight requests for each backend.
+The weights are used to calculate the connection capacity of a backend. Requests are
+routed towards the backend with the highest spare capacity.
+
+When choosing this algorithm, consider the following:
+
+- Provides good distribution of traffic.
+- Doesn't improve cache-hit ratios.
+- This option is more dynamic, since slower backends will have more connections open, and
+ new requests will be routed to other backends automatically.
+
+### Latency
+
+The `latency` algorithm is based on peak EWMA (Exponentially Weighted Moving Average),
+which ensures that the balancer selects the backend by the lowest latency
+(`upstream_response_time`). The latency metric used is the full request cycle, from
+TCP connect to body response time. Since it's a moving average, the metrics will
+decay over time.
+
+Target weights aren't taken into account.
+
+When choosing this algorithm, consider the following:
+
+- Provides good distribution of traffic, provided there is enough base load to keep the metrics alive, since they are always decaying.
+- The algorithm is very dynamic, since it will constantly optimize loads.
+- Latency-based load balancing works best with low variance in latencies, meaning mostly similar-shaped traffic and even workloads for the backends.
+ For example, using this algorithm with a GraphQL backend serving small-fast queries as well big-slow ones will result in high variance in the latency metrics, which will skew the metrics.
+- You must properly set up the backend capacity and ensure proper network latency to prevent resource starvation.
+ For example, you could use 2 servers: a small capacity server close by (low network latency), and a high capacity server far away (high latency).
+ Most traffic will be routed to the small one until its latency starts going up.
+ However, the latency going up means the small server is likely suffering from resource starvation.
+ In this case, the algorithm will keep the small server in a constant state of resource starvation, which is most likely not efficient.
+- This option is not suitable for long-lived connections like websockets or server-sent events (SSE).
## Schema
@@ -70,6 +173,6 @@ The following are examples of common use cases for Upstreams:
{% entity_example %}
type: upstream
data:
- name: example-upstream
- algorithm: round-robin
-{% endentity_example %}
\ No newline at end of file
+ name: example-upstream
+ algorithm: round-robin
+{% endentity_example %}
diff --git a/app/_gateway_entities/vault.md b/app/_gateway_entities/vault.md
index 4577d33b7..4f397515d 100644
--- a/app/_gateway_entities/vault.md
+++ b/app/_gateway_entities/vault.md
@@ -11,9 +11,9 @@ related_resources:
url: /secrets-management/
- text: Workspaces
url: /gateway/entities/workspace/
- - text: RBAC
+ - text: RBAC
url: /gateway/entities/rbac/
-
+
faqs:
- q: What types of fields can be used in Vaults?
@@ -41,9 +41,11 @@ schema:
---
## What is a Vault?
-In {{site.base_gateway}}, the Vault object is used to store secrets. A secret is any sensitive piece of information required for API gateway
-operations. Secrets can be used as part of the core {{site.base_gateway}} configuration, in plugins, or in configuration associated
-with APIs serviced by the gateway.
+
+Vaults allow you to securely store and then reference secrets from within other entities. This ensures that secrets aren't visible in plaintext throughout the platform, in places such as `kong.conf`,
+declarative configuration files, logs, or the UI.
+
+For example, you could store a certificate and a key in a Vault, then reference them from a [Certificate entity](/gateway/entities/certificate/). This way, the certificate and key are not stored in the entity directly and are more secure.
Some of the most common types of secrets used by {{site.base_gateway}} include:
@@ -52,20 +54,19 @@ Some of the most common types of secrets used by {{site.base_gateway}} include:
* API keys
* Sensitive configuration fields, generally used for authentication, hashing, signing, or encryption
-## Vault use cases
-
-Vaults allow you to securely store and then reference secrets from within other entities. This ensures that secrets aren't visible in plaintext throughout the platform, in places such as `kong.conf`,
-declarative configuration files, logs, or the UI.
-
-For example, you could store a certificate and a key in a Vault, then reference them from a [Certificate entity](/gateway/entities/certificate/). This way, the certificate and key are not stored in the entity directly and are more secure.
-
## How do I add secrets to a Vault?
-You can add secrets to Vaults in one of the following ways:
+You can add secrets to Vaults in one of the following ways:
* Environment variables
* {{site.konnect_short_name}} Config Store
* Supported third-party backend vault
+## How do I configure access to a Vault?
+
+Each vault has its own required configuration. You can provide this configuration by creating a Vault entity, or by configuring specific environment variables before starting {{ site.base_gateway }}.
+
+For more information, choose a Vault below to see the specific configuration required.
+
## Supported backends
{% feature_table %}
@@ -79,8 +80,8 @@ columns:
key: supports_konnect
features:
- - title: Environment variable1
- url: /gateway/entities/vault/#store-secrets-as-environment-variables
+ - title: Environment variable
+ url: /gateway/entities/vault/#store-secrets-as-environment-variables
oss: true
enterprise: true
supports_konnect: true
@@ -111,8 +112,6 @@ features:
supports_konnect: true
{% endfeature_table %}
-1 You can use environment variables as a Vaults backend either with or without using the Vaults entity.
-
## How do I reference secrets stored in a Vault?
When you want to use a secret stored in a Vault, you can reference the secret with a `vault` reference. You can use the `vault` reference in places such as `kong.conf`, declarative configuration files, logs, or in the UI.
@@ -138,18 +137,39 @@ Would point to a secret object called `pg` inside a HashiCorp Vault, which may r
`{vault://hcv/pg/username}`.
+Vault references must be used for the whole referenced value. Imagine that you're calling an upstream service with the authentication token `ABC123`:
+
+{% feature_table %}
+item_title: Works
+columns:
+ - title: Configuration Value
+ key: config
+ - title: Vault Value
+ key: vault
+features:
+ - title: ❌
+ config: 'Bearer {vault://hcv/myservice-auth-token}'
+ vault: ABC123
+ - title: ✅
+ config: '{vault://hcv/myservice-auth-token}'
+ vault: Bearer ABC123
+{% endfeature_table %}
+
## Secret rotation in Vaults
-By default, {{site.base_gateway}} automatically rotates secrets *once every minute* in the background. You can also configure how often {{site.base_gateway}} rotates secrets using the Vault entity configuration.
+By default, {{site.base_gateway}} automatically refreshes secrets *once every minute* in the background.
+You can also configure how often {{site.base_gateway}} refreshes secrets using the Vault entity configuration.
-There are two types of rotation configuration available:
-* Rotate periodically using TTLs: For example, check for a new TLS certificate once per day.
-* Rotate on failure: For example, on a database authentication failure, check if the secrets were updated, and try again.
+There are two types of refresh configuration available:
+* Refresh periodically using TTLs: For example, check for a new TLS certificate once per day.
+* Refresh on failure: For example, on a database authentication failure, check if the secrets were updated, and try again.
For more information, see [Secret management](/secrets-management/).
## Best practices for Vaults
+@TODO: Move this to deck docs when available
+
### General best practices
To keep your environment secure and avoid taking down your proxies by accident, make sure to:
diff --git a/app/_gateway_entities/workspace.md b/app/_gateway_entities/workspace.md
index fe7e90036..097cf6626 100644
--- a/app/_gateway_entities/workspace.md
+++ b/app/_gateway_entities/workspace.md
@@ -8,9 +8,6 @@ description: Workspaces provide a way to segment {{site.base_gateway}} entities.
tools:
- admin-api
- - kic
- - deck
- - terraform
tier: enterprise
schema:
@@ -47,13 +44,13 @@ faqs:
---
-
## What is a Workspace?
Workspaces are a way of namespacing {{site.base_gateway}} entities so they can be managed independently. Workspaces work in combination with RBAC to create isolated environments for teams to operate independently of each other. Workspaces can't share entities, like Services, between them, and only Workspace Admins with the correct permissions, in the Workspace, can manage them.
Workspaces support [multi-tenancy](/gateway/multi-tenancy/) by isolating {{site.base_gateway}} configuration objects. When paired with RBAC, {{site.base_gateway}} administrators can effectively create tenants within the control plane. The Workspace administrators have segregated and secure access to only their portion of the {{site.base_gateway}} configuration in Kong Manager, the Admin API, and the declarative configuration tool decK.
+
{% mermaid %}
flowchart LR
@@ -80,6 +77,8 @@ flowchart LR
{% endmermaid %}
+
+
### How does {{site.base_gateway}} resolve entity conflicts between Workspaces?
Routing rules are configured at the data plane level. The data plane routes client traffic based on the configuration applied across all Workspaces. Configuring entities related to routing, such as [Gateway Services](/gateway/entities/service/) and [Routes](/gateway/entities/route/), alter the client traffic routing behavior of the data plane, but {{site.base_gateway}} will always attempt to ensure that routing rules don't contain conflicts.
@@ -88,13 +87,12 @@ To route traffic to the appropriate Workspace, {{site.base_gateway}} uses a conf
When a Service or Route is **created** or **modified**, the {{site.base_gateway}} Router checks for the existence of that object before allowing the operation to proceed in this order:
-1. If the Service or Route created is totally unique and does not match an existing entity, the new entity is created.
-2. If an existing Service or Route object that matches the one being created is found, a `409 Conflict` error is returned.
-3. If an equivalent Service or a Route is found in a different Workspace, the new entity is created.
-4. If an equivalent Service or Route is found in a different Workspace, and the host is a wildcard:
- a. If the host field matches in both Workspaces, a `409 Conflict` error is returned.
- b. If the host field does not match, the new entity can be created.
- c. If the host is an absolute value, a `409 Conflict` error is returned.
+1. If the Service or Route created is unique across all Workspaces, the new entity is created.
+1. If an existing Service or Route object that matches the one being created is found in the current Workspace, a `409 Conflict` error is returned.
+2. If an equivalent Service or Route is found in a different Workspace, and the host is provided:
+ 1. If the host field matches in both Workspaces, a `409 Conflict` error is returned.
+ 1. If the host field does not match, the new entity can be created.
+ 1. If the host is an absolute value, a `409 Conflict` error is returned.
## Roles, groups, and permissions
diff --git a/app/_how-tos/bootstrap-rbac.md b/app/_how-tos/bootstrap-rbac.md
index 616760137..e2520c31e 100644
--- a/app/_how-tos/bootstrap-rbac.md
+++ b/app/_how-tos/bootstrap-rbac.md
@@ -5,6 +5,9 @@ content_type: how_to
products:
- gateway
+tools:
+ - deck
+
works_on:
- on-prem
@@ -19,4 +22,21 @@ min_version:
gateway: '3.4'
---
-@todo Create a super-admin in KGW set up default workspaces and teams validate isolated workspace.
\ No newline at end of file
+@todo Create a super-admin in KGW set up default workspaces and teams validate isolated workspace.
+
+Maybe https://docs.konghq.com/gateway/latest/production/access-control/enable-rbac/ ?
+
+
+## Create an RBAC user
+
+Creating an RBAC User requires [RBAC to be enabled](#enable-rbac) for {{site.base_gateway}}.
+
+{% entity_example %}
+type: rbac
+data:
+ name: my-user
+ user_token: exampletoken
+headers:
+ admin-api:
+ - "Kong-Admin-Token: $ADMIN_TOKEN"
+{% endentity_example %}
\ No newline at end of file
diff --git a/app/_includes/entities/permissions-table.md b/app/_includes/entities/permissions-table.md
index 93e17508e..56b28f8aa 100644
--- a/app/_includes/entities/permissions-table.md
+++ b/app/_includes/entities/permissions-table.md
@@ -4,7 +4,7 @@ By default, when {{site.base_gateway}} is configured, the starting user is confi
| Role | Description |
| ----------- | ----------- |
-| Admin | Full access to all endpoints, across all Workspaces, except the RBAC Admin API |
+| `admin` | Full access to all endpoints, across all Workspaces, except the RBAC Admin API |
| `super-admin` | Full access to all endpoints, across all Workspaces, ability to assign and modify RBAC permissions. |
|`read-only`| Read access to all endpoints, across all Workspaces|
diff --git a/app/_landing_pages/gateway/entities.yaml b/app/_landing_pages/gateway/entities.yaml
index 7763409e2..2583157cc 100644
--- a/app/_landing_pages/gateway/entities.yaml
+++ b/app/_landing_pages/gateway/entities.yaml
@@ -66,11 +66,11 @@ rows:
- type: entity_card
config:
entity: ca_certificate
+ - columns:
- blocks:
- type: entity_card
config:
entity: vault
- - columns:
- blocks:
- type: entity_card
config:
@@ -79,11 +79,6 @@ rows:
- type: entity_card
config:
entity: key-set
- - blocks:
- - type: entity_card
- config:
- entity: keyring
-
- header:
type: h2
diff --git a/app/_layouts/with_aside.html b/app/_layouts/with_aside.html
index b4cbb6584..9ce5d4a70 100644
--- a/app/_layouts/with_aside.html
+++ b/app/_layouts/with_aside.html
@@ -24,7 +24,7 @@
{% if page.toc != false %}
- {% include toc.html html=content h_min=2 h_max=2 id='toc' anchor_class='tab-button__vertical scroll-to' class="tabcolumn" %}
+ {% include toc.html html=content h_min=2 h_max=3 id='toc' anchor_class='tab-button__vertical scroll-to' class="tabcolumn" %}
{% endif %}
diff --git a/app/gateway/health-checks-circuit-breakers.md b/app/gateway/health-checks-circuit-breakers.md
new file mode 100644
index 000000000..05d6f4c06
--- /dev/null
+++ b/app/gateway/health-checks-circuit-breakers.md
@@ -0,0 +1,17 @@
+---
+title: Health checks and circuit breakers
+content_type: reference
+layout: reference
+
+products:
+ - gateway
+
+description: |
+ Kong supports two kinds of health checks, which can be used separately or in conjunction: active and passive (also known as circuit breakers).
+
+---
+
+@todo
+
+Use https://docs.konghq.com/gateway/latest/how-kong-works/health-checks/
+Probably need a separate how-to as well - how do you actually enable and use a health check? What entities are involved (Upstream, Targets)? Does any of this info actually belong in the Upstream or Target entity docs?
\ No newline at end of file
diff --git a/app/_gateway_entities/keyring.md b/app/gateway/keyring.md
similarity index 99%
rename from app/_gateway_entities/keyring.md
rename to app/gateway/keyring.md
index 8eeb7bbab..dadc83c95 100644
--- a/app/_gateway_entities/keyring.md
+++ b/app/gateway/keyring.md
@@ -1,8 +1,10 @@
---
title: Keyring
content_type: reference
-entities:
- - keyring
+layout: reference
+
+products:
+ - gateway
description: |
A Keyring is a mechanism that encrypts sensitive data fields, such as consumer secrets, before storing them in the database.
diff --git a/app/gateway/ldap-service-directory-mapping.md b/app/gateway/ldap-service-directory-mapping.md
new file mode 100644
index 000000000..9ff68f4d9
--- /dev/null
+++ b/app/gateway/ldap-service-directory-mapping.md
@@ -0,0 +1,19 @@
+---
+title: LDAP Service Directory Mapping
+content_type: reference
+layout: reference
+
+products:
+ - gateway
+
+description: |
+ Service directory mapping allows organizations to use their LDAP Directory for authentication and authorization in {{site.base_gateway}}.
+
+tier: enterprise
+
+---
+
+@todo
+
+Use https://docs.konghq.com/gateway/latest/kong-manager/auth/ldap/service-directory-mapping/
+Probably need a separate how-to as well.
\ No newline at end of file
diff --git a/app/gateway/routing/expressions.md b/app/gateway/routing/expressions.md
index 9a12216b4..4c5287bdb 100644
--- a/app/gateway/routing/expressions.md
+++ b/app/gateway/routing/expressions.md
@@ -14,6 +14,8 @@ related_resources:
url: /gateway/entities/route/
- text: Expressions repository
url: https://github.com/Kong/atc-router
+ - text: Traditional router
+ url: /gateway/routing/traditional/
min_version:
gateway: '3.0'
@@ -22,11 +24,15 @@ breadcrumbs:
- /gateway/
faqs:
- - q: When should I use the expressions router in place of (or alongside) the traditional router?
- a: We recommend using the expressions router if you are running {{site.base_gateway}} 3.0.x or later. After enabling expressions, traditional match fields on the Route object (such as `paths` and `methods`) remain configurable. You may specify Expressions in the new `expression` field. However, these cannot be configured simultaneously with traditional match fields. Additionally, a new `priority` field, used in conjunction with the expression field, allows you to specify the order of evaluation for Expression Routes.
+ - q: Is there a performance difference between the traditional router and expressions?
+ a: Both traditional and expressions modes use the same routing engine internally. Traditional mode configures routes with JSON, and expressions uses a DSL.
+ - q: Why would I choose expressions over the traditional router?
+ a: The expressions router provides more routing flexibility, including fast exact matching that is not available in the traditional router.
+ - q: When should I keep using the traditional router over expressions?
+ a: If you are working with APIOps pipelines that manipulate the route using `deck file patch`, we recommend using the JSON format used by the traditional router.
---
-The expressions router is a collection of [Routes](/gateway/entities/route/) that are all evaluated against incoming requests until a match can be found. This allows for more complex routing logic than the traditional router and ensures good runtime matching performance.
+The expressions router provides a Domain Specific Language (DSL) that allows for complex routing rule definition. The expressions router ensures good runtime matching performance by providing specific routing comparisons such as non-regex equality checks that are not available in the traditional router.
You can do the following with the expressions router:
* Prefix-based path matching
@@ -43,10 +49,9 @@ In your `kong.conf` file, set `router_flavor = expressions` and restart your {{s
## How requests are routed with the expressions router
-At runtime, {{site.base_gateway}} builds two separate routers for the HTTP and Stream (TCP, TLS, UDP) subsystem. When a request/connection comes in, {{site.base_gateway}} looks at which field your configured Routes require,
-and supplies the value of these fields to the router execution context.
-Routes are inserted into each router with the appropriate `priority` field set. The priority is a positive integer that defines the order of evaluation of the router. The bigger the priority, the sooner a Route will be evaluated. In the case of duplicate priority values between two Routes in the same router, their order of evaluation is undefined. The router is
-updated incrementally as configured Routes change.
+At runtime, {{site.base_gateway}} builds two separate routers for the HTTP and Stream (TCP, TLS, UDP) subsystem. When a request/connection comes in, {{site.base_gateway}} looks at which field your configured Routes require, and supplies the value of these fields to the router execution context.
+
+Routes are inserted into each router with the appropriate `priority` field set. The priority is a positive integer that defines the order of evaluation of the router. The bigger the priority, the sooner a Route is evaluated. In the case of duplicate priority values between two Routes in the same router, their order of evaluation is undefined. The router is updated incrementally as configured Routes change.
As soon as a Route yields a match, the router stops matching and the matched Route is used to process the current request/connection.
@@ -85,7 +90,7 @@ This section explains how to optimize the expressions you write to get the most
### Number of routes
-#### Route matching priority order
+#### Priority matching
Expressions routes are always evaluated in the descending `priority` order they were defined.
Therefore, it is helpful to put more likely matched routes before (as in, higher priority)
@@ -166,7 +171,7 @@ http.path == "/foo/bar" || http.path == "/foo/bar/"
http.path ~ r#"^/foo/?$"#
```
-## Expressions router reference
+## Expressions router reference
This reference explains the different configurable entities for the expressions router.
@@ -257,13 +262,13 @@ features:
-In addition, expressions also supports one composite type, `Array`. Array types are written as `Type[]`.
+In addition, the expressions router also supports one composite type, `Array`. Array types are written as `Type[]`.
For example: `String[]`, `Int[]`. Currently, arrays can only be present in field values. They are used in
case one field could contain multiple values. For example, `http.headers.x` or `http.queries.x`.
#### Matching fields
-The following table describes the available matching fields, as well as their associated type when using an expressions based router.
+The following table describes the available matching fields, as well as their associated type when using an expressions-based router.
@@ -398,9 +403,9 @@ The expressions language supports a rich set of operators that can be performed
| `>` | Greater than | Field value is greater than the constant value |
| `<=` | Less than or equal | Field value is less than or equal to the constant value |
| `<` | Less than | Field value is less than the constant value |
-| `in` | In | Field value is inside the constant value. This operator is used with `IpAddr` and `IpCidr` types to perform an efficient IP list check. For example, `net.src.ip in 192.168.0.0/24` will only return `true` if the value of `net.src.ip` is within `192.168.0.0/24`. |
-| `not in` | Not in | Field value is not inside the constant value. This operator is used with `IpAddr` and `IpCidr` types to perform an efficient IP list check. For example, `net.src.ip in 192.168.0.0/24` will only return `true` if the value of `net.src.ip` is within `192.168.0.0/24`. |
-| `contains` | Contains | Field value contains the constant value. This operator is used to check the existence of a string inside another string. For example, `http.path contains "foo"` will return `true` if `foo` can be found anywhere inside `http.path`. This will match a `http.path` that looks like `/foo`, `/abc/foo`, or `/xfooy`, for example. |
+| `in` | In | Field value is inside the constant value. This operator is used with `IpAddr` and `IpCidr` types to perform an efficient IP list check. For example, `net.src.ip in 192.168.0.0/24` only returns `true` if the value of `net.src.ip` is within `192.168.0.0/24`. |
+| `not in` | Not in | Field value is not inside the constant value. This operator is used with `IpAddr` and `IpCidr` types to perform an efficient IP list check. For example, `net.src.ip in 192.168.0.0/24` only returns `true` if the value of `net.src.ip` is within `192.168.0.0/24`. |
+| `contains` | Contains | Field value contains the constant value. This operator is used to check the existence of a string inside another string. For example, `http.path contains "foo"` returns `true` if `foo` can be found anywhere inside `http.path`. This will match a `http.path` that looks like `/foo`, `/abc/foo`, or `/xfooy`, for example. |
| `&&` | And | Returns `true` if **both** expressions on the left and right side evaluates to `true` |
| `||` | Or | Returns `true` if **any** expressions on the left and right side evaluates to `true` | |
| `(Expression)` | Parenthesis | Groups expressions together to be evaluated first |
@@ -442,9 +447,9 @@ Depending on the field type, only certain content types and operators are suppor
| Prefix based path matching | `http.path ^= "/foo/bar"` | Matches HTTP requests that have a path starting with `/foo/bar` |
| Regex based path matching | `http.path ~ r#"/foo/bar/\d+"#` | N/A |
| Case insensitive path matching | `lower(http.path) == "/foo/bar"` | Ignores case when performing the path match. |
-| Match by header value ("all" style matching) | `http.headers.x_foo ~ r#"bar\d"#` | If there are multiple header values for `X-Foo` and the client sends more than one `X-Foo` header with different values, the above example will ensure **each** instance of the value will match the regex `r#"bar\d"#`. This is called "all" style matching. |
+| Match by header value ("all" style matching) | `http.headers.x_foo ~ r#"bar\d"#` | If there are multiple header values for `X-Foo` and the client sends more than one `X-Foo` header with different values, the above example ensures that **each** instance of the value matches the regex `r#"bar\d"#`. This is called "all" style matching. |
| Match by header value ("any" style matching) | `any(http.headers.x_foo) ~ r#"bar\d"#` | Returns `true` for the predicate as soon as any of the values pass the comparison. Can be combined with other transformations, like `lower()`. |
-| Regex captures | `http.path ~ r#"/foo/(?P.+)"#` | You can define regex capture groups in any regex operation which will be made available later for plugins to use. Currently, this is only supported with the `http.path` field. The matched value of `component` will be made available later to plugins such as [Request Transformer Advanced](/plugins/request-transformer-advanced/). |
+| Regex captures | `http.path ~ r#"/foo/(?P.+)"#` | You can define regex capture groups in any regex operation, which will be made available later for plugins to use. Currently, this is only supported with the `http.path` field. The matched value of `component` will be made available later to plugins such as [Request Transformer Advanced](/plugins/request-transformer-advanced/). |
### TCP, TLS, and UDP examples
diff --git a/app/gateway/routing/traditional.md b/app/gateway/routing/traditional.md
new file mode 100644
index 000000000..52e4d8250
--- /dev/null
+++ b/app/gateway/routing/traditional.md
@@ -0,0 +1,540 @@
+---
+title: Traditional router
+
+description: "The traditional router is a collection of Routes that are all evaluated against incoming requests until a match can be found."
+
+content_type: reference
+layout: reference
+
+products:
+ - gateway
+
+related_resources:
+ - text: Route entity
+ url: /gateway/entities/route/
+ - text: SNI entity
+ url: /gateway/entities/sni/
+ - text: Expressions router
+ url: /gateway/routing/expressions/
+
+min_version:
+ gateway: "3.0"
+
+breadcrumbs:
+ - /gateway/
+
+faqs:
+ - q: When should I use the traditional router?
+ a: |
+ If you are working with APIOps pipelines that manipulate the route using `deck file patch`, we recommend using the JSON format used by the traditional router.
+
+---
+
+The traditional router is {{ site.base_gateway }}'s original routing configuration format. It uses JSON to provide a list of routing criteria, including `host`, `path`, and `headers`.
+
+Routing based on JSON configuration is available when [`router_flavor`](/gateway/configuration/#router_flavor) is set to `traditional_compat` _or_ `expressions` in `kong.conf`.
+
+## Routing criteria
+
+{{site.base_gateway}} supports native proxying of HTTP/HTTPS, TCP/TLS, and GRPC/GRPCS protocols.
+Each of these protocols accept a different set of routing attributes:
+
+- `http`: `methods`, `hosts`, `headers`, `paths` (and `snis`, if `https`)
+- `tcp`: `sources`, `destinations` (and `snis`, if `tls`)
+- `grpc`: `hosts`, `headers`, `paths` (and `snis`, if `grpcs`)
+
+Note that all of these fields are **optional**, but at least **one of them**
+must be specified.
+
+For a request to match a route:
+
+- The request **must** include **all** of the configured fields
+- The values of the fields in the request **must** match at least one of the
+ configured values. While the field configurations accept one or more values,
+ a request needs only one of the values to be considered a match.
+
+Let's go through a few examples. Consider a route configured like the following:
+
+```json
+{
+ "hosts": ["example.com", "foo-service.com"],
+ "paths": ["/foo", "/bar"],
+ "methods": ["GET"]
+}
+```
+
+Some of the possible requests matching this route would look like the following:
+
+```http
+GET /foo HTTP/1.1
+Host: example.com
+```
+
+```http
+GET /bar HTTP/1.1
+Host: foo-service.com
+```
+
+```http
+GET /foo/hello/world HTTP/1.1
+Host: example.com
+```
+
+All three of these requests satisfy all the conditions set in the route
+definition.
+
+However, the following requests would **not** match the configured conditions:
+
+```http
+GET / HTTP/1.1
+Host: example.com
+```
+
+```http
+POST /foo HTTP/1.1
+Host: example.com
+```
+
+```http
+GET /foo HTTP/1.1
+Host: foo.com
+```
+
+All three of these requests satisfy only two of configured conditions. The
+first request's path is not a match for any of the configured `paths`, same for
+the second request's HTTP method, and the third request's Host header.
+
+Now that we understand how the routing properties work together, let's explore
+each property individually.
+
+### Host header
+
+{{site.base_gateway}} supports routing by arbitrary HTTP headers. A special case of this
+feature is routing by the Host header.
+
+Routing a request based on its Host header is the most straightforward way to
+proxy traffic through {{site.base_gateway}}, especially since this is the intended usage of the
+HTTP Host header. {{site.base_gateway}} makes it easy to do via the `hosts` field of the route
+entity.
+
+`hosts` accepts multiple values, which must be comma-separated when specifying
+them via the Admin API:
+
+```bash
+curl -i -X POST http://localhost:8001/routes/ \
+ --header 'Content-Type: application/json' \
+ --data '{"hosts":["example.com", "foo-service.com"]}'
+```
+
+To satisfy the `hosts` condition of this route, any incoming request from a
+client must now have its Host header set to one of:
+
+```
+Host: example.com
+```
+
+or:
+
+```
+Host: foo-service.com
+```
+
+Similarly, any other header can be used for routing:
+
+```sh
+curl -i -X POST http://localhost:8001/routes/ \
+ --data 'headers.region=north'
+```
+
+Incoming requests containing a `Region` header set to `North` are routed to
+said route.
+
+#### Using wildcard hostnames
+
+To provide flexibility, {{site.base_gateway}} allows you to specify hostnames with wildcards in
+the `hosts` field. Wildcard hostnames allow any matching Host header to satisfy
+the condition, and thus match a given Route.
+
+Wildcard hostnames **must** contain **only one** asterisk at the leftmost
+**or** rightmost label of the domain. For example:
+
+- `*.example.com` would allow Host values such as `a.example.com` and
+ `x.y.example.com` to match.
+- `example.*` would allow Host values such as `example.com` and `example.org`
+ to match.
+
+A complete example would look like this:
+
+```json
+{
+ "hosts": ["*.example.com", "service.com"]
+}
+```
+
+Which would allow the following requests to match this route:
+
+```http
+GET / HTTP/1.1
+Host: an.example.com
+```
+
+```http
+GET / HTTP/1.1
+Host: service.com
+```
+
+### Headers
+
+It's possible to route requests by other headers besides `Host`.
+
+To do this, use the `headers` property in your route:
+
+```json
+{
+ "headers": { "version": ["v1", "v2"] },
+ "service": {
+ "id": "..."
+ }
+}
+```
+
+Given a request with a header such as:
+
+```http
+GET / HTTP/1.1
+version: v1
+```
+
+This request will be routed through to the Service. The same happens with this one:
+
+```http
+GET / HTTP/1.1
+version: v2
+```
+
+This request isn't routed to the Service:
+
+```http
+GET / HTTP/1.1
+version: v3
+```
+
+{:.info}
+> **Note**: The `headers` keys are a logical `AND` and their values a logical `OR`.
+
+### Path
+
+Another way for a route to be matched is via request paths. To satisfy this
+routing condition, a client request's normalized path **must** be prefixed with one of the
+values of the `paths` attribute.
+
+For example, with a route configured like so:
+
+```json
+{
+ "paths": ["/service", "/hello/world"]
+}
+```
+
+The following requests would be matched:
+
+```http
+GET /service HTTP/1.1
+Host: example.com
+```
+
+```http
+GET /service/resource?param=value HTTP/1.1
+Host: example.com
+```
+
+```http
+GET /hello/world/resource HTTP/1.1
+Host: anything.com
+```
+
+For each of these requests, {{site.base_gateway}} detects that their normalized URL path is prefixed with
+one of the routes' `paths` values. By default, {{site.base_gateway}} would then proxy the
+request upstream without changing the URL path.
+
+When proxying with path prefixes, **the longest paths get evaluated first**.
+This allows you to define two routes with two paths, such as `/service` and
+`/service/resource`, and ensure that the former doesn't overshadow the latter.
+
+#### Using regex in paths
+
+For a path to be considered a regular expression, it must be prefixed with a `~`:
+
+```
+paths: ["~/foo/bar$"]
+```
+
+Any path that isn't prefixed with a `~` is considered plain text:
+
+```
+"paths": ["/users/\d+/profile", "/following"]
+```
+
+For more information about how the router processes regular expressions, see the [routing performance considerations](/gateway/entities/route/#routing-performance-recommendations).
+
+##### Regex evaluation order
+
+The router evaluates routes using the `regex_priority` field of the
+`Route` where a route is configured. Higher `regex_priority` values
+mean higher priority.
+
+```json
+[
+ {
+ "paths": ["~/status/d+"],
+ "regex_priority": 0
+ },
+ {
+ "paths": ["~/version/d+/status/d+"],
+ "regex_priority": 6
+ },
+ {
+ "paths": ["/version"]
+ },
+ {
+ "paths": ["~/version/any/"]
+ }
+]
+```
+
+In this scenario, {{site.base_gateway}} evaluates incoming requests against the following
+defined URIs, in this order:
+
+1. `/version/\d+/status/\d+`
+2. `/status/\d+`
+3. `/version/any/`
+4. `/version`
+
+Routers with a large number of regexes can consume traffic intended for other rules.
+Regular expressions are much more expensive to build and execute and can't be optimized easily.
+You can avoid creating complex regular expressions using the [Router Expressions language](/gateway/routing/expressions/).
+
+If you see unexpected behavior, use the Kong debug header to help track down the source:
+
+1. In `kong.conf`, set [`allow_debug_header=on`](/gateway/configuration/#allow_debug_header).
+1. Send `Kong-Debug: 1` in your request headers to indicate the matched route ID in the response headers for
+ troubleshooting purposes.
+
+As usual, a request must still match a Route's `hosts` and `methods` properties
+as well, and {{site.base_gateway}} traverses your Routes until it finds one that [matches
+the most rules](#route-priority).
+
+##### Capture groups
+
+Capture groups are also supported, and the matched group will be extracted
+from the path and available for plugins consumption. Consider the
+following regex:
+
+```
+/version/(?\d+)/users/(?\S+)
+```
+
+And the following request path:
+
+```
+/version/1/users/john
+```
+
+{{site.base_gateway}} considers the request path a match, and if the overall Route is
+matched (considering other routing attributes), the extracted capture groups
+will be available from the plugins in the `ngx.ctx` variable:
+
+```lua
+local router_matches = ngx.ctx.router_matches
+
+-- router_matches.uri_captures is:
+-- { "1", "john", version = "1", user = "john" }
+```
+
+#### Path matching
+
+Keep the following path matching criteria in mind when configuring paths:
+
+1. **Regex in paths:** For a path to be considered a regular expression, it must be prefixed with a `~`.
+You can avoid creating complex regular expressions using the [Router Expressions language](/gateway/routing/expressions/).
+1. **Capture groups:** [Regex capture groups](/gateway/routing/expressions/#example-expressions) are also supported, and the matched group is extracted from the path and available for plugin consumption.
+1. **Escaping special characters:** When configuring Routes with regex paths via the Admin API, be sure to URL encode your payload if necessary according to [RFC 3986](https://tools.ietf.org/html/rfc3986).
+1. **Normalization behavior:** To prevent Route match bypasses, the incoming request URI from the client is always normalized according to [RFC 3986](https://tools.ietf.org/html/rfc3986) before router matching occurs.
+
+#### Path normalization
+
+To prevent trivial route match bypass, the incoming request URI from the client
+is always normalized according to [RFC 3986](https://tools.ietf.org/html/rfc3986)
+before router matching occurs. Specifically, the following normalization techniques are
+used for incoming request URIs, which are selected because they generally don't change
+semantics of the request URI:
+
+1. Percent-encoded triplets are converted to uppercase. For example: `/foo%3a` becomes `/foo%3A`.
+2. Percent-encoded triplets of unreserved characters are decoded. For example: `/fo%6F` becomes `/foo`.
+3. Dot segments are removed as necessary. For example: `/foo/./bar/../baz` becomes `/foo/baz`.
+4. Duplicate slashes are merged. For example: `/foo//bar` becomes `/foo/bar`.
+
+The values in the `paths` attribute of the Route object are also normalized. This is achieved by first determining
+if the path is a plain text or regex path. Based on the result, different normalization techniques
+are used:
+* Plain text route path: Uses the same normalization technique as above, that is, methods 1 through 4.
+* Regex route path: Only uses methods 1 and 2. In addition, if the decoded character becomes a regex
+meta character, it will be escaped with a backslash.
+
+{{site.base_gateway}} normalizes any incoming request URI before performing router
+matches. As a result, any request URI sent over to the upstream services will also
+be in normalized form, which preserves the original URI semantics.
+
+### HTTP method
+
+The `methods` field allows matching the requests depending on their HTTP
+method. It accepts multiple values. Its default value is empty, where the HTTP
+method is not used for routing.
+
+The following route allows routing via `GET` and `HEAD`:
+
+```json
+{
+ "methods": ["GET", "HEAD"],
+ "service": {
+ "id": "..."
+ }
+}
+```
+
+This route would be matched with the following requests:
+
+```http
+GET / HTTP/1.1
+Host: ...
+```
+
+```http
+HEAD /resource HTTP/1.1
+Host: ...
+```
+
+This route wouldn't match a `POST` or `DELETE` request. This allows for much more
+granularity when configuring plugins on Routes. For example, you might have two routes pointing to the same service:
+one with unlimited unauthenticated `GET` requests, and a second one allowing only authenticated and rate-limited
+`POST` requests (by applying the authentication and rate limiting plugins to
+those requests).
+
+### Source
+
+{:.info}
+> **Note:** This section only applies to TCP and TLS routes.
+
+The `sources` routing attribute allows
+matching a route by a list of incoming connection IP and/or port sources.
+
+The following route allows routing via a list of source IP/ports:
+
+```json
+{
+ "protocols": ["tcp", "tls"],
+ "sources": [
+ { "ip": "10.1.0.0/16", "port": 1234 },
+ { "ip": "10.2.2.2" },
+ { "port": 9123 }
+ ],
+ "id": "..."
+}
+```
+
+TCP or TLS connections originating from IPs in CIDR range "10.1.0.0/16" or IP
+address "10.2.2.2" or Port "9123" would match such route.
+
+### Destination
+
+{:.info}
+> **Note:** This section only applies to TCP and TLS routes.
+
+The `destinations` attribute, similarly to `sources`,
+allows matching a route by a list of incoming connection IP and/or port, but
+uses the destination of the TCP/TLS connection as routing attribute.
+
+### SNI
+
+When using secure protocols (`https`, `grpcs`, or `tls`), a
+[Server Name Indication](/gateway/entities/sni/) can be used as a routing attribute.
+The following route allows routing via SNIs:
+
+```json
+{
+ "snis": ["foo.test", "example.com"],
+ "id": "..."
+}
+```
+
+Incoming requests with a matching hostname set in the TLS connection's SNI
+extension would be routed to this route.
+SNI routing also applies to other protocols carried over TLS, such as HTTPS.
+If multiple SNIs are specified in the route, any of them can match the incoming request's SNI.
+
+The SNI is indicated at TLS handshake time and can't be modified after the TLS connection has
+been established. This means, for example, that multiple requests reusing the same keepalive connection
+will have the same SNI hostname while performing router matches, regardless of the value in the `Host` header.
+
+## Route priority
+
+In `traditional_compat` mode, the priority of a Route is determined as follows, by the order of descending significance:
+
+1. **Priority points:** A priority point is added for every `methods`, `host`, `headers`, and `snis` value that a Route has.
+Routes with higher priority point values are considered before those with lower values.
+2. **Wildcard hosts:** Among Routes with the same priority point value, Routes without a wildcard host specified (or no host at all) are prioritized before those that have any wildcard host specification.
+3. **Header count:** The resulting groups are sorted so the Routes with a higher number of specified headers have higher priority than those with a lower number of headers.
+4. **Regular expressions and prefix paths:** Routes that have a regular expression path are considered first and are ordered by their `regex_priority` value.
+Routes that have no regular expression path are ordered by the length of their paths.
+5. **Creation date:** If all of the above are equal, the router chooses the Route that was created first using the Route's `created_at` value.
+
+For example, if two Routes are configured like so:
+
+```json
+{
+ "hosts": ["example.com"],
+ "service": {
+ "id": "..."
+ }
+},
+{
+ "hosts": ["example.com"],
+ "methods": ["POST"],
+ "service": {
+ "id": "..."
+ }
+}
+```
+
+The second route has a `hosts` field **and** a `methods` field, so it is
+evaluated first by {{site.base_gateway}}. By doing so, we avoid the first route "shadowing"
+calls intended for the second one.
+
+Thus, this request matches the first route:
+
+```http
+GET / HTTP/1.1
+Host: example.com
+```
+
+And this request matches the second one:
+
+```http
+POST / HTTP/1.1
+Host: example.com
+```
+
+Following this logic, if a third route was to be configured with a `hosts`
+field, a `methods` field, and a `paths` field, it would be evaluated first by
+{{site.base_gateway}}.
+
+If the rule count for the given request is the same in two routes `A` and
+`B`, then the following tiebreaker rules will be applied in the order they
+are listed. Route `A` will be selected over `B` if:
+
+- `A` has only plain Host headers and `B` has one or more wildcard
+ host headers
+- `A` has more non-Host headers than `B`
+- `A` has at least one regex path and `B` has only plain paths
+- `A`'s longest path is longer than `B`'s longest path
+- `A.created_at < B.created_at`