CHG-2025-XX-XX migrate wiki to hetzner3: Difference between revisions

From Open Source Ecology
Jump to navigation Jump to search
(update LocalSettings to enable the new extensions SmiteSpam & DeleteBatch)
 
(64 intermediate revisions by the same user not shown)
Line 24: Line 24:
# changes site from varnish v4.0.5 to v7.1.1
# changes site from varnish v4.0.5 to v7.1.1
# changes site from nginx v1.20.1 to v1.22.1
# changes site from nginx v1.20.1 to v1.22.1
# changes site from php v5.6 to v8.2
# changes site from php v5.6 to v8.2.26
# changes site from using mod_php to php-fpm
# changes site from using mod_php to php-fpm
# update core MediaWiki from v1.30.0 to v1.35
# changes site from mariadb v5.5.68 to v10.11.6
# update ICU from v50.1.2
# update core MediaWiki from v1.30.0 to v1.43.0


# TODO: Extensions updates
# update "Cologne Blue" skin from unknown version to 9134d2e
# update "Modern" skin from unknown version to 5597681
# update "MonoBook" skin from unknown version to unknown version
# update "Vector" skin from unknown version to v1.0.0
 
# update "Confirm User Accounts" extension from version 4fe25f7 to bb470fd
# update "Interwiki" extension from version v3.1 20160307 to v3.2
# update "Nuke" extension from version 1.3.0 to unknown version
# update "Replace Text" extension from version v1.2 (4426752) to v1.8
# update "UserMerge" extension from version 1.10.1 (4546537) to v1.10.2 (f9d2664)
# update "CategoryTree" extension from version 850c018 to unknown version
# update "Cite" extension from unknown version to unknown version
# update "ParserFunctions" extension from v1.6.0 to v1.6.1
# update "Widgets" extension from version v1.3.0 (fce5acc) to v1.6.0 (50da5c6)
# update "ConfirmEdit" extension from v1.5.0 to v1.6.0
# install "hCaptcha" extension (unknown version)
# uninstall "reCaptcha" extension
# changes ConfirmAccount CAPTCHA from SimpleCaptcha (trivial math) to hCaptcha
# update "Gadgets" extension from unknown version to unknown version
# update "OATHAuth" extension from version v0.2.2 (bed2e4b) to v0.5.0


==Points of Contact==
==Points of Contact==
Line 104: Line 125:
source /root/backups/backup.settings
source /root/backups/backup.settings
stamp=`date +%Y%m%d`
stamp=`date +%Y%m%d`
wgCaptchaSecret=$(cat /dev/random | strings | grep -oE '[A-Za-z0-9]' | perl -p -e 's/\n//g' | head -c 64)
backupDir_hetzner2="/var/tmp/backups_for_migration_to_hetzner3/${vhost_name}_${stamp}"
backupDir_hetzner2="/var/tmp/backups_for_migration_to_hetzner3/${vhost_name}_${stamp}"
backupDir_hetzner3="/var/tmp/backups_for_migration_from_hetzner2/${vhost_name}_${stamp}"
backupDir_hetzner3="/var/tmp/backups_for_migration_from_hetzner2/${vhost_name}_${stamp}"
Line 120: Line 142:


# extract .sql.bz2 -> .sql
# extract .sql.bz2 -> .sql
bzip2 -dc ${backupFileName_db_hetzner2} > db.sql
time nice bzip2 -dc ${backupFileName_db_hetzner2} > db.sql


  time nice mysql -uroot -p${mysqlPass} -sNe "DROP DATABASE IF EXISTS ${dbName};"  
  time nice mysql -uroot -p${mysqlPass} -sNe "DROP DATABASE IF EXISTS ${dbName};"  
Line 137: Line 159:
rsync -av --progress var/www/html/wiki.opensourceecology.org/htdocs/LocalSettings.php ${docrootDir}/
rsync -av --progress var/www/html/wiki.opensourceecology.org/htdocs/LocalSettings.php ${docrootDir}/
rsync -av --progress var/www/html/wiki.opensourceecology.org/htdocs/images ${docrootDir}/
rsync -av --progress var/www/html/wiki.opensourceecology.org/htdocs/images ${docrootDir}/
# backup LocalSettings.php
cp ${vhostDir}/LocalSettings.php ${vhostDir}/LocalSettings.$(date "+%Y%m%d_%H%M%S").php


# fix $wgNamespacesWithSubpages
# fix $wgNamespacesWithSubpages
sed -i 's%^\(\s*\)[^#]*$wgNamespacesWithSubpages\(.*\)%\1#$wgNamespacesWithSubpages\2%' LocalSettings.php
sed -i 's%^\(\s*\)[^#]*$wgNamespacesWithSubpages\(.*\)%\1#$wgNamespacesWithSubpages\2%' ${vhostDir}/LocalSettings.php


grep '$wgNamespacesWithSubpages = \[' LocalSettings.php || sed -i 's%^\(\s*\)#$wgNamespacesWithSubpages\[NS_IMAGE\]\(.*\)%\1#$wgNamespacesWithSubpages\[NS_IMAGE\]\2\n$wgNamespacesWithSubpages = [\n      NS_MAIN => true,\n      NS_TEMPLATE => true,\n      NS_CATEGORY => true,\n      NS_MEDIA => true,\n#      NS_IMAGE => true,\n];%' LocalSettings.php
grep '$wgNamespacesWithSubpages = \[' ${vhostDir}/LocalSettings.php || sed -i 's%^\(\s*\)#$wgNamespacesWithSubpages\[NS_IMAGE\]\(.*\)%\1#$wgNamespacesWithSubpages\[NS_IMAGE\]\2\n$wgNamespacesWithSubpages = [\n      NS_MAIN => true,\n      NS_TEMPLATE => true,\n      NS_CATEGORY => true,\n      NS_MEDIA => true,\n#      NS_IMAGE => true,\n];%' ${vhostDir}/LocalSettings.php


# deprecate require_once() for extensions (use wfLoadExtension() after upgrades instead)
# deprecate require_once() for extensions (use wfLoadExtension() after upgrades instead)
# * https://www.mediawiki.org/wiki/Manual:Upgrading#Upgrade_extensions
# * https://www.mediawiki.org/wiki/Manual:Upgrading#Upgrade_extensions
sed -i 's%^\(\s*\)[^#]*require_once\(.*\)/extensions/\(.*\)%\1#require_once\2/extensions/\3%' LocalSettings.php
sed -i 's%^\(\s*\)[^#]*require_once\(.*\)/extensions/\(.*\)%\1#require_once\2/extensions/\3%' ${vhostDir}/LocalSettings.php


# deprecate require_once() for skins (use wfLoadSkin() after upgrades instead)
# deprecate require_once() for skins (use wfLoadSkin() after upgrades instead)
# * https://www.mediawiki.org/wiki/Manual:Upgrading#Skin_registration
# * https://www.mediawiki.org/wiki/Manual:Upgrading#Skin_registration
sed -i 's%^\(\s*\)[^#]*require_once\(.*\)/skins/\(.*\)%\1#require_once\2/skins/\3%' LocalSettings.php
sed -i 's%^\(\s*\)[^#]*require_once\(.*\)/skins/\(.*\)%\1#require_once\2/skins/\3%' ${vhostDir}/LocalSettings.php


# UPDATE OLD EXTENSIONS
# remove require_once() for DefaultSettings.php, which was deprecated in v1.39
#  * https://www.mediawiki.org/w/index.php?title=Defaultsettings.php
sed -i 's%^\(\s*\)[^#]*require_once\(.*\)/DefaultSettings.php\(.*\)%\1#require_once\2/DefaultSettings.php\3%' ${vhostDir}/LocalSettings.php


# TODO
# add $wgExtensionDirectory (defaults to null in MediaWiki >= v1.37)
#  * https://www.mediawiki.org/wiki/Manual:$wgExtensionDirectory
grep '$wgExtensionDirectory' ${vhostDir}/LocalSettings.php || perl -0777 -pi -e 's/# EXTENSIONS #\n##############/# EXTENSIONS #\n##############\n\$wgExtensionDirectory = "\$IP\/extensions";/igs' ${vhostDir}/LocalSettings.php


# INSTALLL NEW EXTENSIONS
# don't yet load UserMerge (until after upgrades)
sed -i 's%^\(\s*\)[^#]*wfLoadExtension\(.*\)UserMerge\(.*\)%\1#wfLoadExtension\2UserMerge\3%' ${vhostDir}/LocalSettings.php


# TODO
# don't yet load Renameuser (until after upgrades)
sed -i 's%^\(\s*\)[^#]*wfLoadExtension\(.*\)Renameuser\(.*\)%\1#wfLoadExtension\2Renameuser\3%' ${vhostDir}/LocalSettings.php


# SET PERMISSIONS
# don't yet load ConfirmEdit (until after upgrades)
sed -i 's%^\(\s*\)[^#]*wfLoadExtensions\(.*\)ConfirmEdit\(.*\)%\1#wfLoadExtensions\2ConfirmEdit\3%' ${vhostDir}/LocalSettings.php


# first pass, whole site
# uncomment wgServer (now defaults to 'false') https://www.mediawiki.org/wiki/Manual:$wgServer#Default_value
chown -R not-apache:www-data "/var/www/html"
sed -i 's%^\(\s*\)#$wgServer\(.*\)%\1$wgServer\2%' ${vhostDir}/LocalSettings.php
find "/var/www/html" -type d -exec chmod 0050 {} \;
find "/var/www/html" -type f -exec chmod 0040 {} \;


#############
# fix $wgServer
# WORDPRESS #
grep '#$wgServer' ${vhostDir}/LocalSettings.php || perl -0777 -pi -e 's%\$wgServer = "http://opensourceecology.org";
#############
%#\$wgServer = "http://opensourceecology.org";\n\$wgServer = "https://wiki.opensourceecology.org";\n%igs' ${vhostDir}/LocalSettings.php


wordpress_sites="$(find /var/www/html -type d -wholename *htdocs/wp-content)"
# fix MediaWiki bugs
grep 'ini_set' ${vhostDir}/LocalSettings.php || sed -i 's%^<?php%<?php\n# fix mediawiki bugs\n# * https://phabricator.wikimedia.org/T385965\nif( ! function_exists("ini_set") ){\n\tfunction ini_set(){\n\t\treturn;\n\t}\n}\nif( ! function_exists("putenv") ){\n\tfunction putenv(){\n\t\treturn;\n\t}\n}\nif( ! function_exists("php_uname") ){\n\tfunction php_uname(){\n\t\treturn;\n\t}\n}\nif( ! function_exists("set_time_limit") ){\n\tfunction set_time_limit(){\n\t\treturn;\n\t}\n}\nif( ! function_exists("chmod") ){\n\tfunction chmod(){\n\t\treturn;\n\t}\n}\n%' ${vhostDir}/LocalSettings.php


for wordpress_site in $wordpress_sites; do
# FIX PERMISSIONS
time /usr/local/bin/fix_web_permissions.sh


wp_docroot="$(dirname "${wordpress_site}")"
# UPGRADE MEDIAWIKI TO v1.35.0
vhost_dir="$(dirname "${wp_docroot}")"
time nice sudo -u www-data php "${docrootDir}/maintenance/update.php" &> ${chg_dir}/update-to-v1.35.log
 
time nice sudo -u www-data php "${docrootDir}/maintenance/populateContentTables.php" &> ${chg_dir}/populateContentTables-to-v1.35.log
chown -R not-apache:www-data "${vhost_dir}"
time nice sudo -u www-data php "${docrootDir}/maintenance/update.php" &> ${chg_dir}/update-to-v1.35b.log
find "${vhost_dir}" -type d -exec chmod 0050 {} \;
find "${vhost_dir}" -type f -exec chmod 0040 {} \;
 
chown not-apache:apache-admins "${vhost_dir}/wp-config.php"
chmod 0040 "${vhost_dir}/wp-config.php"
 
[ -d "${wp_docroot}/wp-content/uploads" ] || mkdir "${wp_docroot}/wp-content/uploads"
chown -R not-apache:www-data "${wp_docroot}/wp-content/uploads"
find "${wp_docroot}/wp-content/uploads" -type f -exec chmod 0660 {} \;
find "${wp_docroot}/wp-content/uploads" -type d -exec chmod 0770 {} \;
 
[ -d "${wp_docroot}/wp-content/tmp" ] || mkdir "${wp_docroot}/wp-content/tmp"
chown -R not-apache:www-data "${wp_docroot}/wp-content/tmp"
find "${wp_docroot}/wp-content/tmp" -type f -exec chmod 0660 {} \;
find "${wp_docroot}/wp-content/tmp" -type d -exec chmod 0770 {} \;
 
done
 
###########
# phpList #
###########
 
phplist_sites="$(find /var/www/html -maxdepth 1 -type d -iname *phplist*)"
 
for vhost_dir in $phplist_sites; do
for dir in ${vhost_dir}; do chown -R not-apache:www-data "${dir}"; done
for dir in ${vhost_dir}; do find "${dir}" -type d -exec chmod 0050 {} \;; done
for dir in ${vhost_dir}; do find "${dir}" -type f -exec chmod 0040 {} \;; done
for dir in ${vhost_dir}; do [ -d "${dir}/public_html/uploadimages" ] || mkdir "${dir}/public_html/uploadimages"; done
for dir in ${vhost_dir}; do chown -R not-apache:www-data "${dir}/public_html/uploadimages"; done
for dir in ${vhost_dir}; do find "${dir}/public_html/uploadimages" -type f -exec chmod 0660 {} \;; done
for dir in ${vhost_dir}; do find "${dir}/public_html/uploadimages" -type d -exec chmod 0770 {} \;; done
 
done
 
#############
# MediaWiki #
#############
 
vhost_dir="/var/www/html/wiki.opensourceecology.org"
mw_docroot="${vhost_dir}/htdocs"
 
chown -R not-apache:www-data "${vhost_dir}"
find "${vhost_dir}" -type d -exec chmod 0050 {} \;
find "${vhost_dir}" -type f -exec chmod 0040 {} \;
 
chown not-apache:apache-admins "${vhost_dir}/LocalSettings.php"
chmod 0040 "${vhost_dir}/LocalSettings.php"
 
[ -d "${mw_docroot}/images" ] || mkdir "${mw_docroot}/images"
chown -R www-data:www-data "${mw_docroot}/images"
find "${mw_docroot}/images" -type f -exec chmod 0660 {} \;
find "${mw_docroot}/images" -type d -exec chmod 0770 {} \;
 
[ -d "${vhost_dir}/cache" ] || mkdir "${vhost_dir}/cache"
chown -R www-data:www-data "${vhost_dir}/cache"
find "${vhost_dir}/cache" -type f -exec chmod 0660 {} \;
find "${vhost_dir}/cache" -type d -exec chmod 0770 {} \;


# UPGRADE MEDIAWIKI TO v1.35.0
# clear varnish cache (before verify step below)
sudo -u www-data php "${docrootDir}/maintenance/update.php"
varnishadm 'ban req.http.host ~ "wiki.opensourceecology.org"'
sudo -u www-data php "${docrootDir}/maintenance/populateContentTables.php"


# verify by loading:
# verify by loading:
Line 247: Line 218:
# * https://wiki.opensourceecology.org/wiki/Special:Version
# * https://wiki.opensourceecology.org/wiki/Special:Version
#
#
# make sure the MediaWiki version speciried is v1.35.0
# make sure the MediaWiki version specified is v1.35.0


# UPGRADE MEDIAWIKI TO v1.43.0
# UPGRADE MEDIAWIKI TO v1.43.0
Line 260: Line 231:
rsync -av --progress /var/tmp/mediawiki/mediawiki-1.43.0/ ${docrootDir}/
rsync -av --progress /var/tmp/mediawiki/mediawiki-1.43.0/ ${docrootDir}/


rsync -av --progress ${vhost_backup_path}/LocalSettings.php ${vhostDir}/
rsync -av --progress ${vhost_backup_path}/LocalSettings.php* ${vhostDir}/
rsync -av --progress ${vhost_backup_path}/htdocs/LocalSettings.php ${docrootDir}/
rsync -av --progress ${vhost_backup_path}/htdocs/LocalSettings.php ${docrootDir}/
rsync -av --progress ${vhost_backup_path}/htdocs/images ${docrootDir}/
rsync -av --progress ${vhost_backup_path}/htdocs/images ${docrootDir}/
# backup LocalSettings.php
cp ${vhostDir}/LocalSettings.php ${vhostDir}/LocalSettings.$(date "+%Y%m%d_%H%M%S").php


# TODO: idempotent commands to update LocalSettings.php
# TODO: idempotent commands to update LocalSettings.php


# SET PERMISSIONS
# fix OATHAuth extension failure that breaks upgrade (Error 1146: Table "wiki_oathauth_types" doesn't exist)
#  * https://www.mediawiki.org/wiki/Topic:T24w7s9asgty7vxp
cat $docrootDir/extensions/OATHAuth/sql/sqlite/tables-generated.sql | sed 's/AUTOINCREMENT/AUTO_INCREMENT/g' | sed 's%/\*_\*/%wiki_%g' | mysql -u $dbUser -p${dbPass} $dbName
 
# FIX PERMISSIONS
time /usr/local/bin/fix_web_permissions.sh
 
# RUN UPGRADE
time nice sudo -u www-data php "${docrootDir}/maintenance/run.php" "${docrootDir}/maintenance/update.php" &> ${chg_dir}/update-to-v1.43.log
 
# clear varnish cache (before verify step below)
varnishadm 'ban req.http.host ~ "wiki.opensourceecology.org"'
 
# verify by loading:
#
# * https://wiki.opensourceecology.org/wiki/Special:Version
#
# make sure the MediaWiki version speciried is v1.43.0
 
# UPDATE SKINS


# first pass, whole site
rsync -av --progress /var/tmp/mediawiki/themes/CologneBlue ${docrootDir}/skins/
chown -R not-apache:www-data "/var/www/html"
rsync -av --progress /var/tmp/mediawiki/themes/Modern ${docrootDir}/skins/
find "/var/www/html" -type d -exec chmod 0050 {} \;
find "/var/www/html" -type f -exec chmod 0040 {} \;


#############
# UPDATE EXTENSIONS
# WORDPRESS #
#############


wordpress_sites="$(find /var/www/html -type d -wholename *htdocs/wp-content)"
extensions="ConfirmAccount UserMerge Widgets DeleteBatch SmiteSpam"


for wordpress_site in $wordpress_sites; do
for extension in ${extensions}; do
        extension_path="${docrootDir}/extensions/${extension}"
        source_path="/var/tmp/mediawiki/extensions/${extension}"
       
        if [ -d "${source_path}" ]; then
                echo "${extension}"
                rsync -a ${source_path}/ "${extension_path}/"
        fi
done


wp_docroot="$(dirname "${wordpress_site}")"
# enable new extensions: SmiteSpam & DeleteBatch
vhost_dir="$(dirname "${wp_docroot}")"
grep 'SmiteSpam' ${vhostDir}/LocalSettings.php || perl -0777 -pi -e "s%wfLoadExtension\( 'Nuke' \);%wfLoadExtension( 'Nuke' );\nwfLoadExtension( 'SmiteSpam' );\nwfLoadExtension( 'DeleteBatch' );%igs" ${vhostDir}/LocalSettings.php


chown -R not-apache:www-data "${vhost_dir}"
# add skins (with wfLoadSkin() instead of require_once)
find "${vhost_dir}" -type d -exec chmod 0050 {} \;
grep 'wfSkinLoad' ${vhostDir}/LocalSettings.php || perl -0777 -pi -e "s/$wgDefaultSkin = 'Vector';/\$wgDefaultSkin = 'Vector';\n\nwfLoadSkin( 'CologneBlue' );\nwfLoadSkin( 'Modern' );\nwfLoadSkin( 'MonoBook' );\nwfLoadSkin( 'Vector' );/igs" ${vhostDir}/LocalSettings.php
find "${vhost_dir}" -type f -exec chmod 0040 {} \;


chown not-apache:apache-admins "${vhost_dir}/wp-config.php"
# re-enable CategoryTree extension
chmod 0040 "${vhost_dir}/wp-config.php"
grep 'wfLoadExtension.*CategoryTree' ${vhostDir}/LocalSettings.php || perl -0777 -pi -e 's%#require_once\("{\$IP}/extensions/CategoryTree/CategoryTree.php"\);%#require_once("{$IP}/extensions/CategoryTree/CategoryTree.php");\n\nwfLoadExtension( "CategoryTree" );\n%igs' ${vhostDir}/LocalSettings.php


[ -d "${wp_docroot}/wp-content/uploads" ] || mkdir "${wp_docroot}/wp-content/uploads"
# re-enable ConfirmEdit and switch to FancyCaption
chown -R not-apache:www-data "${wp_docroot}/wp-content/uploads"
grep 'FancyCaptcha' ${vhostDir}/LocalSettings.php || perl -0777 -pi -e "s%\\\$wgCaptchaClass = 'SimpleCaptcha';%\#\\\$wgCaptchaClass = 'SimpleCaptcha';\n\nwfLoadExtensions([ 'ConfirmEdit', 'ConfirmEdit/FancyCaptcha' ]);\n\\\$wgCaptchaDirectory = '/var/www/html/wiki.opensourceecology.org/htdocs/images/captcha/';\n\\\$wgCaptchaSecret = '$wgCaptchaSecret';\n%igs" ${vhostDir}/LocalSettings.php
find "${wp_docroot}/wp-content/uploads" -type f -exec chmod 0660 {} \;
find "${wp_docroot}/wp-content/uploads" -type d -exec chmod 0770 {} \;


[ -d "${wp_docroot}/wp-content/tmp" ] || mkdir "${wp_docroot}/wp-content/tmp"
# update cron script to use new secret
chown -R not-apache:www-data "${wp_docroot}/wp-content/tmp"
cp /usr/local/bin/mediawiki_generate_captchas.sh /usr/local/bin/mediawiki_generate_captchas.sh.$(date "+%Y%m%d_%H%M%S")
find "${wp_docroot}/wp-content/tmp" -type f -exec chmod 0660 {} \;
sed -ie "s%CAPTCHA_SECRET='\([^']*\)'%\CAPTCHA_SECRET='$wgCaptchaSecret'%" /usr/local/bin/mediawiki_generate_captchas.sh
find "${wp_docroot}/wp-content/tmp" -type d -exec chmod 0770 {} \;


done
# re-enable ConfirmAccount extension
grep 'wfLoadExtension.*ConfirmAccount' ${vhostDir}/LocalSettings.php || perl -0777 -pi -e 's%#require_once "\$IP/extensions/ConfirmAccount/ConfirmAccount.php";%#require_once "$IP/extensions/ConfirmAccount/ConfirmAccount.php";\n\nwfLoadExtension( "ConfirmAccount" );\n%igs' ${vhostDir}/LocalSettings.php


###########
# re-enable UserMerge extension
# phpList #
sed -i 's%^\(\s*\)#wfLoadExtension\(.*\)UserMerge\(.*\)%\1wfLoadExtension\2UserMerge\3%' ${vhostDir}/LocalSettings.php
###########


phplist_sites="$(find /var/www/html -maxdepth 1 -type d -iname *phplist*)"
# re-enable Widgets extension
grep 'wfLoadExtension.*Widgets' ${vhostDir}/LocalSettings.php || perl -0777 -pi -e 's%#require_once\("\$IP/extensions/Widgets/Widgets.php"\);%#require_once("$IP/extensions/Widgets/Widgets.php");\n\nwfLoadExtension( "Widgets" );\n%igs' ${vhostDir}/LocalSettings.php


for vhost_dir in $phplist_sites; do
# re-enable ParserFunctions extension
grep 'wfLoadExtension.*ParserFunctions' ${vhostDir}/LocalSettings.php || perl -0777 -pi -e 's%#require_once\( "\$IP/extensions/ParserFunctions/ParserFunctions.php" \);%#require_once( "$IP/extensions/ParserFunctions/ParserFunctions.php" );\n\nwfLoadExtension( "ParserFunctions" );\n%igs' ${vhostDir}/LocalSettings.php
for dir in ${vhost_dir}; do chown -R not-apache:www-data "${dir}"; done
for dir in ${vhost_dir}; do find "${dir}" -type d -exec chmod 0050 {} \;; done
for dir in ${vhost_dir}; do find "${dir}" -type f -exec chmod 0040 {} \;; done
for dir in ${vhost_dir}; do [ -d "${dir}/public_html/uploadimages" ] || mkdir "${dir}/public_html/uploadimages"; done
for dir in ${vhost_dir}; do chown -R not-apache:www-data "${dir}/public_html/uploadimages"; done
for dir in ${vhost_dir}; do find "${dir}/public_html/uploadimages" -type f -exec chmod 0660 {} \;; done
for dir in ${vhost_dir}; do find "${dir}/public_html/uploadimages" -type d -exec chmod 0770 {} \;; done


done
# remove deprecated password policy and add new https://www.mediawiki.org/wiki/Manual:$wgPasswordPolicy
grep 'PasswordNotInCommonList' ${vhostDir}/LocalSettings.php || perl -0777 -pi -e "s%\\\$wgPasswordPolicy\['policies'\]\['default'\]\['PasswordCannotBePopular'\] = PHP_INT_MAX;\n\\\$wgPasswordPolicy\['policies'\]\['default'\]\['PasswordCannotMatchUsername'\] = true;%#\\\$wgPasswordPolicy['policies']['default']['PasswordCannotBePopular'] = PHP_INT_MAX;\n#\\\$wgPasswordPolicy['policies']['default']['PasswordCannotMatchUsername'] = true;\n\\\$wgPasswordPolicy['policies']['default']['PasswordNotInCommonList'] = true;\n\\\$wgPasswordPolicy['policies']['default']['PasswordCannotBeSubstringInUsername'] = true;%igs" ${vhostDir}/LocalSettings.php


#############
# configure OATH (2FA) requirements
# MediaWiki #
grep 'wgOATHAuthWindowRadius' ${vhostDir}/LocalSettings.php || perl -0777 -pi -e "s%wfLoadExtension\( 'OATHAuth' \);%wfLoadExtension( 'OATHAuth' );\n\n# Relaxed mode with +/- 4 minutes time drift tolerance. This is important or users will complain and/or disable 2FA entirely\n# The security consequences are small. The usability benefits are huge.\n\\\$wgOATHAuthWindowRadius = 8;\n\n# make admins require 2FA\n\\\$wgOATHRequiredForGroups = ['sysop', 'interface-admin', 'bureaucrat', 'suppress', 'widgeteditor' ];\n\n# make 'powerful' rights require 2FA\n\\\$wgOATHExclusiveRights =  [ 'apihighlimits', 'applychangetags', 'autoconfirmed', 'autopatrol', 'bigdelete', 'block', 'blockemail', 'bot', 'changetags', 'createaccount', 'createtalk', 'delete', 'deletechangetags', 'deletedhistory', 'deletedtext', 'deletelogentry', 'deleterevision', 'editcontentmodel', 'editinterface', 'editprotected', 'editsemiprotected', 'editsitecss', 'editsitejs', 'editsitejson', 'editusercss', 'edituserjs', 'edituserjson', 'hideuser', 'import', 'importupload', 'ipblock-exempt', 'managechangetags', 'markbotedits', 'mergehistory', 'move-categorypages', 'move-rootuserpages', 'move-subpages', 'nominornewtalk', 'noratelimit', 'patrol', 'protect', 'renameuser', 'reupload-shared', 'sendemail', 'suppressionlog', 'suppressredirect', 'suppressrevision', 'unblockself', 'unwatchedpages', 'userrights', ];\n\n# full list for reference (taken from htdocs/includes/MainConfigSchema.php) https://www.mediawiki.org/wiki/Extension:OATHAuth#Configuration\n#\\\$wgOATHExclusiveRights =  [ 'apihighlimits', 'applychangetags', 'autoconfirmed', 'autopatrol', 'bigdelete', 'block', 'blockemail', 'bot', 'browsearchive', 'changetags', 'createaccount', 'createpage', 'createtalk', 'delete', 'deletechangetags', 'deletedhistory', 'deletedtext', 'deletelogentry', 'deleterevision', 'edit', 'editcontentmodel', 'editinterface', 'editmyoptions', 'editmyprivateinfo', 'editmyusercss', 'editmyuserjs', 'editmyuserjson', 'editmyuserjsredirect', 'editmywatchlist', 'editprotected', 'editsemiprotected', 'editsitecss', 'editsitejs', 'editsitejson', 'editusercss', 'edituserjs', 'edituserjson', 'hideuser', 'import', 'importupload', 'ipblock-exempt', 'managechangetags', 'markbotedits', 'mergehistory', 'minoredit', 'move', 'move-categorypages', 'movefile', 'move-rootuserpages', 'move-subpages', 'nominornewtalk', 'noratelimit', 'patrol', 'protect', 'read', 'renameuser', 'reupload', 'reupload-shared', 'rollback', 'sendemail', 'suppressionlog', 'suppressredirect', 'suppressrevision', 'unblockself', 'undelete', 'unwatchedpages', 'upload', 'userrights', 'viewmyprivateinfo', 'viewmywatchlist', 'viewsuppressed' ];\n%igs" ${vhostDir}/LocalSettings.php
#############


vhost_dir="/var/www/html/wiki.opensourceecology.org"
# FIX PERMISSIONS
mw_docroot="${vhost_dir}/htdocs"
time /usr/local/bin/fix_web_permissions.sh


chown -R not-apache:www-data "${vhost_dir}"
# clear varnish cache again
find "${vhost_dir}" -type d -exec chmod 0050 {} \;
varnishadm 'ban req.http.host ~ "wiki.opensourceecology.org"'
find "${vhost_dir}" -type f -exec chmod 0040 {} \;


chown not-apache:apache-admins "${vhost_dir}/LocalSettings.php"
# log into the new MediaWiki site, and update settings:
chmod 0040 "${vhost_dir}/LocalSettings.php"


[ -d "${mw_docroot}/images" ] || mkdir "${mw_docroot}/images"
# Create a new account (Called 'CatarinaAdmin') and add it to sysop group
chown -R www-data:www-data "${mw_docroot}/images"
find "${mw_docroot}/images" -type f -exec chmod 0660 {} \;
find "${mw_docroot}/images" -type d -exec chmod 0770 {} \;


[ -d "${vhost_dir}/cache" ] || mkdir "${vhost_dir}/cache"
# Remove the following accounts from the sysop group
chown -R www-data:www-data "${vhost_dir}/cache"
## Audrey Rampone
find "${vhost_dir}/cache" -type f -exec chmod 0660 {} \;
## Elifarley
find "${vhost_dir}/cache" -type d -exec chmod 0770 {} \;
## Hart
## Will


# RUN UPGRADE
# TODO: Enforce 2FA for all admin accounts
sudo -u www-data php "${docrootDir}/maintenance/run.php" "${docrootDir}/maintenance/update.php"
</pre>
</pre>


Line 356: Line 337:
while true; do date; dig store.opensourceecology.org; sleep 10; echo; done
while true; do date; dig store.opensourceecology.org; sleep 10; echo; done
</pre>
</pre>
Finally, log into the new MediaWiki site, and update settings:
# TODO: Enforce 2FA for all admin accounts


==Validation Steps==
==Validation Steps==

Latest revision as of 21:57, 17 March 2025

Status

2024-12-29 11:06 UTC

Initial Ticket draft created on wiki (WIP)

Change Info

Scheduled Time

This change will take place on 2025-??-?? ??:00 UTC

  • = 2025-??-?? ??:00 Kansas City, US
  • = 2025-??-?? ??:00 Guayaquil, EC

https://www.timeanddate.com/worldclock/converter.html?iso=20240727T160000&p1=405&p2=1440&p3=93

Purpose

This change does the following for wiki.opensourceecology.org

  1. entirely migrate the OSE MediaWiki site from hetzner2 (EOL CentOS7) to hetzner3 (Debian 12)
  2. changes site from apache v2.4.6 to v2.4.62
  3. changes site from varnish v4.0.5 to v7.1.1
  4. changes site from nginx v1.20.1 to v1.22.1
  5. changes site from php v5.6 to v8.2.26
  6. changes site from using mod_php to php-fpm
  7. changes site from mariadb v5.5.68 to v10.11.6
  8. update ICU from v50.1.2
  9. update core MediaWiki from v1.30.0 to v1.43.0
  1. update "Cologne Blue" skin from unknown version to 9134d2e
  2. update "Modern" skin from unknown version to 5597681
  3. update "MonoBook" skin from unknown version to unknown version
  4. update "Vector" skin from unknown version to v1.0.0
  1. update "Confirm User Accounts" extension from version 4fe25f7 to bb470fd
  2. update "Interwiki" extension from version v3.1 20160307 to v3.2
  3. update "Nuke" extension from version 1.3.0 to unknown version
  4. update "Replace Text" extension from version v1.2 (4426752) to v1.8
  5. update "UserMerge" extension from version 1.10.1 (4546537) to v1.10.2 (f9d2664)
  6. update "CategoryTree" extension from version 850c018 to unknown version
  7. update "Cite" extension from unknown version to unknown version
  8. update "ParserFunctions" extension from v1.6.0 to v1.6.1
  9. update "Widgets" extension from version v1.3.0 (fce5acc) to v1.6.0 (50da5c6)
  10. update "ConfirmEdit" extension from v1.5.0 to v1.6.0
  11. install "hCaptcha" extension (unknown version)
  12. uninstall "reCaptcha" extension
  13. changes ConfirmAccount CAPTCHA from SimpleCaptcha (trivial math) to hCaptcha
  14. update "Gadgets" extension from unknown version to unknown version
  15. update "OATHAuth" extension from version v0.2.2 (bed2e4b) to v0.5.0

Points of Contact

Change being performed by: Michael Altfield

Service owners: Marcin Jakubowski

Time Length

This whole process is expected to take 6-24 hours.

Some systems could be impacted for days, if issues are encountered.

Systems Impacted

This change impacts both hetzner2 and hetzner3. It's possible that we'll need to restart one or both of these servers during this migration, which could affect the availability of all OSE & OBI websites.

Staging Test

n/a

Change Steps


# TODO: actually verify these commands

####################
# run on hetzner2 #
####################

sudo su -

# DECLARE VARIABLES
vhost_name='wiki.opensourceecology.org'
dbName='osewiki_db'
 dbUser="CHANGEME"
 dbPass="CHANGEME"

source /root/backups/backup.settings
stamp=`date +%Y%m%d`
backupDir_hetzner2="/var/tmp/backups_for_migration_to_hetzner2/${vhost_name}_${stamp}"
backupDir_hetzner3="/var/tmp/backups_for_migration_from_hetzner2/${vhost_name}_${stamp}"
backupFileName_db_hetzner2="mysqldump_${vhost_name}.${stamp}.sql.bz2"
backupFileName_files_hetzner2="${vhost_name}_files.${stamp}.tar.gz"
vhostDir="/var/www/html/${vhost_name}"

# STEP 2: BACKUP DB
mkdir -p ${backupDir_hetzner2}/{current,old}
pushd ${backupDir_hetzner2}/current/
mv ${backupDir_hetzner2}/current/* ${backupDir_hetzner2}/old/

time nice mysqldump -u"${dbUser}" -p"${dbPass}" ${dbName} | bzip2 -c > ${backupDir_hetzner2}/current/${backupFileName_db_hetzner2}

# STEP 3: BACKUP FILES
time nice tar -czvf ${backupDir_hetzner2}/current/${backupFileName_files_hetzner2} ${vhostDir}

# STEP 4: COPY TO HETZNER3
ssh -p 32415 maltfield@hetzner3 sudo mkdir -p ${backupDir_hetzner3}/{current,old}
ssh -p 32415 maltfield@hetzner3 sudo mv ${backupDir_hetzner3}/current/* ${backupDir_hetzner3}/old/
rsync -av --progress --rsync-path="sudo rsync" -e "ssh -p 32415" ${backupDir_hetzner2}/current/* maltfield@hetzner3:${backupDir_hetzner3}/current/

####################
# run on hetzner3 #
####################

sudo su -

# DECLARE VARIABLES
vhost_name='wiki.opensourceecology.org'
dbName='osewiki_db'
 dbUser="CHANGEME"
 dbPass="CHANGEME"

source /root/backups/backup.settings
stamp=`date +%Y%m%d`
wgCaptchaSecret=$(cat /dev/random | strings | grep -oE '[A-Za-z0-9]' | perl -p -e 's/\n//g' | head -c 64)
backupDir_hetzner2="/var/tmp/backups_for_migration_to_hetzner3/${vhost_name}_${stamp}"
backupDir_hetzner3="/var/tmp/backups_for_migration_from_hetzner2/${vhost_name}_${stamp}"
backupFileName_db_hetzner2="mysqldump_${vhost_name}.${stamp}.sql.bz2"
backupFileName_files_hetzner2="${vhost_name}_files.${stamp}.tar.gz"
vhostDir="/var/www/html/${vhost_name}"
docrootDir="${vhostDir}/htdocs"
chg_dir="/var/tmp/CHG_${stamp}_wiki_1.30-to-1.35"
mkdir -p ${chg_dir}/{pre,post}

# STEP 1: ADD DB

# create backup before we start changing the sql file
pushd ${backupDir_hetzner3}/current
cp ${backupFileName_db_hetzner2} ${backupFileName_db_hetzner2}.orig

# extract .sql.bz2 -> .sql
time nice bzip2 -dc ${backupFileName_db_hetzner2} > db.sql

 time nice mysql -uroot -p${mysqlPass} -sNe "DROP DATABASE IF EXISTS ${dbName};" 
 time nice mysql -uroot -p${mysqlPass} -sNe "CREATE DATABASE ${dbName}; USE ${dbName};"
 time nice mysql ${dbName} -uroot -p${mysqlPass} < "db.sql"
 time nice mysql -uroot -p${mysqlPass} -sNe "GRANT ALL ON ${dbName}.* TO '${dbUser}'@'localhost' IDENTIFIED BY '${dbPass}'; FLUSH PRIVILEGES;"

# STEP 2: Add vhost files
mv "${vhostDir}" "${chg_dir}/pre/${vhost_name}.$(date "+%Y%m%d_%H%M%S")"
tar -xzvf ${backupFileName_files_hetzner2}

mkdir -p ${vhostDir}
rsync -av --progress /var/tmp/mediawiki/mediawiki-1.35.0/ ${docrootDir}/

rsync -av --progress var/www/html/wiki.opensourceecology.org/LocalSettings.php ${vhostDir}/
rsync -av --progress var/www/html/wiki.opensourceecology.org/htdocs/LocalSettings.php ${docrootDir}/
rsync -av --progress var/www/html/wiki.opensourceecology.org/htdocs/images ${docrootDir}/

# backup LocalSettings.php
cp ${vhostDir}/LocalSettings.php ${vhostDir}/LocalSettings.$(date "+%Y%m%d_%H%M%S").php

# fix $wgNamespacesWithSubpages
sed -i 's%^\(\s*\)[^#]*$wgNamespacesWithSubpages\(.*\)%\1#$wgNamespacesWithSubpages\2%' ${vhostDir}/LocalSettings.php

grep '$wgNamespacesWithSubpages = \[' ${vhostDir}/LocalSettings.php || sed -i 's%^\(\s*\)#$wgNamespacesWithSubpages\[NS_IMAGE\]\(.*\)%\1#$wgNamespacesWithSubpages\[NS_IMAGE\]\2\n$wgNamespacesWithSubpages = [\n      NS_MAIN => true,\n      NS_TEMPLATE => true,\n      NS_CATEGORY => true,\n      NS_MEDIA => true,\n#      NS_IMAGE => true,\n];%' ${vhostDir}/LocalSettings.php

# deprecate require_once() for extensions (use wfLoadExtension() after upgrades instead)
# * https://www.mediawiki.org/wiki/Manual:Upgrading#Upgrade_extensions
sed -i 's%^\(\s*\)[^#]*require_once\(.*\)/extensions/\(.*\)%\1#require_once\2/extensions/\3%' ${vhostDir}/LocalSettings.php

# deprecate require_once() for skins (use wfLoadSkin() after upgrades instead)
# * https://www.mediawiki.org/wiki/Manual:Upgrading#Skin_registration
sed -i 's%^\(\s*\)[^#]*require_once\(.*\)/skins/\(.*\)%\1#require_once\2/skins/\3%' ${vhostDir}/LocalSettings.php

# remove require_once() for DefaultSettings.php, which was deprecated in v1.39
#  * https://www.mediawiki.org/w/index.php?title=Defaultsettings.php
sed -i 's%^\(\s*\)[^#]*require_once\(.*\)/DefaultSettings.php\(.*\)%\1#require_once\2/DefaultSettings.php\3%' ${vhostDir}/LocalSettings.php

# add $wgExtensionDirectory (defaults to null in MediaWiki >= v1.37)
#  * https://www.mediawiki.org/wiki/Manual:$wgExtensionDirectory
grep '$wgExtensionDirectory' ${vhostDir}/LocalSettings.php || perl -0777 -pi -e 's/# EXTENSIONS #\n##############/# EXTENSIONS #\n##############\n\$wgExtensionDirectory = "\$IP\/extensions";/igs' ${vhostDir}/LocalSettings.php

# don't yet load UserMerge (until after upgrades)
sed -i 's%^\(\s*\)[^#]*wfLoadExtension\(.*\)UserMerge\(.*\)%\1#wfLoadExtension\2UserMerge\3%' ${vhostDir}/LocalSettings.php

# don't yet load Renameuser (until after upgrades)
sed -i 's%^\(\s*\)[^#]*wfLoadExtension\(.*\)Renameuser\(.*\)%\1#wfLoadExtension\2Renameuser\3%' ${vhostDir}/LocalSettings.php

# don't yet load ConfirmEdit (until after upgrades)
sed -i 's%^\(\s*\)[^#]*wfLoadExtensions\(.*\)ConfirmEdit\(.*\)%\1#wfLoadExtensions\2ConfirmEdit\3%' ${vhostDir}/LocalSettings.php

# uncomment wgServer (now defaults to 'false') https://www.mediawiki.org/wiki/Manual:$wgServer#Default_value
sed -i 's%^\(\s*\)#$wgServer\(.*\)%\1$wgServer\2%' ${vhostDir}/LocalSettings.php

# fix $wgServer
grep '#$wgServer' ${vhostDir}/LocalSettings.php || perl -0777 -pi -e 's%\$wgServer = "http://opensourceecology.org";
%#\$wgServer = "http://opensourceecology.org";\n\$wgServer = "https://wiki.opensourceecology.org";\n%igs' ${vhostDir}/LocalSettings.php

# fix MediaWiki bugs
grep 'ini_set' ${vhostDir}/LocalSettings.php || sed -i 's%^<?php%<?php\n# fix mediawiki bugs\n# * https://phabricator.wikimedia.org/T385965\nif( ! function_exists("ini_set") ){\n\tfunction ini_set(){\n\t\treturn;\n\t}\n}\nif( ! function_exists("putenv") ){\n\tfunction putenv(){\n\t\treturn;\n\t}\n}\nif( ! function_exists("php_uname") ){\n\tfunction php_uname(){\n\t\treturn;\n\t}\n}\nif( ! function_exists("set_time_limit") ){\n\tfunction set_time_limit(){\n\t\treturn;\n\t}\n}\nif( ! function_exists("chmod") ){\n\tfunction chmod(){\n\t\treturn;\n\t}\n}\n%' ${vhostDir}/LocalSettings.php

# FIX PERMISSIONS
time /usr/local/bin/fix_web_permissions.sh

# UPGRADE MEDIAWIKI TO v1.35.0
time nice sudo -u www-data php "${docrootDir}/maintenance/update.php" &> ${chg_dir}/update-to-v1.35.log
time nice sudo -u www-data php "${docrootDir}/maintenance/populateContentTables.php" &> ${chg_dir}/populateContentTables-to-v1.35.log
time nice sudo -u www-data php "${docrootDir}/maintenance/update.php" &> ${chg_dir}/update-to-v1.35b.log

# clear varnish cache (before verify step below)
varnishadm 'ban req.http.host ~ "wiki.opensourceecology.org"'

# verify by loading:
#
# * https://wiki.opensourceecology.org/wiki/Special:Version
#
# make sure the MediaWiki version specified is v1.35.0

# UPGRADE MEDIAWIKI TO v1.43.0
chg_dir="/var/tmp/CHG_${stamp}_wiki_1.35-to-1.43"
mkdir -p ${chg_dir}/{pre,post}

# Add vhost files
vhost_backup_path="${chg_dir}/pre/${vhost_name}.${stamp}"
mv "${vhostDir}" "${vhost_backup_path}"

mkdir -p ${vhostDir}
rsync -av --progress /var/tmp/mediawiki/mediawiki-1.43.0/ ${docrootDir}/

rsync -av --progress ${vhost_backup_path}/LocalSettings.php* ${vhostDir}/
rsync -av --progress ${vhost_backup_path}/htdocs/LocalSettings.php ${docrootDir}/
rsync -av --progress ${vhost_backup_path}/htdocs/images ${docrootDir}/

# backup LocalSettings.php
cp ${vhostDir}/LocalSettings.php ${vhostDir}/LocalSettings.$(date "+%Y%m%d_%H%M%S").php

# TODO: idempotent commands to update LocalSettings.php

# fix OATHAuth extension failure that breaks upgrade (Error 1146: Table "wiki_oathauth_types" doesn't exist)
#  * https://www.mediawiki.org/wiki/Topic:T24w7s9asgty7vxp
cat $docrootDir/extensions/OATHAuth/sql/sqlite/tables-generated.sql | sed 's/AUTOINCREMENT/AUTO_INCREMENT/g' | sed 's%/\*_\*/%wiki_%g' | mysql -u $dbUser -p${dbPass} $dbName

# FIX PERMISSIONS
time /usr/local/bin/fix_web_permissions.sh

# RUN UPGRADE
time nice sudo -u www-data php "${docrootDir}/maintenance/run.php" "${docrootDir}/maintenance/update.php" &> ${chg_dir}/update-to-v1.43.log

# clear varnish cache (before verify step below)
varnishadm 'ban req.http.host ~ "wiki.opensourceecology.org"'

# verify by loading:
#
# * https://wiki.opensourceecology.org/wiki/Special:Version
#
# make sure the MediaWiki version speciried is v1.43.0

# UPDATE SKINS

rsync -av --progress /var/tmp/mediawiki/themes/CologneBlue ${docrootDir}/skins/
rsync -av --progress /var/tmp/mediawiki/themes/Modern ${docrootDir}/skins/

# UPDATE EXTENSIONS

extensions="ConfirmAccount UserMerge Widgets DeleteBatch SmiteSpam"

for extension in ${extensions}; do
        extension_path="${docrootDir}/extensions/${extension}"
        source_path="/var/tmp/mediawiki/extensions/${extension}"
        
        if [ -d "${source_path}" ]; then
                echo "${extension}"
                rsync -a ${source_path}/ "${extension_path}/"
        fi
done

# enable new extensions: SmiteSpam & DeleteBatch
grep 'SmiteSpam' ${vhostDir}/LocalSettings.php || perl -0777 -pi -e "s%wfLoadExtension\( 'Nuke' \);%wfLoadExtension( 'Nuke' );\nwfLoadExtension( 'SmiteSpam' );\nwfLoadExtension( 'DeleteBatch' );%igs" ${vhostDir}/LocalSettings.php

# add skins (with wfLoadSkin() instead of require_once)
grep 'wfSkinLoad' ${vhostDir}/LocalSettings.php || perl -0777 -pi -e "s/$wgDefaultSkin = 'Vector';/\$wgDefaultSkin = 'Vector';\n\nwfLoadSkin( 'CologneBlue' );\nwfLoadSkin( 'Modern' );\nwfLoadSkin( 'MonoBook' );\nwfLoadSkin( 'Vector' );/igs" ${vhostDir}/LocalSettings.php

# re-enable CategoryTree extension
grep 'wfLoadExtension.*CategoryTree' ${vhostDir}/LocalSettings.php || perl -0777 -pi -e 's%#require_once\("{\$IP}/extensions/CategoryTree/CategoryTree.php"\);%#require_once("{$IP}/extensions/CategoryTree/CategoryTree.php");\n\nwfLoadExtension( "CategoryTree" );\n%igs' ${vhostDir}/LocalSettings.php

# re-enable ConfirmEdit and switch to FancyCaption
grep 'FancyCaptcha' ${vhostDir}/LocalSettings.php || perl -0777 -pi -e "s%\\\$wgCaptchaClass = 'SimpleCaptcha';%\#\\\$wgCaptchaClass = 'SimpleCaptcha';\n\nwfLoadExtensions([ 'ConfirmEdit', 'ConfirmEdit/FancyCaptcha' ]);\n\\\$wgCaptchaDirectory = '/var/www/html/wiki.opensourceecology.org/htdocs/images/captcha/';\n\\\$wgCaptchaSecret = '$wgCaptchaSecret';\n%igs" ${vhostDir}/LocalSettings.php

# update cron script to use new secret
cp /usr/local/bin/mediawiki_generate_captchas.sh /usr/local/bin/mediawiki_generate_captchas.sh.$(date "+%Y%m%d_%H%M%S")
sed -ie "s%CAPTCHA_SECRET='\([^']*\)'%\CAPTCHA_SECRET='$wgCaptchaSecret'%" /usr/local/bin/mediawiki_generate_captchas.sh

# re-enable ConfirmAccount extension
grep 'wfLoadExtension.*ConfirmAccount' ${vhostDir}/LocalSettings.php || perl -0777 -pi -e 's%#require_once "\$IP/extensions/ConfirmAccount/ConfirmAccount.php";%#require_once "$IP/extensions/ConfirmAccount/ConfirmAccount.php";\n\nwfLoadExtension( "ConfirmAccount" );\n%igs' ${vhostDir}/LocalSettings.php

# re-enable UserMerge extension
sed -i 's%^\(\s*\)#wfLoadExtension\(.*\)UserMerge\(.*\)%\1wfLoadExtension\2UserMerge\3%' ${vhostDir}/LocalSettings.php

# re-enable Widgets extension
grep 'wfLoadExtension.*Widgets' ${vhostDir}/LocalSettings.php || perl -0777 -pi -e 's%#require_once\("\$IP/extensions/Widgets/Widgets.php"\);%#require_once("$IP/extensions/Widgets/Widgets.php");\n\nwfLoadExtension( "Widgets" );\n%igs' ${vhostDir}/LocalSettings.php

# re-enable ParserFunctions extension
grep 'wfLoadExtension.*ParserFunctions' ${vhostDir}/LocalSettings.php || perl -0777 -pi -e 's%#require_once\( "\$IP/extensions/ParserFunctions/ParserFunctions.php"  \);%#require_once( "$IP/extensions/ParserFunctions/ParserFunctions.php"  );\n\nwfLoadExtension( "ParserFunctions" );\n%igs' ${vhostDir}/LocalSettings.php

# remove deprecated password policy and add new https://www.mediawiki.org/wiki/Manual:$wgPasswordPolicy
grep 'PasswordNotInCommonList' ${vhostDir}/LocalSettings.php || perl -0777 -pi -e "s%\\\$wgPasswordPolicy\['policies'\]\['default'\]\['PasswordCannotBePopular'\] = PHP_INT_MAX;\n\\\$wgPasswordPolicy\['policies'\]\['default'\]\['PasswordCannotMatchUsername'\] = true;%#\\\$wgPasswordPolicy['policies']['default']['PasswordCannotBePopular'] = PHP_INT_MAX;\n#\\\$wgPasswordPolicy['policies']['default']['PasswordCannotMatchUsername'] = true;\n\\\$wgPasswordPolicy['policies']['default']['PasswordNotInCommonList'] = true;\n\\\$wgPasswordPolicy['policies']['default']['PasswordCannotBeSubstringInUsername'] = true;%igs" ${vhostDir}/LocalSettings.php

# configure OATH (2FA) requirements
grep 'wgOATHAuthWindowRadius' ${vhostDir}/LocalSettings.php || perl -0777 -pi -e "s%wfLoadExtension\( 'OATHAuth' \);%wfLoadExtension( 'OATHAuth' );\n\n# Relaxed mode with +/- 4 minutes time drift tolerance. This is important or users will complain and/or disable 2FA entirely\n# The security consequences are small. The usability benefits are huge.\n\\\$wgOATHAuthWindowRadius = 8;\n\n# make admins require 2FA\n\\\$wgOATHRequiredForGroups = ['sysop', 'interface-admin', 'bureaucrat', 'suppress', 'widgeteditor' ];\n\n# make 'powerful' rights require 2FA\n\\\$wgOATHExclusiveRights =  [ 'apihighlimits', 'applychangetags', 'autoconfirmed', 'autopatrol', 'bigdelete', 'block', 'blockemail', 'bot', 'changetags', 'createaccount', 'createtalk', 'delete', 'deletechangetags', 'deletedhistory', 'deletedtext', 'deletelogentry', 'deleterevision', 'editcontentmodel', 'editinterface', 'editprotected', 'editsemiprotected', 'editsitecss', 'editsitejs', 'editsitejson', 'editusercss', 'edituserjs', 'edituserjson', 'hideuser', 'import', 'importupload', 'ipblock-exempt', 'managechangetags', 'markbotedits', 'mergehistory', 'move-categorypages', 'move-rootuserpages', 'move-subpages', 'nominornewtalk', 'noratelimit', 'patrol', 'protect', 'renameuser', 'reupload-shared', 'sendemail', 'suppressionlog', 'suppressredirect', 'suppressrevision', 'unblockself', 'unwatchedpages', 'userrights', ];\n\n# full list for reference (taken from htdocs/includes/MainConfigSchema.php) https://www.mediawiki.org/wiki/Extension:OATHAuth#Configuration\n#\\\$wgOATHExclusiveRights =  [ 'apihighlimits', 'applychangetags', 'autoconfirmed', 'autopatrol', 'bigdelete', 'block', 'blockemail', 'bot', 'browsearchive', 'changetags', 'createaccount', 'createpage', 'createtalk', 'delete', 'deletechangetags', 'deletedhistory', 'deletedtext', 'deletelogentry', 'deleterevision', 'edit', 'editcontentmodel', 'editinterface', 'editmyoptions', 'editmyprivateinfo', 'editmyusercss', 'editmyuserjs', 'editmyuserjson', 'editmyuserjsredirect', 'editmywatchlist', 'editprotected', 'editsemiprotected', 'editsitecss', 'editsitejs', 'editsitejson', 'editusercss', 'edituserjs', 'edituserjson', 'hideuser', 'import', 'importupload', 'ipblock-exempt', 'managechangetags', 'markbotedits', 'mergehistory', 'minoredit', 'move', 'move-categorypages', 'movefile', 'move-rootuserpages', 'move-subpages', 'nominornewtalk', 'noratelimit', 'patrol', 'protect', 'read', 'renameuser', 'reupload', 'reupload-shared', 'rollback', 'sendemail', 'suppressionlog', 'suppressredirect', 'suppressrevision', 'unblockself', 'undelete', 'unwatchedpages', 'upload', 'userrights', 'viewmyprivateinfo', 'viewmywatchlist', 'viewsuppressed' ];\n%igs" ${vhostDir}/LocalSettings.php

# FIX PERMISSIONS
time /usr/local/bin/fix_web_permissions.sh

# clear varnish cache again
varnishadm 'ban req.http.host ~ "wiki.opensourceecology.org"'

# log into the new MediaWiki site, and update settings:

# Create a new account (Called 'CatarinaAdmin') and add it to sysop group

# Remove the following accounts from the sysop group
## Audrey Rampone
## Elifarley
## Hart
## Will

# TODO: Enforce 2FA for all admin accounts

TODO: Update DNS to point to hetzner3

  1. wait until DNS changes to hetzner3
while true; do date; dig store.opensourceecology.org; sleep 10; echo; done

Validation Steps

  1. TODO: copy from previous CHGs

Revert Steps

TODO

See Also

  1. CHG-2018-02-05_migrate_osemain_to_hetzner2 Last wordpress migration from hetzner1 to hetzner2
  2. CHG-2024-07-26 yum update Last (possible) update to hetzner2
  3. List of other CHG "tickets"