Nginx Rewrite to remove php extensions from URI

How to "finally" remove all the php extensions from your URL/URI using Nginx rewrites in Ubuntu (LEMP / PHP-FPM).

Nginx Rewrite to remove php extensions from URI
Photo by Gabriel Heinzer / Unsplash

Update 1: I edited the rewrites for the user pages generated by queries.

Update 2: The final streamlined rewrite is below at the bottom of the post.

This was an issue that boggled my mind for a couple days. I wanted to remove all PHP extensions from the URI. This was never an issue for me with running WordPress, Moodle, and Laravel, on the same Ubuntu server. I am running my website on a LEMP server with PHP-FPM at Linode. For a pure PHP website, this proved, unnecessarily, difficult. Luckily, I found the solution after reading up more on Nginx rewrite rules.

My goal was to remove the PHP extensions in all my pages. You can see in the code block below, that meant removing them from index.php, about.php, version.php, and all the user pages. Yes, I tried using try_files and the variations, such as below, but it still did not work.

try_files $uri $uri/ $uri.php $uri.php$is_args$query_string;

Works with WordPress and dynamic sites.

Finally, I found a rewrite that would remove the php extension:

location ~ ^/(user)$
    rewrite ^/(.*)$ /$1.php last;
}

rewrite ^(/.+?)/?$ $1.php last;
rewrite ^/(about|version)$ /$1.php last;
rewrite_log on;

That worked great, but I was using index.php for my homepage which fully worked with domain.xyz/index, but not with domain.xyz which provided a 404 error.

Then, with the help of ChatGPT, I realized I forgot to add the following rewrite:

rewrite ^/$ /index.php last;

After I inserted it into the correct block, restarted Nginx, I finally got all the PHP extensions to remove from all the URIs. Below is my final configuration. Be sure to put the rewrites below the initial server block above the first location block.

server {
    listen [::]:80;
    listen 80;
    server_name domain.xyz www.domain.xyz;
    root /var/www/webfolder;
    index index.php;

    location ~ ^/(user)$
        rewrite ^/(.*)$ /$1.php last;
}

    rewrite ^(/.+?)/?$ $1.php last;
    rewrite ^/(about|version)$ /$1.php last;
    rewrite ^/$ /index.php last;
    rewrite_log on;

    location / {
        try_files $uri $uri/ /index.php =404;
    }

    location ~ \.php$ {
        include snippets/fastcgi-php.conf;
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass unix:/run/php/php8.2-fpm.sock;
        if (!-f $document_root$fastcgi_script_name) {
             return 404;
     }
        include fastcgi_params;
    }
}

Now I know, there has to be an even more streamlined way to get all the rewrites to work with one line. I am still trying to research this more, until then, this works fine for me.

Streamlined Rewrite

The problem with the rewrite above was that is was not allowing access to the folder with my css file. After about three days, I finally got the below edit to work.

location / {
rewrite ^(/.+)\.php$ $1 permanent;
rewrite ^(/.+?)/?$ $1.php last;
try_files $uri $uri/ /index.php?$query_string =404;
}

Subscribe to Kevin Matsunaga

Don’t miss out on the latest issues. Sign up now to get access to the library of members-only issues.
jamie@example.com
Subscribe