• If you are still using CentOS 7.9, it's time to convert to Alma 8 with the free centos2alma tool by Plesk or Plesk Migrator. Please let us know your experiences or concerns in this thread:
    CentOS2Alma discussion

Forwarded to devs Nginx-only php location does not work for WordPress permalinks

TimReeves

Regular Pleskian
Username: TimReeves

TITLE

Nginx-only php location does not work for WordPress permalinks

PRODUCT, VERSION, OPERATING SYSTEM, ARCHITECTURE

Plesk WebAdmin, 18.0.33, Debian 9, PHP-FPM

PROBLEM DESCRIPTION

I'm using nginx with no proxy mode ("Turn off to stop using Apache") - but the Plesk standard configuration does not work with WordPress, when in WordPress "Settings | Permalinks | Common Settings | Post name" is chosen (as is usual, for SEO reasons), or any other permalink form with a trailing slash. Until now, (for 6 years) I have been using a custom template for nginxDomainVirtualHost.php, which I keep having to update as Plesk nginx config evolves, so now I was looking if I can dispense with the custom template.

Sadly, there is one almost-showstopper and some not-so-optimal stuff in the standard template /usr/local/psa/admin/conf/templates/default/domain/nginxDomainVirtualHost.php.

The (almost) Showstopper

Starting at line 211 two conditions are tested and if true this nginx code is generated:

location ~ /$ { index <?=$VAR->quote($VAR->domain->physicalHosting->directoryIndex)?>; }

This test matches all URLs ending in slash - the assumed intention to provide indexing information for URLs which are directories (otherwise the webserver would refuse to list a directories content). However, some Pseudo-URLs such as WordPress permalinks to articles using the article name also end in slash, and should be passed to WordPress's index.php. But the matched location does not actually DO anything, it just sets the index value. The outcome is, that "index.php" is tacked on to the permalink and WordPress articles are not reachable, the server returns a 404 not found. And since regex location processing in nginx terminates on the first match, and the nginx code which a user can append for a domain is inserted after all the Plesk statements, this situation cannot be remedied with another location statement.

Therefore, it needs to be removed, i.e. the test must be false, but the only thing I could have control over is $VAR->domain->physicalHosting->directoryIndex. This is a (obviously) a string, a string only evaluates to boolean false if it is empty or the string "0". At first I did not see how to set this value for nginx, because when you go to {domain} | Apache & nginx Settings and look at nginx settings, there is no such field offered. So it takes a leap of intuition to realise that you have to set the value in the section "Common Apache settings", although lower down I have selected "Turn off to stop using Apache" - the UI should be improved here. And also, in the Apache field "Index files", emtpy string and "0" are not accepted, and the field value reverts to its standard value. Thus the test on physicalHosting->directoryIndex can never be false, so the test is currently meaningless, and the location statement for trailing slash URLs will always be generated when not nginxProxyMode.

There is a way to get around this in one's own configuration - rewrites trigger a complete re-evaluation:
rewrite ^/.+/$ /index.php?q=$uri&$args last;

But I would prefer not to have to do it - as I'm not sure that it will work in all cases.

Sub-optimal: lack of "try_files" in the .php block

Since nginx is not told to check if a .php file actually exists, it passes the request to php-fpm in any case. In such a case, php-fpm just returns a text "File not found" (not even HTML) and sets a 404 HTTP return code. This is not only a waste of resources - the nginx error log fills up with messages like "/var/www/vhosts/example.com/httpdocs/blog-article/index.php" is not found...", so it becomes easy to oversee 'real' error messages in the log - not to mention what happens when your website is subject to a DDoS attack...

So my custom .php location block looks like this:

location ~ \.php(/.*)?$ {
fastcgi_split_path_info ^((?U).+\.php)(/?.+)$;
set $path_info $fastcgi_path_info;
# Requested PHP Scripts MUST exist exactly as named
try_files $fastcgi_script_name =404;
# try_files has emptied $fastcgi_path_info
fastcgi_param PATH_INFO $path_info;
# Tell comet cache that we have cared about the nginx config
fastcgi_param WP_NGINX_CONFIG done;
# You can add any application-special headers to $_SERVER here
fastcgi_param PATH "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin";
fastcgi_pass "unix:///var/www/vhosts/system/$domain/php-fpm.sock";
include /etc/nginx/fastcgi.conf;
# access_log off;
}

Sub-optimal: lack of any way to add to the Plesk .php block

Looking at the custom location block above, which I use, there are two statements, apart from the try_files, which I added:

1) fastcgi_param WP_NGINX_CONFIG done;
This tells a caching plugin that I've done the neccessary already
2) fastcgi_param PATH "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin";
This ramps up the otherwise very brief default value of PATH - some php scripts may need it.

So it would be helpful to have a way to add custom statements (per website) to the .php location.

STEPS TO REPRODUCE

Try the standard Plesk handling of PHP-FPM with WordPress configured to use post name as permalink.

ACTUAL RESULT

Articles are not reachable, instead 404.

EXPECTED RESULT

Articles are displayed.

ANY ADDITIONAL INFORMATION

I discoverd the "location ~ /$" problem nearly 6 years ago - would be really great if it could finally be overcome - easiest fix on Plesk's part to allow empty index string in the domain config.

YOUR EXPECTATIONS FROM PLESK SERVICE TEAM

Confirm bug
 
Sorry, I forget two other comments yesterday:

1) When proxy mode is off, i.e. Apache is "turned off completely", even then, the full Apache config for the domain is generated. But Apache can never be reached in this case, so the configuration, which will cause Apache processes, is just a complete waste of resources on the server. It would be so easy to suppress this. I do it myself with an empty custom template for Apache - I always use only nginx on all domains, so I can do this. And all works fine.

2) There is a first location in the nginx php-fpm block, apparently for web users. I would like to turn this off, as I do not on principle allow web users via Plesk (if need be, they can use FTP or SSH). I would appreciate a possibility to deselect this location statement. Apart from which, I've analysed it and it looks a bit, well, strange:

location ~ ^/~(.+?)(/.*?\.php)(/.*)?$ {
fastcgi_read_timeout 300;
alias /var/www/vhosts/reeves.work/web_users/$1/$2;
fastcgi_split_path_info ^((?U).+\.php)(/?.+)$;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_pass "unix:///var/www/vhosts/system/reeves.work/php-fpm.sock";
include /etc/nginx/fastcgi.conf;
}

location ~ ^/~(.+?)(/.*?\.php)(/.*)?$

It matches from the url start to url end, within that (splitting it up for easier recognition):

/~(.+?)(/.*?\.php)(/.*)? => / ~(.+?) (/.*?\.php) (/.*)?

o URL must start with a slash

o ~ makes the following expression case-insensitive
o Grouping brackets for $1, which gets .+? i.e. any char, one or more of them, "?" matches zero or one occurrences of the regular expression.
This seems to make no sense: The tilde is meaningless, as "." matches any character anyway; the questionmark allows zero or one of one or more :)

o Grouping brackets for $2, catching everything from the last "/" before the first ".php".
Again, the internal expression ".*? seems crazy - a sequence of zero or more of any character, allowed zero or one times?

o Grouping brackets for $3, followed by "?" - so zero or one of "Slash followed by any number of other characters". But $3 is not used.

SO what this effectively does:
- Catches anything after the first slash and before a slash in front of <file>.php as $1
- Catches the <file>.php as $2 ("/<file>.php" must be present)
- Catches any PATH_INFO in $3
 
Thank you. Here is the developer's reply:

1. The (almost) Showstopper - the product issue PPPM-12817 is confirmed.
2. Sub-optimal: lack of "try_files" in the .php block - the product issue PPPM-12815 is already reported
3. Sub-optimal: lack of any way to add to the Plesk .php block - both WP_NGINX_CONFIG none, and PATH aren't domain-specific and can be just added to /etc/nginx/fastcgi.conf. I mean that it might be helpful in some cases, but at this moment we don't have any other complaints, and I recommend to create a UserVoice request.
 
Hey thanks @IgorG , that is truly good news!
Is there any way to see these issues like "PPPM-12817" (and their progress / patch-release) on the public internet? Or do I need to keep inspecting all the release notes? Also, do you have any knowledge or "gut feeling" about the priority of said issues - are we talking about days, weeks or months?
 
@TimReeves There is no possibility for public tracking of bug reports. You can only see the number of the fixed bug report in the changelog for the new Plesk release.
Unfortunately, I can't say anything about the specific timing of the fix. Too many different reasons affect the timing.
 
This is not fixed.
Permalinks are NOT working in the last version of Plesk when FPM is selected with NGINX and the Proxy mode is not enabled.
I only get 404 errors in everything except the homepage.
If you implemented this it would be good to explain HOW so we can check why it's not working.
 
Can you please explain why this is not working on 95% of my sites?. I can only make it work if I create a new WordPress site, older sites are still broken.
On top of that, if a newly created site that is working with NGINX working as native is changed to Apache and then switched back to NGINX native, it stops working and cannot work again.
So this is obviously broken.

I need a fix for this. All of my customers are complaining of broken pages. The previous custom NGINX configuration that I had is not working because you've changed the nginxvirtualdomain files too so I'm at a loss here.

Do I need to change 300 sites back to Apache to make them all work?
 
I have the same issue - none of my sites with permalinks set to "postname" now work. Details for the problem report are:

Nginx-only php location does not work for WordPress permalinks when set to anything other than plain.

PRODUCT, VERSION, OPERATING SYSTEM, ARCHITECTURE

Plesk WebAdmin, 18.0.45 Update #2, Ubuntu 18.04.6 LTS, Nginx, PHP-FPM 8.1.8, WordPress 6.0.1

PROBLEM DESCRIPTION

Any wordpress installation (existing or newly created) that has permalinks set to "Post name" or a customer stucture with "/%postname%/" displays a 404 error when accessing any of the posts. The initial home page is always available. If the permalink is set back to "plain" then the site correctly shows the home page and the individual posts. There are no added directives for any of the components (nginx/ apache or php). This appears to have happened in either most recent or previous updates.


STEPS TO REPRODUCE

1) For the domain apache and nginx settings: all Apache settings set to "default". Smart file processing is ticked. No additional nginx directives specified
2) for the domain php settings: VErsion 8.1.8 is selected running as "FPM Application served by nginx". No additional directives specified.
3) For the wordpress settings : Hotlink protection is enabled, search engine indexing is disabled. All plugins / themes are upto date. Security status settings have benen loosened. Only options ticked enabled : Restrict Access to files, Configure SEcurity Keys, Block Directory Browsing, Block unauth access to wp-config, Disable php execution in cache, change default table predix, block access to sensitive files, change admin username.

Redirect from http to https is enabled.

ACTUAL RESULT

Articles and posts are not reachable if anything other than "plain" is selected for permalink. A 404 error is displayed.

EXPECTED RESULT

Articles/posts are displayed when permalink type other than "Plain" is selected.

ANY ADDITIONAL INFORMATION

I have tested this now against an existsing plesk managed site and one created this morning from clean on a new domain. I have then also run a wordpress installation using manual config on another UBuntu server, with the same php / wordpress versions. As the manual installation works, I believe it is a bug somewhere in the plesk installation.


YOUR EXPECTATIONS FROM PLESK SERVICE TEAM

A temporary fix to get me through the problem and a fix for the next plesk release.
 
@Hockeychap I asked for a new separate report, not an addition to an existing one. Please do so. This is necessary for proper processing.
 
@Hockeychap I asked for a new separate report, not an addition to an existing one. Please do so. This is necessary for proper processing.
My apologies - I thought you might have wanted to tag it on as it appears to be the same issue - I will open a new discussion thread (and cut and paste my description etc)
 
Back
Top