How to Fix Nginx Connection Refused on Kubernetes Pod


The Root Cause

“Nginx Connection Refused” on a Kubernetes Pod typically indicates that the application (Nginx) inside the container is not listening on the port that Kubernetes expects, or that the Service resource is unable to route traffic to the correct Pod. This often stems from a mismatch between the containerPort defined in the Pod/Deployment and the targetPort in the Service, or an incorrect Service selector preventing traffic from reaching the Nginx Pod entirely.

Quick Fix (CLI)

Use these commands to diagnose the issue immediately:

  1. Check Pod Logs for Nginx Errors: Identify your Nginx pod name (e.g., nginx-deployment-xxx-yyy) and check its logs. Look for startup failures or configuration errors.

    kubectl get pods -l app=nginx
    kubectl logs <nginx-pod-name>
  2. Inspect Pod Status and Events: Examine the Pod’s status, events, and port configurations.

    kubectl describe pod <nginx-pod-name>
  3. Inspect Service Endpoints: Verify if the Service has successfully discovered and linked to your Nginx Pods. If “Endpoints” is <none>, the Service selector or Pod labels are likely mismatched, or the Pod is not ready.

    kubectl describe svc <nginx-service-name>
  4. Verify Nginx Process and Listening Port Inside the Container: If the Pod is running but connection is refused, exec into the container and check if Nginx is actually running and listening on the expected port (e.g., 80).

    kubectl exec -it <nginx-pod-name> -- /bin/sh
    # Inside the container:
    ps aux | grep nginx
    netstat -tulnp | grep :80 # Or the expected port
    exit

Configuration Check

The resolution usually involves modifying one or more of these Kubernetes manifest files:

  1. Deployment / Pod Specification (deployment.yaml or pod.yaml):

    • Ensure containerPort matches the port Nginx is configured to listen on inside the container.
    # Example: Deployment.yaml
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: nginx-deployment
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: nginx
      template:
        metadata:
          labels:
            app: nginx
        spec:
          containers:
          - name: nginx
            image: nginx:latest
            ports:
            - containerPort: 80 # <-- This must match Nginx's internal listen port
  2. Service Specification (service.yaml):

    • Verify targetPort matches the containerPort defined in your Pod/Deployment.
    • Confirm that the selector labels accurately match the labels of your Nginx Pods.
    # Example: Service.yaml
    apiVersion: v1
    kind: Service
    metadata:
      name: nginx-service
    spec:
      selector:
        app: nginx # <-- Must match Pod labels
      ports:
        - protocol: TCP
          port: 80        # Port the Service listens on
          targetPort: 80  # <-- Must match Pod's containerPort
  3. Nginx Configuration (nginx.conf): If Nginx is not listening on the expected port (e.g., 80), check its configuration. This file might be:

    • Mounted via a Kubernetes ConfigMap.
    • Baked into the Docker image via the Dockerfile. Ensure the listen directive is correct:
    # Example: snippet from nginx.conf
    server {
        listen 80; # <-- Ensure Nginx listens on the correct port
        server_name localhost;
        ...
    }

    If you modify nginx.conf via a ConfigMap, you’ll need to roll out a new deployment to pick up the changes. If it’s in the Dockerfile, rebuild and redeploy the image.

Verification

After applying configuration changes, verify the fix using these steps:

  1. Check Service Endpoints (Crucial): This command confirms if your Service has successfully found and connected to healthy Pods. You should see IP addresses listed under Endpoints.

    kubectl get ep <nginx-service-name>
  2. Test Connectivity to the Service: Use curl to send a request to your Nginx Service’s cluster IP or exposed endpoint (NodePort, LoadBalancer, Ingress).

    kubectl get svc <nginx-service-name>
    # If using ClusterIP from another pod:
    kubectl run -it --rm --image=busybox:latest curl-test -- /bin/sh
    # Inside busybox:
    wget -O- <nginx-service-name>:<port>
    exit

    Or, if exposed externally (e.g., LoadBalancer):

    curl http://<external-ip-of-service>