Fix: Nginx URL Rewrites Displaying Raw PHP Source Code
The Issue
Section titled “The Issue”In high-performance cloud environments (AWS EC2, GCP Compute Engine, or Azure VMs), a common misconfiguration occurs when implementing “Pretty URLs” or custom routing logic. Instead of the PHP engine processing the script, the browser renders the raw <?php ... ?> source code or prompts for a file download.
This typically happens because the Nginx rewrite logic routes the request to a URI that no longer matches the defined PHP processing location block, or the rewrite happens after the script execution phase in the Nginx request lifecycle.
Exact Error Log
Section titled “Exact Error Log”While the Nginx error.log often remains silent (as the server technically fulfills the request with a 200 OK), the “error” is visible in the client-side response or the Access Log:
Access Log (/var/log/nginx/access.log):
172.31.24.11 - - [12/Oct/2023:14:22:01 +0000] "GET /api/users/1 HTTP/1.1" 200 452 "-" "Mozilla/5.0..."Response Body (Browser View Source):
<?php// Sensitive Database Configurationdefine('DB_PASSWORD', 'super-secret-password');include_once('controller/User.php');...?>Diagnostic Checklist
Section titled “Diagnostic Checklist”- FastCGI Service Status: Ensure
php-fpmis actually running in the background. - Location Block Precedence: Check if your rewrite rule is sending the request to a location that lacks the
fastcgi_passdirective. - MIME Type Mismatch: Verify that
include /etc/nginx/mime.types;is present in thehttpblock. - Socket Permissions: On Linux instances, ensure the Nginx user (
www-dataornginx) has read/write permissions to the PHP-FPM.sockfile. - The “Try_Files” Trap: Ensure
try_filespoints toindex.phpwith arguments, and thatindex.phpis caught by a regex location block.
The Fix
Section titled “The Fix”1. Correcting the Nginx Location Logic
Section titled “1. Correcting the Nginx Location Logic”The most common cause is defined by a regex order conflict. In Nginx, a regular expression match (location ~ \.php$) takes precedence over a prefix match unless the ^~ modifier is used.
Update your site configuration (e.g., /etc/nginx/sites-available/default) to ensure all rewrites are captured by the FastCGI handler.
server { listen 80; server_name api.example.com; root /var/www/html/public; index index.php index.html;
# Rewrite rule for clean URLs location / { try_files $uri $uri/ /index.php?$query_string; }
# Ensure this block handles the result of the rewrite location ~ \.php$ { include snippets/fastcgi-php.conf;
# Adjust socket path based on your PHP version (e.g., 8.1, 8.2) fastcgi_pass unix:/var/run/php/php8.1-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; }}2. Verify PHP-FPM Environment Configuration
Section titled “2. Verify PHP-FPM Environment Configuration”If you are using a custom cloud image, PHP-FPM might be listening on a network port instead of a Unix socket. Check your PHP-FPM pool configuration.
Check /etc/php/8.1/fpm/pool.d/www.conf:
# Ensure the listener matches the Nginx fastcgi_passlisten = /var/run/php/php8.1-fpm.sock
# Ensure permissions are set for the web serverlisten.owner = www-datalisten.group = www-datalisten.mode = 06603. Permission and Ownership Audit
Section titled “3. Permission and Ownership Audit”On AWS/GCP, manual deployments often suffer from incorrect ownership, leading Nginx to read the file as a static asset rather than passing it to the upstream.
# Set ownership to the web user (Ubuntu/Debian standard)sudo chown -R www-data:www-data /var/www/html
# Set correct directory and file permissionssudo find /var/www/html -type d -exec chmod 755 {} \;sudo find /var/www/html -type f -exec chmod 644 {} \;4. Apply and Test
Section titled “4. Apply and Test”Before restarting, always validate the syntax to ensure no downtime.
# Test Nginx configurationsudo nginx -t
# Reload servicessudo systemctl reload nginxsudo systemctl restart php8.1-fpmBy ensuring that the try_files directive redirects to index.php and that the location ~ \.php$ block is properly configured to handle that path, Nginx will correctly hand off the request to the PHP interpreter rather than serving it as a static text file.