Configuring an AWS Target Group Health Check for the NGINX Gateway Fabric Data Plane Daemonset Pods

Please use this template for troubleshooting questions.

My issue:
cannot figure out how to expose /readyz to my AWS Target Group’s Health Check, /readyz on port 8081 is exposed in the cluster, but the worker node is not exposing /readyz for the AWS Target Group Health Check to be successful.

How I encountered the problem:
installing NGF for the first time

Working Solution:
Here’s a minimal hashicorp/http-echo backend plus the HTTPRoute for ALB health checks. This puts everything in nginx-gateway so it is easy to manage with the shared gateway.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: gateway-healthcheck
  namespace: nginx-gateway
  labels:
    app: gateway-healthcheck
spec:
  replicas: 2
  selector:
    matchLabels:
      app: gateway-healthcheck
  template:
    metadata:
      labels:
        app: gateway-healthcheck
    spec:
      containers:
      - name: http-echo
        image: hashicorp/http-echo:1.0.0
        args:
        - "-listen=:5678"
        - "-text=ok"
        ports:
        - containerPort: 5678
          name: http
        readinessProbe:
          httpGet:
            path: /
            port: 5678
          initialDelaySeconds: 2
          periodSeconds: 5
        livenessProbe:
          httpGet:
            path: /
            port: 5678
          initialDelaySeconds: 5
          periodSeconds: 10
---
apiVersion: v1
kind: Service
metadata:
  name: gateway-healthcheck
  namespace: nginx-gateway
  labels:
    app: gateway-healthcheck
spec:
  selector:
    app: gateway-healthcheck
  ports:
  - name: http
    port: 80
    targetPort: 5678
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: gateway-healthcheck
  namespace: nginx-gateway
spec:
  parentRefs:
  - name: nginx-gateway
    namespace: nginx-gateway
  rules:
  - matches:
    - path:
        type: Exact
        value: /healthz
    backendRefs:
    - name: gateway-healthcheck
      port: 80

Then set the ALB target group health check to:

  • protocol: HTTP

  • port: your existing gateway listener NodePort

  • path: /healthz

  • success codes: 200

Version of NGF and/or NGINX:
2.5.1

Deployment environment:
test

What I am asking the community, is there an easier way to accomplish this?

@beergeek303 Are you wanting the /readyz endpoint on the gateway to be exposed on the LoadBalancer Service? If so, you can update the NginxProxy CRD with the following config to expose the readiness port on the Service

spec:
  kubernetes:
    deployment:
      container:
        readinessProbe:
          expose: true

References:

No, we don’t use the Load Balancer Service. We have an already deployed ALB, we only add in a listener that points to the target group for the node port.

Here is our Helm values we pass in:

nginx:
  kind: daemonSet
  config:
    ipFamily: ipv4
  service:
    type: NodePort
    nodePorts:
    - port: 32323
      listenerPort: 80
gateways:
-  name: nginx-gateway
   namespace: nginx-gateway
   spec:
     gatewayClassName: nginx
     listeners:
       - name: http
         port: 80
         protocol: HTTP
         allowedRoutes:
           namespaces:
             from: All

The setup is working, but we are looking the best approach for allowing the target group to monitor readyz.

Do you just need the readyz 8081 port exposed on the NodePort Service then? (shouldn’t matter LB vs NodePort)

In the helm values, what if you set

nginx:
  container:
    readinessProbe:
      expose: true

We have add this config:

nginx:
  kind: daemonSet
  config:
    ipFamily: ipv4
  container:
    readinessProbe:
      expose: true
  service:
    type: NodePort
    nodePorts:
    - port: 32323
      listenerPort: 80
gateways:
-  name: nginx-gateway
   namespace: nginx-gateway
   spec:
     gatewayClassName: nginx
     listeners:
       - name: http
         port: 80
         protocol: HTTP
         allowedRoutes:
           namespaces:
             from: All

We can get a response back from a data plane pod:

❯ curl -i http://10.XX.XX.XX:8081/readyz
HTTP/1.1 200 OK
Server: nginx
Date: Tue, 14 Apr 2026 20:15:25 GMT
Content-Type: application/octet-stream
Content-Length: 0
Connection: keep-alive

But when we try to get a response back from the node using the node port, the same node the data plane pod resides on:

❯ curl -i http://10.XX.XX.XX:32323/readyz
HTTP/1.1 404 Not Found
Server: nginx
Date: Tue, 14 Apr 2026 20:39:12 GMT
Content-Type: text/html
Content-Length: 146
Connection: keep-alive

<html>
<head><title>404 Not Found</title></head>
<body>
<center><h1>404 Not Found</h1></center>
<hr><center>nginx</center>
</body>
</html>

What we are ultimately trying to accomplish here is to get a health check endpoint for the nginx proxy.

This works in ingess-nginx currently for /healthz. Just looking for similar functionality to help others as well who will bump into this potentially. Thanks for your support.

I see now, the NodePort you configured maps to port 80 on the Service, not 8081 where the /readyz endpoint is exposed.

What if in your Service nodeport config you add:

service:
  type: NodePort
  nodePorts:
  - port: 32323
    listenerPort: 80
  - port: 32324
    listenerPort: 8081

That worked! We were used to both being on the same port, but now they are different (80/8081). We updated out AWS Target Group Health Check to check 32324 now and it works. We did validate we did need the expose: true for this to work as well.

Glad to hear it!

We were used to both being on the same port, but now they are different

Yes, the current setup is that only the paths that are defined in HTTPRoutes get exposed on the ports defined in the Gateway Listeners that those Routes are attached to. We don’t create an extra /readyz endpoint on those ports, because they are owned by the Listeners/HTTPRoutes. So we expose it on a separate port that won’t conflict with anything that might be defined in an HTTPRoute.