# Upstream Settings Policy API Type of document: How-to guide Product: F5 NGINX Gateway Fabric > Use UpstreamSettingsPolicy to configure load balancing, zone size, and keepalives between NGINX and upstreams. --- Learn how to use the `UpstreamSettingsPolicy` API. ## Overview The `UpstreamSettingsPolicy` API allows Application Developers to configure the behavior of a connection between NGINX and the upstream applications. The settings in `UpstreamSettingsPolicy` correspond to the following NGINX directives: - [`zone`]() - [`keepalive`]() - [`keepalive_requests`]() - [`keepalive_time`]() - [`keepalive_timeout`](https://nginx.org/en/docs/http/ngx_http_upstream_module.html#keepalive_timeout) - [`random`](https://nginx.org/en/docs/http/ngx_http_upstream_module.html#random) - [`least_conn`](https://nginx.org/en/docs/http/ngx_http_upstream_module.html#least_conn) - [`least_time`](https://nginx.org/en/docs/http/ngx_http_upstream_module.html#least_time) - [`upstream`](https://nginx.org/en/docs/http/ngx_http_upstream_module.html#upstream) - [`ip_hash`](https://nginx.org/en/docs/http/ngx_http_upstream_module.html#ip_hash) - [`hash`](https://nginx.org/en/docs/http/ngx_http_upstream_module.html#hash) - [`variables`](https://nginx.org/en/docs/http/ngx_http_upstream_module.html#variables) - [`health_check`](https://nginx.org/en/docs/http/ngx_http_upstream_hc_module.html#health_check) (NGINX Plus only) `UpstreamSettingsPolicy` is a [Direct Policy Attachment](https://gateway-api.sigs.k8s.io/reference/policy-attachment/) that can be applied to one or more services in the same namespace as the policy. `UpstreamSettingsPolicies` can only be applied to HTTP or gRPC services, in other words, services that are referenced by an HTTPRoute or GRPCRoute. See the [custom policies](/ngf/overview/custom-policies.md) document for more information on policies. This guide will show you how to use the `UpstreamSettingsPolicy` API to configure the load balancing method, upstream zone size and keepalives for your applications. For all the possible configuration options for `UpstreamSettingsPolicy`, see the [API reference](/ngf/reference/api.md). --- ## Before you begin - [Install](/ngf/install/) NGINX Gateway Fabric. ## Setup Create the `coffee` and `tea` example applications: ```yaml kubectl apply -f - < 80/TCP 23h service/tea ClusterIP 10.244.0.15 80/TCP 23h NAME READY STATUS RESTARTS AGE pod/coffee-676c9f8944-n9g6n 1/1 Running 0 23h pod/tea-6fbfdcb95d-cf84d 1/1 Running 0 23h ``` Create a Gateway: ```yaml kubectl apply -f - < ``` Replace `` with the port number you use to access your Gateway. **Note:** In a production environment, you should have a DNS record for the external IP address that is exposed, and it should refer to the hostname that the gateway will forward for. Create HTTPRoutes for the `coffee` and `tea` applications: ```yaml kubectl apply -f - < ``` Next, verify that the policy has been applied to the `coffee` and `tea` upstreams by inspecting the NGINX configuration: ```shell kubectl exec -it deployments/gateway-nginx -- nginx -T ``` You should see the `zone` directive in the `coffee` and `tea` upstreams both specify the size `1m`: ```text upstream default_coffee_80 { random two least_conn; zone default_coffee_80 1m; server 10.244.0.14:8080; } upstream default_tea_80 { random two least_conn; zone default_tea_80 1m; server 10.244.0.15:8080; } ``` ## Enable keepalive connections By default, the `keepalive` directive is omitted, which results in the default NGINX `keepalive` value being used. You can override this value or disable `keepAlive` entirely by configuring an UpstreamSettingsPolicy. To disable keepalive, set the connections field to 0. The following example creates an `UpstreamSettingsPolicy` that configures keepalive connections for the `coffee` Service with a value of 24: ```yaml kubectl apply -f - < ``` Next, verify that the policy has been applied to the `coffee` upstreams, by inspecting the NGINX configuration: ```shell kubectl exec -it deployments/gateway-nginx -- nginx -T ``` You should see that the `coffee` upstream has the `keepalive` directive set to 24: ```text upstream default_coffee_80 { random two least_conn; zone default_coffee_80 1m; server 10.244.0.14:8080; keepalive 24; } ``` To disable the `keepalive` directive, lets create an `UpstreamSettingsPolicy` targeting the `tea` service with value 0: ```yaml kubectl apply -f - < ``` Next, verify that the policy has been applied to the `coffee` upstream by inspecting the NGINX configuration: ```shell kubectl exec -it deployments/gateway-nginx -- nginx -T ``` You should see `max_fails` and `fail_timeout` set on the `server` directive in the `coffee` upstream: ```text upstream default_coffee_80 { random two least_conn; zone default_coffee_80 1m; server 10.244.0.14:8080 max_fails=3 fail_timeout=5s; } ``` ### Configure an active health check (NGINX Plus) Active health checks probe your backends on a schedule, separate from client traffic. Set the fields under `spec.healthCheck.active`: - `interval` (duration): the time between checks. - `jitter` (duration): a random delay added to each check. - `fails` (integer, minimum 1): consecutive failed checks before a server is considered unhealthy. - `passes` (integer, minimum 1): consecutive passed checks before a server is considered healthy again. - `path` (string): the URI for probe requests. The default is `/`. Mutually exclusive with `grpc`. Maps to the `uri` parameter on the `health_check` directive. - `port` (integer, 1 through 65535): the port used for the health-check connection. - `match.status` (string): the expected response status codes for a check to pass. The default is any 2xx or 3xx code. It accepts an optional leading `!` for negation and space-separated codes or ranges, for example `"200"`, `"! 500"`, `"200 204"`, or `"200-399"`. Mutually exclusive with `grpc`. - `mandatory` (boolean): require every newly added server to pass a check before it receives traffic. This requirement warms up new endpoints. - `persistent` (boolean): keep a server's pre-reload state across reloads. Requires `mandatory: true`. - `keepAliveTime` (duration): how long NGINX reuses a single keepalive connection for health-check requests before opening a new one. - `timeout.connect`, `timeout.read`, and `timeout.send` (durations): the timeouts for health-check requests. - `headers` (list, maximum 16): request headers to send with each check. NGINX Plus always sets `Host`, `User-Agent`, and `Connection`, which you can't override. A header name can contain only alphanumeric characters or `-`. NGINX Gateway Fabric also rejects the names `host`, `connection`, and `upgrade` (case-insensitive), even when they meet that format rule. A value can't contain line breaks, but it can include NGINX variables such as `$remote_addr`. For gRPC upstreams, configure the check through `spec.healthCheck.active.grpc`. The check follows the [gRPC health-checking protocol](https://github.com/grpc/grpc/blob/master/doc/health-checking.md), and the `grpc` field is mutually exclusive with `path` and `match`. The `grpc` field contains two settings: - `service` (string): the gRPC service to check. If you don't set it, NGINX checks the health of the whole server. - `status` (string): the gRPC status code that counts as healthy. Set it only if your service doesn't implement the gRPC health-checking protocol. Use a status name, such as `UNIMPLEMENTED`, or its number, such as `12`. If a valid BackendTLSPolicy targets the same Service, active health checks use TLS as well. The health-check location connects over HTTPS, or over gRPC with TLS for a gRPC check. It verifies the backend certificate with the certificate authority (CA) certificate and hostname from the BackendTLSPolicy. To set up a BackendTLSPolicy, see [Securing backend traffic using mutual TLS](/ngf/traffic-security/secure-backend.md). The following `UpstreamSettingsPolicy` configures an active health check for the `tea` Service: ```yaml kubectl apply -f - < ``` NGINX Plus generates a dedicated internal `location` containing the `health_check` directive. Because the policy sets `match.status`, it also generates a `match` block that the `health_check` directive references through `match=`. The `server` directive in the upstream doesn't change. Inspect the NGINX configuration: ```shell kubectl exec -it deployments/gateway-nginx -- nginx -T ``` You should see a `location` with the `health_check` directive and its `match` block: ```text server { location @hc-default_tea_80 { internal; proxy_pass http://default_tea_80; proxy_connect_timeout 2s; proxy_read_timeout 2s; proxy_send_timeout 2s; health_check interval=10s jitter=3s fails=3 passes=2 uri=/healthz mandatory persistent keepalive_time=60s match=default_tea_80_match; } } match default_tea_80_match { status ! 500; } ``` ### Configure an active health check for a gRPC service For a gRPC upstream, set `spec.healthCheck.active.grpc` instead of `path` and `match`. The check uses the [gRPC health-checking protocol](https://github.com/grpc/grpc/blob/master/doc/health-checking.md), and `grpc.service` names the service to query. This example targets a `grpc-backend` Service referenced by a GRPCRoute rather than the HTTP `coffee` and `tea` Services from the setup: ```yaml kubectl apply -f - < ``` For a gRPC check, the health-check location uses the `grpc_pass` directive instead of `proxy_pass`. Its `health_check` directive includes `type=grpc`, and `grpc_service=my.grpc.Service` for this example. To confirm, run `nginx -T` as in the [active health check example for the `tea` Service](/ngf/traffic-management/upstream-settings.md#configure-an-active-health-check-nginx-plus). ## Enable routing to Service ClusterIPs The ability to configure NGINX to route to the Service ClusterIP and port instead of individual Pod IPs can be useful in service mesh scenarios or when working with other Kubernetes controllers/operators that require traffic to flow to the Service IP address. View the IP address of the `coffee` backend pod and verify it matches the IP address in the `coffee` upstream: ```shell kubectl get endpoints coffee ``` ```text NAME ENDPOINTS AGE coffee 10.244.0.8:8080 13m ``` ```shell kubectl exec -it deployments/gateway-nginx -- nginx -T ``` ```text upstream default_coffee_80 { random two least_conn; zone default_coffee_80 1m; server 10.244.0.8:8080; keepalive 32; } ``` The following example creates an `UpstreamSettingsPolicy` that configures NGINX to route to the coffee Service ClusterIP instead of the individual backend Pod IPs by using the `useClusterIP` field: ```yaml kubectl apply -f - < ``` **note:** This setting applies only when the target Service has a ClusterIP. For headless Services (ClusterIP: None) and ExternalName Services, normal endpoint resolution is used instead. Additionally, this setting is also not applied to L4/stream upstreams. View the IP address of the `coffee` Service and verify it matches the IP address in the `coffee` upstream: ```shell kubectl get service coffee ``` ```text NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE coffee ClusterIP 10.96.23.26 80/TCP 16m ``` ```shell kubectl exec -it deployments/gateway-nginx -- nginx -T ``` ```text upstream default_coffee_80 { random two least_conn; zone default_coffee_80 1m; server 10.96.23.26:80; keepalive 32; } ``` --- ## Route upstream traffic to the Service ClusterIP By default, NGINX Gateway Fabric resolves each backend Service to its individual Pod IPs and uses those as the upstream servers. Setting `useClusterIP` to `true` in an `UpstreamSettingsPolicy` configures NGINX to route to the Service's ClusterIP and port instead, so the upstream contains a single server (the Service VIP). This is useful for service mesh compatibility and for controllers or operators that require traffic to traverse the Service VIP. You can also enable this globally for all Services through the `useClusterIP` field of the `NginxProxy` resource. When both are configured for the same Service, the `UpstreamSettingsPolicy` value takes precedence. See [Data plane configuration](/ngf/how-to/data-plane-configuration.md) for the global setting. **note:** Because the upstream contains only the Service VIP as a single server, you lose NGINX's load balancing across the backend Pods. Traffic is instead load balanced by the Kubernetes Service (kube-proxy), so the load balancing and keepalive settings of an `UpstreamSettingsPolicy` no longer apply to that Service. `useClusterIP` applies only when the target Service has a ClusterIP; headless (`ClusterIP: None`) and ExternalName Services fall back to the default Pod IP resolution. To route to the ClusterIP of the `coffee` service, create the following `UpstreamSettingsPolicy`: ```yaml kubectl apply -f - < ``` Find the ClusterIP of the `coffee` service: ```shell kubectl get service coffee ``` Next, verify that the `coffee` upstream targets that ClusterIP by inspecting the NGINX configuration: ```shell kubectl exec -it deployments/gateway-nginx -- nginx -T ``` You should see a single `server` in the `coffee` upstream set to the Service ClusterIP and port (`10.244.0.14` is the ClusterIP in this example): ```nginx upstream default_coffee_80 { random two least_conn; zone default_coffee_80 512k; server 10.244.0.14:80; keepalive 16; } ``` --- ## Further reading - [Custom policies](/ngf/overview/custom-policies.md): learn about how NGINX Gateway Fabric custom policies work. - [API reference](/ngf/reference/api.md): all configuration fields for the `UpstreamSettingsPolicy` API. - [NGINX health check module](https://nginx.org/en/docs/http/ngx_http_upstream_hc_module.html): optional background on the active health check directives available in NGINX Plus.