• 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

Input Joomla (multilingual too) under native nginx

Sergio Manzi

Regular Pleskian
... or, paraphrasing the old saying, "quite a big leap for me, but a really small step for mankind".

I've passed the last few days fighting my battle with Plesk, Joomla and nginx. The objective was to have Joomla to run natively (not in "proxy mode") under Plesk's nginx.

Joomla, as most CMS I think, want to handle every URL through its main entry point, /index.php, and that seems quite reasonable. Excluded from this must of course be real "static resources", such as images, CSS files, scripts, fonts, etc...

Joomla can (basically, with some more variants in between...) be used with two type of URLs:
the latter requires the cooperation of the web server to redirect the URL to /index.php for parsing.

In Apache this is done by putting the following directives in .htaccess:
Code:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !^/index\.php
RewriteRule .* index.php [L]

Of course the above means "If the URI is not a file, not even a directory and it doesn't start with /index.php, then redirect the damn thing to /index.php".
This has worked, for ages, with Apache and Joomla.

It is common knowledge (Nginx - Joomla! Documentation and Enabling php-fpm + nginx and link rewrite or All URLs Display Homepage Content on a Joomla Website Powered by NGINX | itoctopus among the many I found around) that in nginx you should "translate" the above with the following nginx configuration block:
Code:
location / {try_files $uri $uri/ /index.php?$args;}
or the simpler form (which doesn't bother of the "$args" and seems to perfectly work):
Code:
location / {try_files $uri $uri/ /index.php;}

The above should do about the same (see if it is a file or directory and if not try /index.php) and it mostly works.
But it doesn't always works: enter "Joomla multilingual"!

In multilingual Joomla installations using SEF URLs, the language is expressed by a "language code" used as a prefix in the URL:
Code:
https://example.com/en/
https://example.com/en/8-category-en/1-article
https://example.com/it/
https://example.com/it/9-category-it/2-articolo

Well, for some yet-to-fully-understand reason the above URLs do not work and you get instead a nice "nginx 404" error, even for the "home pages".
This apparently doesn't make any sense: Joomla handle 404s by itself and doesn't let them to "percolate" to the nginx level... but... it happens, methodically, always.

P.S.: Read some posts below: the general issue is with URLs ending with a slash.
"Multilingual" is just a particular case, where Joomla language switcher uses URLs ending with a slash (/en/, /it/, etc...)


In such conditions (if you're an experimenter) try to create the "en" and "it" directories and put /index.html files inside: they are displayed!!!!

From a logcial point of view there are two possibilities to explain the above:
  • "try_files" has an idiosyncrasy for Joomla language codes and handles them in a different way, like they always exists as files/directories even when this is not the case

  • The Joomla router component responsible for parsing language codes (I think it is the "language filter" plugin) has some bug and redirects in such a way to confound nginx.
    I'm slightly inclined to suspect this latter might be the cause.

The solution:


In any case, if it works with Apache, by Jove, it must also work with nginx!
So I did the simplest of the things and "translated" the Apache .htaccess directives in nginx parlance (inverting the logic for implementation simplicity).

put this in your subscription "Apache & nginx Settings" in the "Additional nginx directives".
Code:
set $rewrite 1;
if (-f $request_filename) {set $rewrite 0;}
if (-d $request_filename) {set $rewrite 0;}
if ($uri ~* "^/index\.php") {set $rewrite 0;}
if ($rewrite) {rewrite /.* /index.php last;}

At this point I have the strange feeling of having @trialotto teeth at my throat, grinnning: "if" in nginx is EVIL!

:( I know... but... ehi, the above works, always!! ;)

hoping that someone else can find an even simpler and "if-less" solution, if you have Joomla-nginx-multilingual-blues, please give the above a try: for me it works, flawlessly.

Hope the above can help someone...
 
Last edited:
@Sergio Manzi

I think that you can rewrite the entire

set $rewrite 1;
if (-f $request_filename) {set $rewrite 0;}
if (-d $request_filename) {set $rewrite 0;}
if ($uri ~* "^/index\.php") {set $rewrite 0;}
if ($rewrite) {rewrite /.* /index.php last;}

with one Nginx try_files directive of the form

try_files $uri $uri/ /index.php;

but for a more detailed discussion of this, have a look at: How to Create NGINX Rewrite Rules | NGINX

Anyway, the try_files directive should work, since

- your first two "if" statements are checking for the existence of files and directories, in the same fashion that the try_files directive does, (and)
- your third "if" statement is just saying "use the file/script, if it exists", in a similar fashion that the try_files directive does, (and)
- your fourth "if" statement is just stating "if the file/script does not exist, just use index.php", which is exactly what the try_files directive does,

and that is very, very rough outline of the comparison of your code and the effect of introducing the try_files directive.

Hope the above helps a bit.

Regards!
 
Hello @trialotto!

I already tried (pun intended!) the try_files solution.
Actually all of my post above is an account of me trying that solution and at the end coming to the conclusion that (for whatever reason...) it doesn't work.

I know it sounds absurd, but please give it a try with a Joomla multilingual installation. It's quite an easy feat:
  • create an empty MySQL database to be used by Joomla
  • upload and unzip the latest "stable" Joomla release (3.8.5 as of this writing) in your httpdocs
  • just proceed with a standard Joomla installation (by visiting your front-end) without installing the sample data
  • when asked for the possibility, add a second language to the installation
  • at the end (easy to miss step...) say "Yes" at the "Activate multilingual features" question (This will also install a couple of "articles" for testing).
  • Important: In Joomla "Global Configuration" activate the "Search Engine Friendly URLs" and "Use URL Rewriting" options
Then try and let me know...
 
Actually there are "if-less" solutions:

1) a generic solution that will catch every 2-characters "language prefix" in the URI:
Code:
location / {try_files $uri $uri/ /index.php;}
rewrite ^(/[A-z][A-z]/.*) /index.php;
The above anyway, will catch every 2-characters long prefix (so it will also redirect for any 2-characters long directory name, which is something you potentially don't want...).


2) a "tailored" solution, knowing which are the language codes you're using:
Code:
location / {try_files $uri $uri/ /index.php;}
rewrite ^(/en/.*) /index.php;
rewrite ^(/it/.*) /index.php;
... which not being "generic" it is something I frown upon.


Again,
Code:
location / {try_files $uri $uri/ /index.php;}
doesn't cut, but I must add that it really seems this is due to an interaction with Joomla-multilingual redirects: in a simple "static" site without Joomla, or with a non-multilingual Joomla installation, the above perfectly works.


Addendum: for solution 1) I initially tried:
Code:
location / {try_files $uri $uri/ /index.php;}
rewrite ^(/[A-z]{2}/.*) /index.php;
but that is refused by Plesk with the following error message:
Code:
Invalid nginx configuration: nginx: [emerg] directive "rewrite" is not terminated by ";" in /var/www/vhosts/system/fubar.smz.it/conf/vhost_nginx.conf:2 nginx: configuration file /etc/nginx/nginx.conf test failed
... but the ";" is there, so something must be wrong in my regexp, but I cant't figure out what...
 
Last edited:
@Sergio Manzi

In your last post(s), you essentially used a "location /" block that competes with the default Nginx configuration, shipped with Plesk.

This explains why you get some errors.

Anyway, I will try to investigate the topic in the next 1 or 2 days and provide you with an explanation of what happens and/or what should be done.

Regards!
 
In your last post(s), you essentially used a "location /" block that competes with the default Nginx configuration, shipped with Plesk.

No, I don't think so... That's the case only for when Nginx is set in proxy mode, not for when it is running native.

When you switch from proxy to native mode you can't, at the same time, set a "location /" entry, but after that (i.e. after having switched to native mode), you absolutely can...
 
@trialotto I made further tests and I came to the conclusion that the "try_files" method doesn't work in many others ways for Joomla, not only for multilingual.

In joomla you may have URLs with or without the leading slash:
They do both normally works, under Apache and the Joomla provided .htaccess, leading to the same content

With the try_files method you described (and is widespread advised) all URLs with a leading slash do not work and give a 404

The issue is emerging with multilingual because the URLs generated by the Joomla "language switcher" always contain a trailing slash ("/it/", "/en/", etc...), but it is not just limited to the multilingual environment.

Initially I thought this could be easily solved by eliminating the leading slash with a nginx rewrite:
Code:
rewrite ^/(.*)/$ /$1 permanent;
try_files $uri $uri/ /index.php;
This seems to work for every front-end (site) URL, but... there is a small issue: you can't access joomla back-end anymore, infinite redirect between /administrator and /administrator/ as Joomla always try to redirect to the latter :eek:

I think this might be a Joomla "snafu"... I don't remember if it was done for any good reason...
In any case... it doesn't work!

So far, the only reliable nginx configuration I have found for Joomla is the one I advised in my OP, the horrible one with all those "if"... :(


P.S.: Linguistic doubt: the "last", "rightmost" slash is it "leading" or "trailing" ???? Anyway, above, I'm always talking about the rightmost slash, with nothing to its right...
 
Last edited:
Back
Top