ListenerSet API
Learn how to use the ListenerSet API to specify additional listeners for a Gateway
A ListenerSet is a Gateway API type for specifying additional listeners for a Gateway. It decouples network listener configurations—such as ports, hostnames, and TLS termination—from the central Gateway resource and provides a mechanism to merge multiple listeners into a single Gateway. This enables multiple application developer teams who manage their own Services and Routes to configure their own listeners on a Gateway without needing to modify the Gateway itself (which may be owned by a different team).
Additionally, by using ListenerSets, users are able to scale beyond the 64-listener limit of a single Gateway resource.
- Install NGINX Gateway Fabric.
Create the coffee application in Kubernetes by copying and pasting the following block into your terminal:
kubectl apply -f - <<EOF
apiVersion: apps/v1
kind: Deployment
metadata:
name: coffee
spec:
replicas: 1
selector:
matchLabels:
app: coffee
template:
metadata:
labels:
app: coffee
spec:
containers:
- name: coffee
image: nginxdemos/nginx-hello:plain-text
ports:
- containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
name: coffee
spec:
ports:
- port: 80
targetPort: 8080
protocol: TCP
name: http
selector:
app: coffee
EOFThis will create the coffee service and deployment. Run the following command to verify the resources were created:
kubectl get deployments,svcYour output should include a coffee pod and service:
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/coffee 1/1 1 1 7s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/coffee ClusterIP 10.96.188.209 <none> 80/TCP 7sCreate a Gateway:
kubectl apply -f - <<EOF
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: gateway
spec:
gatewayClassName: nginx
listeners:
- name: gateway-listener
port: 80
protocol: HTTP
hostname: "gateway.example.com"
allowedListeners:
namespaces:
from: Same
EOFBy default, Gateways will not allow ListenerSets to attach to them, only when spec.allowedListeners.namespaces.from is configured to something other than None (default), will the Gateway allow ListenerSets to attach to it. Additionally, Gateways must have at least one listener specified to be valid, so a Gateway with zero listeners specified with all of its listeners coming from ListenerSets is not a valid scenario.
After creating the Gateway resource, NGINX Gateway Fabric will provision an NGINX Pod and Service fronting it to route traffic. Verify the gateway is created:
kubectl describe gateways.gateway.networking.k8s.io gatewayVerify the status is Accepted:
Status:
Addresses:
Type: IPAddress
Value: 10.96.163.87
Attached Listener Sets: 0
Conditions:
Last Transition Time: 2026-05-04T23:36:50Z
Message: The Gateway is accepted
Observed Generation: 1
Reason: Accepted
Status: True
Type: Accepted
Last Transition Time: 2026-05-04T23:36:50Z
Message: The Gateway is programmed
Observed Generation: 1
Reason: Programmed
Status: True
Type: ProgrammedSave the public IP address and port(s) of the Gateway into shell variables:
GW_IP=XXX.YYY.ZZZ.III
GW_PORT=<port number>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.
For those that are familiar with the Gateway resource, ListenerSet spec.listeners is a direct copy of the Gateway’s spec.listeners. For more information, view the API Reference.
Create a ListenerSet:
kubectl apply -f - <<EOF
apiVersion: gateway.networking.k8s.io/v1
kind: ListenerSet
metadata:
name: listenerset
spec:
parentRef:
name: gateway
kind: Gateway
group: gateway.networking.k8s.io
listeners:
- name: listenerset-listener
port: 80
protocol: HTTP
hostname: "cafe.example.com"
allowedRoutes:
namespaces:
from: All
EOFThis will create a ListenerSet named listenerset, attached to the Gateway we created previously, and with a single listener named listenerset-listener.
Verify the ListenerSet has been configured:
kubectl describe listenersets.gateway.networking.k8s.io listenersetStatus:
Conditions:
Last Transition Time: 2026-05-04T23:37:51Z
Message: The ListenerSet is programmed
Observed Generation: 1
Reason: Programmed
Status: True
Type: Programmed
Last Transition Time: 2026-05-04T23:37:51Z
Message: The ListenerSet is accepted
Observed Generation: 1
Reason: Accepted
Status: True
Type: AcceptedVerify the Gateway’s status has been updated:
kubectl describe gateways.gateway.networking.k8s.io gatewayStatus:
Addresses:
Type: IPAddress
Value: 10.96.163.87
Attached Listener Sets: 1
Conditions:
Last Transition Time: 2026-05-04T23:37:51Z
Message: The Gateway is accepted
Observed Generation: 1
Reason: Accepted
Status: True
Type: Accepted
Last Transition Time: 2026-05-04T23:37:51Z
Message: The Gateway is programmed
Observed Generation: 1
Reason: Programmed
Status: True
Type: ProgrammedThe Attached Listener Sets field should now report 1 as the ListenerSet has attached to it successfully.
Create an HTTPRoute attached to the ListenerSet:
kubectl apply -f - <<EOF
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: listenerset-http-route
spec:
parentRefs:
- kind: ListenerSet
group: gateway.networking.k8s.io
name: listenerset
sectionName: listenerset-listener
rules:
- matches:
- path:
type: PathPrefix
value: /coffee
backendRefs:
- name: coffee
port: 80
EOFVerify the HTTPRoute is configured:
kubectl describe httproutes.gateway.networking.k8s.io listenerset-http-routeStatus:
Parents:
Conditions:
Last Transition Time: 2026-05-04T23:39:36Z
Message: The Route is accepted
Observed Generation: 1
Reason: Accepted
Status: True
Type: Accepted
Last Transition Time: 2026-05-04T23:39:36Z
Message: All references are resolved
Observed Generation: 1
Reason: ResolvedRefs
Status: True
Type: ResolvedRefs
Controller Name: gateway.nginx.org/nginx-gateway-controller
Parent Ref:
Group: gateway.networking.k8s.io
Kind: ListenerSet
Name: listenerset
Namespace: default
Section Name: listenerset-listenerVerify the ListenerSet listener’s status has been updated:
kubectl describe listenersets.gateway.networking.k8s.io listenersetStatus:
Conditions:
Last Transition Time: 2026-05-04T23:38:36Z
Message: The ListenerSet is programmed
Observed Generation: 1
Reason: Programmed
Status: True
Type: Programmed
Last Transition Time: 2026-05-04T23:38:36Z
Message: The ListenerSet is accepted
Observed Generation: 1
Reason: Accepted
Status: True
Type: Accepted
Listeners:
Attached Routes: 1
Conditions:
Last Transition Time: 2026-05-04T23:38:36Z
Message: The Listener is programmed
Observed Generation: 1
Reason: Programmed
Status: True
Type: Programmed
Last Transition Time: 2026-05-04T23:38:36Z
Message: The Listener is accepted
Observed Generation: 1
Reason: Accepted
Status: True
Type: Accepted
Last Transition Time: 2026-05-04T23:38:36Z
Message: All references are resolved
Observed Generation: 1
Reason: ResolvedRefs
Status: True
Type: ResolvedRefs
Last Transition Time: 2026-05-04T23:38:36Z
Message: No conflicts
Observed Generation: 1
Reason: NoConflicts
Status: False
Type: Conflicted
Name: listenerset-listener
Supported Kinds:
Group: gateway.networking.k8s.io
Kind: HTTPRoute
Group: gateway.networking.k8s.io
Kind: GRPCRouteThe Attached Routes field should now report 1 as the HTTPRoute has attached to it successfully.
Send a request to the coffee service with this command:
curl --resolve cafe.example.com:$GW_PORT:$GW_IP http://cafe.example.com:$GW_PORT/coffee Server address: 10.244.0.7:8080
Server name: coffee-654ddf664b-4xdrr
Date: 04/May/2026:23:45:57 +0000
URI: /coffee
Request ID: 7dbd29ec0c783475d50ed3b563b0a8a6To set up HTTPS Termination or TLS passthrough on a listener from a ListenerSet, configure the listener on the ListenerSet as you would on a Gateway. Follow our HTTPS Termination and TLS passthrough guides and copy the Gateway listener’s configuration onto a ListenerSet to mimic the behavior.
To learn more about the ListenerSet Gateway API, see the following resources: