Page MenuHomePhabricator

Mediawiki 1.31 break symlinked, cause LocalSettings.php failed to load.
Open, NormalPublic

Description

Starting from Mediawiki 1.31, Mediawiki will always looking for LocalSettings.php from where the MW code located, instead of the folder containing symlink.

This is not a problem for many single wiki setup. Since their LocalSettings.php are placed right under Mediawiki codes folder.
However, it cause fatal issue to wiki farms where symlink where widely used to set up multiple wikis.

E.G.
We are loading wiki farms in following method:
/www/mediawiki (all MW code, no config file, no web access)
/www/a (web access point, own LocalSettings.php, symlinked to /www/mediawiki)
/www/b (same)
/www/c (...)
/www/d
......
All the wiki failed, due to Mediawiki now only looking for LocalSettings.php under /www/mediawiki folder.

It also break the distribute version of Mediawiki in Debian std. They put MediaWiki core files under /usr/share/mediawiki and then /etc/mediawiki/LocalSettings.php. Mediawiki is loaded via symlink from web-server directory. Therefore, after upgrade to 1.31, Mediawiki will start to load LocalSettings.php under /usr/share/mediawiki, instead of where the symlink LocalSettings.php, which break the site.


This problem seems to be caused by this change: https://gerrit.wikimedia.org/r/plugins/gitiles/mediawiki/core/+/0d5f8f6bee296c4e29f03acbd5c07f34d6c8a88a%5E%21/ in WebStart.php.
Where $IP is set to the folder of Mediawiki codes' absolute path in 1.31, instead of the original path.
Therefore, in line 61

define( 'MW_CONFIG_FILE', "$IP/LocalSettings.php" );

will point LocalSettings.php path to MW code folder, instead of the folder where MW was called.

We'd like Mediawiki to add a specify extra check for and only for LocalSettings.php under where the symlink initiated from MW 1.31 to newest master verison. Because it is easier and safer to Debian/Ubuntu users, and judging which folder to load by nginx/Apache is much faster than a giant LocalSettings.php files with hundreds of if statements for wiki farm.

get the calling url if ( strpos( $callingurl, '/wiki1' ) === 0 ) {

       require_once 'LocalSettings_wiki1.php';
} elseif 
......

few more lines of if statement needs to be add to WebStart.php to fix this problem.
such as

// If no LocalSettings file exists, try to display an error page
// (use a callback because it depends on TemplateParser)
$possibleCurrentDirectoryLocalSettings = getcwd().'/LocalSettings.php'; //an extra check for LocalSettings.php under current Directory incase of symlink used.

if ( !defined( 'MW_CONFIG_CALLBACK' ) ) {
	if ( !defined( 'MW_CONFIG_FILE' ) ) {
		if (  is_readable($possibleCurrentDirectoryLocalSettings) ) {
			define( 'MW_CONFIG_FILE', $possibleCurrentDirectoryLocalSettings );
		}else{
			define( 'MW_CONFIG_FILE', "$IP/LocalSettings.php" );
		}
	}

We tested it, and could confirm that by modify WebStart.php like so, we get the wiki farm run again as well as the Debian distribution MW in version 1.31.

It seems that by setting $IP to the actual MW code path, Mediawiki get slightly better performance due to file path unify in apc. But not much. Therefore, switch back to the way Mediawiki 1.30 used to use(relative path) could be a choice too.

Event Timeline

Zoglun created this task.Aug 29 2018, 6:45 AM
Restricted Application added a subscriber: Aklapper. · View Herald TranscriptAug 29 2018, 6:45 AM
Zoglun updated the task description. (Show Details)Aug 29 2018, 6:50 AM
Legoktm added a subscriber: Krinkle.
Legoktm added a subscriber: Legoktm.
RazeSoldier added a comment.EditedAug 29 2018, 7:14 AM

I guess the web server can pass MW_CONFIG_FILE (custom profile path) environment variable defined by the web server to PHP, and then MW can use it to load LocalSettings.php.

We are loading wiki farms in following method:

  • /www/mediawiki (all MW code, no config file, no web access)
  • /www/a (web access point, own LocalSettings.php, symlinked to /www/mediawiki)

Can you add more details about this structure? I do not understand it currently.

If /www/a is not a directory but a sylink to /www/mediawiki, then it cannot have files. Where is the LocalSettings.php file?

www.a.com point to /www/a.
/www/a contain LocalSettings.php and symlink to each file/folder under /www/mediawiki.

Such structure were documented https://www.mediawiki.org/wiki/Manual:Wiki_family

www.a.com point to /www/a.
/www/a contain LocalSettings.php and symlink to each file/folder under /www/mediawiki.
Such structure were documented https://www.mediawiki.org/wiki/Manual:Wiki_family

I'm not sure such structure was officially supported. (The documentation is freely editable). But, I think we can support this structure.

The only requirement is for MW_INSTALL_PATH to be set as an environment variable to the imitation directory for the current site. Everything will automatically fall into place after that. We can add that to the 1.31 release/upgrade notes.

Krinkle triaged this task as High priority.Aug 31 2018, 7:54 PM
Krinkle added a project: MediaWiki-Installer.
Zoglun added a comment.Sep 1 2018, 6:15 PM

I'm not sure such structure was officially supported. (The documentation is freely editable). But, I think we can support this structure.
The only requirement is for MW_INSTALL_PATH to be set as an environment variable to the imitation directory for the current site. Everything will automatically fall into place after that. We can add that to the 1.31 release/upgrade notes.

Cool!
In our further test, set MW_INSTALL_PATH to the real file path is slightly faster & much more stable under heavy load, which is good compare to the original method used by 1.30. Therefore, it's better to keep MW_INSTALL_PATH as a variable set to the real file path.
But only detect LocalSettings.php from both the symlink directory as well as the real directory. What I mean is similar to the /maintenance schema. Those schema could mark LocalSettings.php location with --conf parameters, as documented here: https://www.mediawiki.org/wiki/Manual:Update.php#Script_specific_parameters . This is useful when LocalSettings.php was placed under other directory, or when they have different name for wiki farm.

Krinkle added a comment.EditedSep 1 2018, 7:18 PM

I'm not sure such structure was officially supported. (The documentation is freely editable). But, I think we can support this structure.
The only requirement is for MW_INSTALL_PATH to be set as an environment variable to the imitation directory for the current site. Everything will automatically fall into place after that. We can add that to the 1.31 release/upgrade notes.

Cool!
In our further test, set MW_INSTALL_PATH to the real file path is slightly faster & much more stable under heavy load, which is good compare to the original method used by 1.30. Therefore, it's better to keep MW_INSTALL_PATH as a variable set to the real file path.
But only detect LocalSettings.php from both the symlink directory as well as the real directory. What I mean is similar to the /maintenance schema. Those schema could mark LocalSettings.php location with --conf parameters, as documented here: https://www.mediawiki.org/wiki/Manual:Update.php#Script_specific_parameters . This is useful when LocalSettings.php was placed under other directory, or when they have different name for wiki farm.

It is good to hear you care about performance. Me too! Optimising for performance is easier when there is only 1 method of doing something. Right now, MediaWiki supports multiple methods.

  1. One imitation directory for every wiki, is supported. This must set MW_INSTALL_PATH to the imitation directory. This still works the same as in 1.30 and earlier versions. This is the current method you describe.
  2. One installation path for all wikis, is supported. The configuration file can be set in two ways:
    • A) Dynamically load the wiki-specific LocalSettings.php file from a central LocalSettings.php file. For example, by loading it based on a custom environment variable set from the web server, or by comparing the virtual hostname in PHP. This is what Wikipedia does today.
    • B) Dynamically set MW_CONFIG_FILE or MW_CONFIG_CALLBACK from an entry point wrapper.

These are all compatible, and supported. They work. But, they are not all the fastest. The difference in performance is small, but if you want the best performance, I recommend you use the same method of installation as Wikipedia.

If I understand correctly, you have more than just settings different per-wiki, but also uploads and cache, and these are not currently explicitly assigned in configuration, but happen automatically by $IP? If you follow method 2A above, these will need to become explicit. For example:

Directories
* private/shared/mediawiki/
* public/www.foo.example/
** uploads/
** LocalSettings.php
** .. symlinks
* public/www.bar.example/
** uploads/
** LocalSettings.php
** .. symlinks

Then, you could do:

Apache
<VirtualHost www.foo.example>
  DocumentRoot /public/www.foo.example/

 SetEnv MYFARM_WIKIDIR=/public/www.foo.example/
</VirtualHost>
private/shared/mediawiki/LocalSettings.php
# (default, real path) $IP = '/private/shared/mediawiki'
$myFarmWikiDir = getenv( 'MYFARM_WIKIDIR' ) ?: '/dev/null';

$wgUploadDirectory = "$myFarmWikiDir/uploads/";
require_once "$myFarmWikiDir/LocalSettings.php";

This means that for the wiki directories, nothing changes. And it means that the installation will use a method that is officially supported, by using configuration variables explicitly.

It also break the distribute version of Mediawiki in Debian std. They put MediaWiki core files under /usr/share/mediawiki and then /etc/mediawiki/LocalSettings.php. Mediawiki is loaded via symlink from web-server directory. Therefore, after upgrade to 1.31, Mediawiki will start to load LocalSettings.php under /usr/share/mediawiki, instead of where the symlink LocalSettings.php, which break the site.

I'm unable to reproduce any breakage using the Debian filesystem symlink layout under MediaWiki 1.31 - it seems to work just fine.

Zoglun added a comment.EditedSep 2 2018, 12:27 AM

It also break the distribute version of Mediawiki in Debian std. They put MediaWiki core files under /usr/share/mediawiki and then /etc/mediawiki/LocalSettings.php. Mediawiki is loaded via symlink from web-server directory. Therefore, after upgrade to 1.31, Mediawiki will start to load LocalSettings.php under /usr/share/mediawiki, instead of where the symlink LocalSettings.php, which break the site.

I'm unable to reproduce any breakage using the Debian filesystem symlink layout under MediaWiki 1.31 - it seems to work just fine.

Debian changes to MediaWiki
We change a few things about MediaWiki to fit in with what Debian expects. Files can be found in the following places:
/usr/share/mediawiki - MediaWiki core files
/etc/mediawiki/LocalSettings.php - expected location of ?LocalSettings.php. You can also put other configuration files in this directory.
/var/lib/mediawiki - Main directory that the webserver will read from. Most core files from /usr/share/mediawiki are symlinked into this directory, and the ?LocalSettings.php file as well.

from https://wiki.debian.org/MediaWiki

Can you load /etc/mediawiki/LocalSettings.php when the site were point to /var/lib/mediawiki with Mediawiki 1.31?

Liuxinyu970226 added a subscriber: Liuxinyu970226.

as we know that this is an Installer problem

Zoglun edited projects, added MediaWiki-General; removed MediaWiki-Installer.EditedSep 2 2018, 11:57 PM

@Krinkle
I tired your method of "SetEnv" in nginx. It does not work due to nginx remove any environment variable. Moreover, env MW_CONFIG_FILE=value; will set a single value to all wikis, which is not ideal for wiki farm.

It does not work with fastcgi_params as well. nginx treat param as $_SERVER like "$_SERVER['MW_CONFIG_FILE'] /mediawiki-setting/LocalSettings-example.com.php". It seems that mediawiki ignored $_SERVER.

I found a bug report in 2015 T115432, which going to load MW_CONFIG_FILE from environment variable. However it not been implemented.

What's the effective way to do this with nginx+php-fpm?


This bug is nothing related to installer.

@Krinkle
I tired your method of "SetEnv" in nginx. It does not work due to nginx remove any environment variable. Moreover, env MW_CONFIG_FILE=value; will set a single value to all wikis, which is not ideal for wiki farm.
It does not work with fastcgi_params as well. nginx treat param as $_SERVER [..]

Somewhere in your web server, there is configuration per wiki, right? Otherwise every website would be identical. There is a variable somewhere somehow for the current wiki and it associates it with a directory on disk, is that right?

If you have that, then that is presumably the place where you tried fastcgi_params. That does not work, I understand. But can you use SetEnv from that same location, instead of from the global location?

Alternatively, if you have a variable for the current website, but not a conditional/location block, then you can still use that variable. For example if you have somewhere DocumentRoot /var/www/$mysite you can use SetEnv MYFARM_SITE=$mysite, and access it from PHP and correlate it to a LocalSettings file.

private/shared/mediawiki/LocalSettings.php
$settingsDir = getenv( 'MYFARM_SITE' ) ? '/private/wiki-settings/' . getenv( 'MYFARM_SITE' ) : '/dev/null';
require_once "$settingsDir/LocalSettings.php";

Or if you want it simpler (but more fragile, in my opinion), you can even use DOCUMENT_ROOT directly, if the settings file is there

private/shared/mediawiki/LocalSettings.php
$documentRoot = $_SERVER['DOCUMENT_ROOT'];
require_once "$documentRoot/LocalSettings.php";

I am closing this issue now, because the use case of storing LocalSettings.php is supported by MediaWiki it. This is done by mediawiki-debian in one way, and is done by Wikimedia Foundation in another way, and there are many other ways to do it. I have shown several ways as examples.

For further help with MediaWiki, I recommend https://www.mediawiki.org/wiki/Project:Support_desk, or https://discourse-mediawiki.wmflabs.org/. For help with how to configure Nginx, I recommend https://nginx.org/en/support.html or https://serverfault.com/questions/ask?tags=nginx.

Krinkle closed this task as Resolved.Sep 7 2018, 12:18 AM
Krinkle claimed this task.

I noticed this in the backscroll of #mediawiki from today:

[11:20:56] <myier> Hi, I am struggling to install mediawiki 1.31 the debian way, with symlinks in /var/lib/mediawiki/* for
[11:20:59] <myier> multi-site install, it always looks for LocalSettings.php in /usr/share/mediawiki where the files are, has
[11:21:02] <myier> this become impossible in 1.31? thanks
Legoktm reopened this task as Open.Sep 26 2018, 4:25 AM
[06:55:05] <TheSin> hey guys debian finally updated to 1.31 but now I can't get it to find the LocalSettings.php that was working, it's a central install, as in I have multiple instances of mediawiki running where each instance have symlinks to shared code
[06:55:36] <TheSin> I assume it's trying to find /etc/mediawiki/LocalSettings.php but it's should be looking for <webroot>/LocalSettings.php
[06:55:44] <TheSin> did somethign change form 1.30 to 1.31?

I think we need to reconsider this behavior change given the amount of breakage it seems to be causing.

Krinkle removed Krinkle as the assignee of this task.Sep 26 2018, 11:38 PM

Yeah, let's revisit before release. I'm still not convinced that we need to restore previous behaviour as-is because I also believe it fixed various things.

But, I recognise the use case. At the very least we should make it really easy to upgrade for these users and maybe at most require them to change one thing (whatever that one thing might be), I think we can afford to require one change on their part for such relatively unusual set up.

80686 added a subscriber: 80686.EditedOct 3 2018, 9:58 AM

just broke my wikis the same way while trying to upgrade to 1.31.1

I have a central directory with MediaWiki files in it.
In the document root I just keep cache, images, LocalSettings.php and mw-config. Everything else is symlinked to the central directory. It used to work fine, now as described above the LocalSettings.php is expected to reside in the central MediaWiki directory instead of the local directory.

Change 466865 had a related patch set uploaded (by Krinkle; owner: Alangi Derick):
[mediawiki/core@master] Fix $IP value when directory is a symlink

https://gerrit.wikimedia.org/r/466865

I think it's fine to add support this. But, if possible, we should do it in a way that doesn't re-introduce the problem described at T153882.

Krinkle moved this task from Backlog to Core on the MW-1.31-release board.Oct 20 2018, 5:48 AM

Is anyone committing to implementing this? It's in the backlog for the release, but in no team's backlog, and not assigned to anyone. If nobody committed to doing this, it probably should not block the release.

@CCicalese_WMF this seems like it's down your alley. What do you think, should CPT pick this up? The code should be minimal/trivial, the tricky bit is to not break some other way of installing MediaWiki in the process.

Larrystrickland raised the priority of this task from High to Needs Triage.Jan 16 2019, 2:11 AM
Larrystrickland updated the task description. (Show Details)
Aklapper triaged this task as High priority.Jan 16 2019, 11:08 AM
Aklapper updated the task description. (Show Details)

Change 466865 abandoned by D3r1ck01:
[NOT TESTED] Fix $IP value when directory is a symlink

Reason:
No longer working on it, seems I've not understood the scope of things here.

https://gerrit.wikimedia.org/r/466865

CCicalese_WMF removed CCicalese_WMF as the assignee of this task.Apr 1 2019, 1:36 PM

Since there is not an insignificant number of installations done using symlinks, this should be fixed.

WDoranWMF lowered the priority of this task from High to Normal.Wed, Jul 17, 8:39 PM