WARNING! AUTOMATE BACKUP BEFORE AUTOMATE UPDATE-UPGRADE!

While keeping WordPress including its plugins and themes up to date on a daily basis is a important thing to avoid beeing hacked and abused to spread malware, it must be said, that automating self-hosted wordpress installations is no simple task.

In order to avoid any mishaps (as it has happened before!!!) it is HIGHLY recommended to AUTOMATICALLY backup 1) all fiels in web root 2) the database BEFORE the automated update-upgrade and also test the restore process! After restore everything still working as it should? Good! Advance to automated updates-upgrades! NOT BEFORE! WARNING SEND!

automatic (daily, hourly?) updates of everything internet-reachable is important.

  • of course developers need to provide timely updates for possible cybersec problems
  • users/admins need working update methods that work with minimum downtime

the wordpress “automatic core and plugin auto-updates” feature, has been php-implemented into wordpress for a while and sometimes it even works.

but somteimes it does not (!?).

  • so there might be a reliable mechanism required to:
    • make an backup
    • then reliably run wordperss core and plugin auto update on daily basis

if the user runs it own webserver (vm or dedicated server): https://github.com/wp-cli/wp-cli + the following script 🙂 can do that.

also check out: https://wp-cli.org/

update: 2022

something must have gone wrong.

added “update translations” to the script.

so … updating self hosted wordpress “manual” way, still seems to be ONLY solid option. 🙁

==> /var/log/apache2/domain.com-error.log <== [Tue Dec 13 13:11:18.913569 2022] [php:error] [pid 416927] [client xxx.xxx.xxx.xxx:17253] PHP Fatal error: Uncaught Error: Call to undefined function trailingslashit() in /var/www/html/domain.com/public_html/wp-includes/class-wp-textdomain-registry.php:1 03\nStack trace:\n#0 /var/www/html/domain.com/public_html/wp-includes/l10n.php(784): WP_Textdomain_Registry->set()\n#1 /var/www/html/domain.com/public_html/wp-includes/load.php(1401): load_textdomain()\n#2 /var/www/html/domain.com/public_html/wp-includes/load.php(162): wp_load_translations_early()\n#3 /var/www/html/domain.com/public_html/wp-settings.php(37): wp_check_php_mysql_versions()\n#4 /var/www/html/domain.com/public_html/wp-config.php(93): req
uire_once('...')\n#5 /var/www/html/domain.com/public_html/wp-load.php(50): require_once('...')\n#6 /var/www/html/domain.com/public_html/wp-blog-header.php(13): require_once('...')\n#7 /var/www/html/domain.com/public_ht
ml/index.php(17): require('...')\n#8 {main}\n  thrown in /var/www/html/domain.com/public_html/wp-includes/class-wp-textdomain-registry.php on line 103 

snapshot/backup before update:

because things might break, and then a restore to working state is possible.

GNU Linux Bash – simple backup web root and mysql mariadb database in one go script

install:

the default apache2 user is called www-data and is per default not allowed to login

lsb_release -d; # tested on
Description: Debian GNU/Linux 11 (bullseye)
su - root
mkdir software
cd software
# download the software
curl -O https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar
# check integrity
php wp-cli.phar --info
# install
chmod +x wp-cli.phar
mv - wp-cli.phar /usr/local/bin/wp

# temporarily allow login
usermod -s /bin/bash www-data
# become that user
su - www-data

# cd into a wordpress installation
cd /var/www/html/some-domain.com/

wp --info
# or
wp cli info
OS:	Linux 5.10.0-15-amd64 #1 SMP Debian 5.10.120-1 (2022-06-09) x86_64
Shell:	/bin/sh
PHP binary:	/usr/bin/php8.1
PHP version:	8.1
php.ini used:	/etc/php/8.1/cli/php.ini
MySQL binary:	/usr/bin/mysql
MySQL version:	mysql  Ver 15.1 Distrib 10.5.15-MariaDB, for debian-linux-gnu (x86_64) using  EditLine wrapper
SQL modes:	
WP-CLI root dir:	phar://wp-cli.phar/vendor/wp-cli/wp-cli
WP-CLI vendor dir:	phar://wp-cli.phar/vendor
WP_CLI phar path:	/var/www/html/some-domain.com
WP-CLI packages dir:	
WP-CLI global config:	
WP-CLI project config:	
WP-CLI version:	2.6.0

# what version of wordpress is installed?
wp core version --extra
WordPress version: 6.0.1
Database revision: 53496
TinyMCE version:   4.9110 (49110-20201110)
Package language:  en_US

# update wordperss, if update is available
wp core update
Success: WordPress is up to date.

# list all installed plugins
wp plugin list
+--------------------------+----------+--------+---------+
| name                     | status   | update | version |
+--------------------------+----------+--------+---------+
| antispam-bee             | active   | none   | 2.11.1  |
+--------------------------+----------+--------+---------+


# update plugins
wp plugin update --all

# disable login again for non-root apache2 default user
usermod -s /sbin/nologin www-data

script it:

vim /root/scripts/wordpress_update.sh

#!/bin/bash
# what to backup
WEBROOT=/var/www/html

# temporarily allow non-root apache2 user to login
usermod -s /bin/bash www-data

echo "===== wordpress automatic update single wordpress in web root ===="
INSTALLATION=$WEBROOT
echo "currently installed:";
su www-data -c "wp core version --path=$INSTALLATION";
echo "..... if updates available, updating:"
echo "...core"; su www-data -c "wp core update --path=$INSTALLATION";
echo "...themes"; su www-data -c "wp theme update --all --path=$INSTALLATION";
echo "...plugins"; su www-data -c "wp plugin update --all --path=$INSTALLATION";
# echo "===== wordperss automatic update multiple wordpress in web root ====="
# for FULLPATH in $WEBROOT/*; do
#     if [ -d "$FULLPATH" ]; then
#         BASENAME=$(basename $FULLPATH);
# 
# 	INSTALLATION=$FULLPATH;
# 	# might need modification like this:
# 	# INSTALLATION=$FULLPATH/public_html;
# 
#         echo "=== updating $INSTALLATION ==="
#         echo "currently installed:"; su www-data -c "wp core version --path=$INSTALLATION";
#         echo "..... if updates available, updating:"
#         echo "...core"; su www-data -c "wp core update --path=$INSTALLATION";
#         echo "...themes"; su www-data -c "wp theme update --all --path=$INSTALLATION";
#         echo "...plugins"; su www-data -c "wp plugin update --all --path=$INSTALLATION";
#     fi
# done

# disable login again for non-root apache2 default user
usermod -s /sbin/nologin www-data

echo "=== disable xmlrpc.php because a lot of pwd brute force attacks focus on this file ==="
echo "... also via the readme.html the installed version of wordpress can be identified"
echo "... the following files were found and renamed to .disabled"
find $WEBROOT -type f -name 'xmlrpc.php';
find $WEBROOT -type f -name 'xmlrpc.php' -print0 | xargs --null -I{} mv {} {}.disabled;

find $WEBROOT -type f -name 'liesmich.html';
find $WEBROOT -type f -name 'liesmich.html' -print0 | xargs --null -I{} mv {} {}.disabled;

find $WEBROOT -type f -name 'readme.html';
find $WEBROOT -type f -name 'readme.html' -print0 | xargs --null -I{} mv {} {}.disabled;

find $WEBROOT -type f -name 'license.txt';
find $WEBROOT -type f -name 'license.txt' -print0 | xargs --null -I{} mv {} {}.disabled;

alternative version including update of translations:

#!/bin/bash
# what to backup
WEBROOT=/var/www/html

# temporarily allow non-root apache2 user to login
# /usr/sbin/usermod -s /bin/bash www-data

echo "===== wordperss automatic update all wordpress in web root ====="
for FULLPATH in $WEBROOT/*; do
    if [ -d "$FULLPATH" ]; then
        BASENAME=$(basename $FULLPATH);

	INSTALLATION=$FULLPATH/public_html;

        echo "=== updating $INSTALLATION ==="
        echo "currently installed:"
	wp core version --path=$INSTALLATION
        echo "..... if updates available, updating:"
        echo "...core"
	wp core update --path=$INSTALLATION
        echo "...themes"
	wp theme update --all --path=$INSTALLATION
        echo "...plugins"
	wp plugin update --all --path=$INSTALLATION
	echo "...translations"
	wp language core update --path=$INSTALLATION
    fi
done

cron it:

no need for separate cron job just make it part of the (already existing?) daily update script 🙂

crontab -e
# m h   dom mon dow command
  0 2   *   *   *   /root/scripts/update.sh; # every day 2:00 run updates
cat /root/scripts/update.sh 
#!/bin/bash

echo "=== attempting automatic daily update on $(date '+%Y-%m-%d-%H:%M:%S') ===" | tee -a /scripts/update.sh.log

apt update 2>&1 | tee -a /scripts/update.sh.log
apt -y upgrade 2>&1 | tee -a /scripts/update.sh.log

echo "=== automatically removing un-needed packages (and old kernels) ==="
# keeping too many old kernel versions might fill up boot partition
apt -y autoremove | tee -a /scripts/update.sh.log

echo "=== updating wordpress installations ===" | tee -a /scripts/update.sh.log
/root/scripts/wordpress_update.sh | tee -a /scripts/update.sh.log

echo "=== fine ===" | tee -a /scripts/update.sh.log
echo "" | tee -a /scripts/update.sh.log

manpages:

wp.man.txt

liked this article?

  • only together we can create a truly free world
  • plz support dwaves to keep it up & running!
  • (yes the info on the internet is (mostly) free but beer is still not free (still have to work on that))
  • really really hate advertisement
  • contribute: whenever a solution was found, blog about it for others to find!
  • talk about, recommend & link to this blog and articles
  • thanks to all who contribute!
admin