How to Fix Nginx 404 Not Found on Kubernetes Pod


The Root Cause

On Kubernetes, an Nginx 404 Not Found error most commonly occurs because the Nginx container cannot locate the requested web content within its filesystem, usually due to a mismatch between Nginx’s root directive and the actual path where application files are mounted or copied. This often stems from incorrect volumeMounts in the Pod definition or an improperly configured Dockerfile that places content in an unexpected location.

Quick Fix (CLI)

These commands help diagnose the immediate problem within the running pod:

  1. Identify the Nginx Pod:

    kubectl get pods -l app=nginx # Adjust label selector as needed
  2. Access the Pod’s shell:

    kubectl exec -it <nginx-pod-name> -- bash
  3. Inside the Pod, locate nginx.conf and identify its root directive:

    find / -name nginx.conf # Find the Nginx configuration file
    cat <path_to_nginx.conf> | grep "root"

    Common paths for nginx.conf: /etc/nginx/nginx.conf, /etc/nginx/conf.d/default.conf

  4. Verify the content exists at the specified root path from the previous step:

    ls -la <nginx_root_directory>
    ls -la <nginx_root_directory>/index.html # Or other expected entry file
  5. Examine Kubernetes Pod definition for volume-related issues (if content is missing or path is incorrect):

    exit # Exit the pod shell
    kubectl describe pod <nginx-pod-name> | grep -E "Volumes:|Volume Mounts:"

    This helps identify if the correct content source (e.g., ConfigMap, PVC, hostPath) is mounted to the expected containerPath.

Configuration Check

Based on the diagnosis, the fix will involve editing one or more configuration files:

  1. Kubernetes Deployment/Pod Manifest (e.g., deployment.yaml):

    • Verify volumeMounts: Ensure the path where your application content is expected matches Nginx’s root directive.
      containers:
      - name: nginx
        image: my-nginx-image:latest
        volumeMounts:
        - name: app-content-volume
          mountPath: /usr/share/nginx/html # This path must match Nginx's root directive
      volumes:
      - name: app-content-volume
        configMap:
          name: my-app-html-content # Or persistentVolumeClaim, emptyDir, etc.
    • Check ConfigMap for nginx.conf (if applicable): If you’re providing a custom nginx.conf via a ConfigMap, ensure the root directive within it is correct.
      apiVersion: v1
      kind: ConfigMap
      metadata:
        name: nginx-config
      data:
        nginx.conf: |
          server {
            listen 80;
            root /usr/share/nginx/html; # Ensure this path is correct and accessible
            index index.html index.htm;
            location / {
              try_files $uri $uri/ =404;
            }
          }
  2. Dockerfile (if building a custom Nginx image):

    • Inspect COPY commands: Ensure your application’s static files are copied to the path Nginx expects.
      FROM nginx:alpine
      COPY ./build /usr/share/nginx/html # Ensure /usr/share/nginx/html is where Nginx looks
      # Optionally, copy a custom nginx.conf
      # COPY ./nginx.conf /etc/nginx/nginx.conf
    • Rebuild and redeploy the image if Dockerfile changes are made.

Verification

After applying configuration changes and redeploying the affected Pods:

  1. Port-forward to the Nginx Pod and access locally:
    kubectl port-forward <nginx-pod-name> 8080:80
  2. In a new terminal, test the service:
    curl http://localhost:8080
    You should receive the HTML content of your index page (or expected file) instead of a 404.