Skip to main content

Nginx + PHP-FPM Pod Troubleshooting

·1209 words·6 mins
Jack Warner
Author
Jack Warner
A little blog by me

Scenario
#

An application using Nginx and PHP-FPM failed to serve pages. The resources involved:

  • Pod: nginx-phpfpm
  • ConfigMap: nginx-config

Your task is to find and fix the issue, then copy /home/thor/index.php from the jump host into the Nginx document root inside the nginx-container so the site becomes accessible.

Diagnosis
#

You provided the recent pod events and logs — both containers started successfully, so this is not a startup or image-pull failure. Here are the events observed:

Normal  Scheduled  6m52s  default-scheduler  Successfully assigned default/nginx-phpfpm to kodekloud-control-plane
Normal  Pulling    6m51s  kubelet            Pulling image "php:7.2-fpm-alpine"
Normal  Pulled     6m49s  kubelet            Successfully pulled image "php:7.2-fpm-alpine"
Normal  Created    6m49s  kubelet            Created container php-fpm-container
Normal  Started    6m48s  kubelet            Started container php-fpm-container
Normal  Pulling    6m48s  kubelet            Pulling image "nginx:latest"
Normal  Pulled     6m43s  kubelet            Successfully pulled image "nginx:latest"
Normal  Created    6m43s  kubelet            Created container nginx-container
Normal  Started    6m42s  kubelet            Started container nginx-container

Nginx logs show the container initialized and is ready to start:

/docker-entrypoint.sh: Configuration complete; ready for start up

PHP-FPM logs show the PHP process is running and ready to handle connections:

[12-Jan-2026 19:48:39] NOTICE: fpm is running, pid 1
[12-Jan-2026 19:48:39] NOTICE: ready to handle connections

Because both containers are Running and Ready (see kubectl describe pod), and the nginx-config is mounted into /etc/nginx/nginx.conf, we can draw specific conclusions from the provided outputs.

Observed from kubectl describe pod nginx-phpfpm:

Containers:
	php-fpm-container: Ready: True
	nginx-container:    Ready: True
Mounts:
	/var/www/html from shared-files (rw)
	/etc/nginx/nginx.conf from nginx-config-volume (rw,path="nginx.conf")

ConfigMap nginx-config contents show Nginx is listening on port 8099 and serving from /var/www/html with index including index.php. The fastcgi_pass is configured as 127.0.0.1:9000:

server {
	listen 8099 default_server;
	root /var/www/html;
	index  index.html index.htm index.php;
	location / {
		try_files $uri $uri/ =404;
	}
	location ~ \.php$ {
		include fastcgi_params;
		fastcgi_param REQUEST_METHOD $request_method;
		fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
		fastcgi_pass 127.0.0.1:9000;
	}
}

Root cause analysis:

  • Nginx and PHP-FPM are up and running and the ConfigMap is mounted.
  • The ConfigMap config sets root /var/www/html; (so Nginx expects files under /var/www/html).
  • The shared-files EmptyDir is mounted at different paths in the two containers:
    • In php-fpm-container it is mounted at /var/www/html.
    • In nginx-container it is mounted at /usr/share/nginx/html.
  • Because Nginx’s configured root (/var/www/html) does not exist inside the nginx-container (its shared volume is at /usr/share/nginx/html), requests return 404 even though the file may exist in the php-fpm-container path.

Therefore the immkubectl delete pod nginx-phpfpm

wait for new pod to be Ready before proceeding
#

kubectl get pods -wkubectl delete pod nginx-phpfpm

wait for new pod to be Ready before proceeding
#

kubectl get pods -wkubectl delete pod nginx-phpfpm

wait for new pod to be Ready before proceeding
#

kubectl get pods -wediate fix is to make Nginx use the path it actually has mounted, or change the mount path in the pod spec. The simpler, safe approach is to update the nginx-config ConfigMap so root points to /usr/share/nginx/html (the path present in the nginx-container). After that, recreate the pod so Nginx picks up the updated config and then copy the index.php into /usr/share/nginx/html inside the nginx-container.

Fix summary: change root /var/www/html; to root /usr/share/nginx/html; in the nginx-config ConfigMap, restart the pod, then copy /home/thor/index.php into /usr/share/nginx/html/index.php in nginx-container.

Likely Root Cause
#

In many kata-style exercises the common issue is a configuration typo in nginx-config that points Nginx to the wrong PHP-FPM socket (e.g. fastcgi_pass unix:/var/run/php-fpm.sock; when the PHP-FPM container listens on 127.0.0.1:9000 or vice-versa), or an invalid include/syntax causing the Nginx process to not start.

For this scenario, inspect the nginx-config contents and look for fastcgi_pass pointing to a non-existent socket or mismatched upstream.

Fix
#

Edit the ConfigMap in-place and correct the fastcgi_pass setting (or other syntax errors):

kubectl edit configmap nginx-config
  • If fastcgi_pass is set to 127.0.0.1:9000, ensure PHP-FPM listens on TCP socket at that address.
  • If it uses a unix socket path, ensure PHP-FPM creates that socket and the volume mount points match.

After saving the corrected ConfigMap, restart the pod to pick up the new configuration:

kubectl delete pod nginx-phpfpm
# pod will be recreated by its controller (Deployment/ReplicaSet) if present

If the pod is a standalone Pod (not managed), re-create it using the corrected manifest.

Copy index.php into container
#

Once the pod is running and Nginx is serving, copy /home/thor/index.php from the jump host into the container’s document root (commonly /usr/share/nginx/html or /var/www/html depending on your image). First, confirm the document root used by your Nginx configuration.

Assuming document root is /usr/share/nginx/html and the container name is nginx-container:

kubectl cp /home/thor/index.php nginx-phpfpm:/usr/share/nginx/html/index.php -c nginx-container

If the pod uses a Deployment and new pods are created, copy the file into the running pod’s container after it’s ready.

Verification
#

  • Check pod status:
kubectl get pods
kubectl describe pod nginx-phpfpm
  • Tail Nginx logs:
kubectl logs -f nginx-phpfpm -c nginx-container
  • After copying index.php, open the Website button in the top bar (or curl the NodePort/ingress URL) to verify the PHP page is rendered:
curl -sS http://<node-ip>:<nodeport>/ | head -n 30

Useful commands to inspect and fix nginx-config
#

# View current configmap contents
kubectl get configmap nginx-config -o yaml

# Edit the configmap in-place
kubectl edit configmap nginx-config

# After editing, restart the pod to pick up changes
kubectl delete pod nginx-phpfpm

If you get 502 Bad Gateway after copying the file, check these logs for clues:

kubectl logs nginx-phpfpm -c nginx-container --tail=200
kubectl logs nginx-phpfpm -c php-fpm-container --tail=200

If you want, I can craft the exact fastcgi_pass fix if you paste the nginx-config content here. Otherwise run the kubectl get configmap nginx-config -o yaml command and look for the fastcgi_pass line — it should point to the address/socket where PHP-FPM is listening (for example 127.0.0.1:9000 or the unix socket path /var/run/php/php7.2-fpm.sock).

Exact commands to run now (from the jump host)
#

  1. Confirm index.php is missing inside the container:
kubectl exec -it nginx-phpfpm -c nginx-container -- ls -la /var/www/html || true
  1. Copy the file from the jump host into the running container:
kubectl edit configmap nginx-config

# In the editor, change the `root` line from `/var/www/html` to `/usr/share/nginx/html` and save.

# Recreate the pod so the nginx container picks up the new config
kubectl delete pod nginx-phpfpm

# Wait for the pod to become Ready, then copy the file into the nginx container's mount path
kubectl cp /home/thor/index.php nginx-phpfpm:/usr/share/nginx/html/index.php -c nginx-container
  1. Confirm the file is present and readable by both containers:
kubectl exec -it nginx-phpfpm -c nginx-container -- ls -la /var/www/html/index.php
kubectl exec -it nginx-phpfpm -c php-fpm-container -- ls -la /var/www/html/index.php
  1. Check logs if you still see issues:
kubectl logs nginx-phpfpm -c nginx-container --tail=200
kubectl logs nginx-phpfpm -c php-fpm-container --tail=200
  1. Verify via curl (replace <node-ip> and <nodeport> with your cluster/node details):
curl -sS http://<node-ip>:<nodeport>/ | head -n 50

If the page still returns 404, paste the output of step (1) and the kubectl get configmap nginx-config -o yaml here and I’ll provide the exact next diagnosis. Otherwise, after step (2) the Website button should work and serve the PHP page.

Expected result: the PHP page is served and contains whatever test output is in /home/thor/index.php.

Notes
#

  • If you continue to see 502 Bad Gateway, it’s typically a PHP-FPM connection issue—verify fastcgi_pass and ensure PHP-FPM is listening on the configured address/socket.
  • If kubectl cp fails due to permissions, ensure you run it from the jump host location with the source file accessible.

Related