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.

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;

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

admin