Skip to content

Fix: Nginx URL Rewrites Displaying Raw PHP Source Code

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.

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):

Terminal window
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):

Terminal window
<?php
// Sensitive Database Configuration
define('DB_PASSWORD', 'super-secret-password');
include_once('controller/User.php');
...
?>
  1. FastCGI Service Status: Ensure php-fpm is actually running in the background.
  2. Location Block Precedence: Check if your rewrite rule is sending the request to a location that lacks the fastcgi_pass directive.
  3. MIME Type Mismatch: Verify that include /etc/nginx/mime.types; is present in the http block.
  4. Socket Permissions: On Linux instances, ensure the Nginx user (www-data or nginx) has read/write permissions to the PHP-FPM .sock file.
  5. The “Try_Files” Trap: Ensure try_files points to index.php with arguments, and that index.php is caught by a regex location block.

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.

Terminal window
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_pass
listen = /var/run/php/php8.1-fpm.sock
# Ensure permissions are set for the web server
listen.owner = www-data
listen.group = www-data
listen.mode = 0660

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.

Terminal window
# Set ownership to the web user (Ubuntu/Debian standard)
sudo chown -R www-data:www-data /var/www/html
# Set correct directory and file permissions
sudo find /var/www/html -type d -exec chmod 755 {} \;
sudo find /var/www/html -type f -exec chmod 644 {} \;

Before restarting, always validate the syntax to ensure no downtime.

Terminal window
# Test Nginx configuration
sudo nginx -t
# Reload services
sudo systemctl reload nginx
sudo systemctl restart php8.1-fpm

By 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.