The danger of Upgrading WordPress

Late last night, just as I completed my post about Tesla trying to scam me, I decided to upgrade WordPress to version 5.4. Normally, this shouldn’t be an issue, but for me, since I run a multisite system, there are extra security issues and directory layout complications that must be taken into account.

The first step was, apparently, to backup my database. Since I’ve never backed up the mysql database before, I felt this seemed like a reasonable approach. I certainly didn’t want to pay JetPack to do it; I’m a genuine code jockey, I can do my own backups. After some digging around, I found mysqldump. Unfortunately, all the instructions on how to use it were incorrect.

After some further poking around, I finally came across the correct syntax. Essentially, the user name and host have to come before the --all-databases command. Also, the host can’t be localhost, it must be the IP for the local host. Unfortunately, I was not able to find a way to get it to prompt for my password which meant I had to type my password in the command line, leaving all there in the open for any history recall to see. Not very secure at all.

mysqldump -h --user=<uid> --password=<pw> --all-databases > mysql.2020.03.31.bak

mysqldump command; note <uid> and <pw> are placeholders for the user name and password; you must replace this with your own values.

Alas, I was not able to find a way to get mysqldump to prompt for a password. I think if I have more time, I may write a python script which builds the command by first prompting for the password. At least that way, the password wouldn’t be stored in the command line history.

The mysqldump command is quite clever. It just stores the list of sql commands that would be required to recreate the databases you have stored. However, the file is rather big and being text, it compresses nicely with bzip2 -9, which is what I did.

Once I did this, I was ready for the main Upgrade. I held my breath and pulled the trigger…

This site is built with WordPress… and a very skilled programmer who has been writing HTML since 1993 and hacking UNIX for even longer.

The install progressed along nicely until it tried to write a file to the wordpress directory. 🤦🏻‍♂️ I logged into my server and sure enough, the permissions on the wordpress directory were 755, which meant the user could add and remove files, but the group and anyone else could not. You see, with my multisite, I try to have all wordpress files with user wp-user and group as www-data, to work with apache. And apache runs all web processes as www-data for both user and group. Thus, when WordPress asked to add a file to its codebase, apache could not write it because the www-data group didn’t have permission, only wp-user did.

find /usr/share/wordpress -type 'd' -print0 | xargs -0 sudo chmod 775

Change all the wordpress directors to allow www-data to add and remove files from them.

Realizing my mistake, I changed the permissions on all directories to be 775 (both wp-user and www-data could add and remove files). Unfortunately, it was too late. Instead, I had no choice but to blow away my current install and replace it with a fresh, new install of WordPress 5.4. At least, that’s what I did on a high level. The details, though, are a bit more complex.

Once I extracted all the wordpress files, I needed to get their ownership to match the settings for my wordpress install. I was able to do this quite easily with the chown command.

sudo chown -R wp-user:www-data wordpress/

Command to set the right file ownership for wordpress.

Next, I set the directories as above. Finally, the files themselves had to have the right permissions. Namely, they should be readable and writable by wp-user and the www-data group, but only readable to others, not writable. Namely, they needed to be set to permission 664.

find wordpress/ -type 'f' -print0 | xargs -0 sudo chmod 664

Change all the wordpress files to allow www-data to modify them.

Next, I had to copy over the active wordpress configuration file. This file is actually fairly spartan as all the active site configurations are actually stored in /etc/wordpress; my wp-config.php actually just scans this directory for configurations. The configurations, in turn, point to directories in /srv/www/wp-content with the site-specific files. I thuns needed to bring that file over to the new install.

cp /usr/share/wordpress/wp-config.php wordpress

Copy the configuration to the new wordpress install.

Next, I wanted to preserve the Languages I had installed. I just copied the entire directory over to the local install.

cp -r /usr/share/wordpress/wp-content/languages wordpress/wp-content/

Copy the Languages directory to the wordpress install.

I also have an upgrades directory that I wanted to preserve.

cp -r /usr/share/wordpress/wp-content/upgrades/ wordpress/wp-content/

Copy the Upgrades directory to the wordpress install.

Finally, I needed to move the links to my shared, dynamic contents that are for all the sites on my server. Specifically, the uploads, themes, and plugins folders all rest in /var/lib/wordpress/wp-content. (Technically, Uploads rests in site-specific Uploads directory, but that’s something I’ll fix later to conform with the same layout Themes and Plugins use.) Since these are already symbolic links, they can be moved to the new wordpress install directory to replace the defaults.

One caveat however, is the default install for wordpress comes with one plugin and three themes. In order to preserve those, I renamed the default plugins directory to plugins-default, and the default themes directory to themes-default. This was necessary before the symbolic links could be moved since those directories were in the way.

mv /usr/share/wordpress/wp-content/uploads wordpress/wp-content
mv /usr/share/wordpress/wp-content/plugins wordpress/wp-content
mv /usr/share/wordpress/wp-content/themes wordpress/wp-content

Move the symbolic links to the plugins, themes, and uploads directories.

Finally, the apache permissions file needed to be moved as it was also a link, pointing to /etc/wordpress/htaccess. I store the file there because it makes it easier to maintain in case I accidentally bow the .htaccess file away.

cp /usr/share/wordpress/.htaccess wordpress

Move the symbolic link to the .htaccess file.

Once all this is done, it’s a good idea to run the chown and chmod commands from above on the wordpress install directory once more to make sure the copied files and moved links are also properly attributed.

Finally, it was time to perform the brain transplant and move my staged wordpress install to the active /usr/share/ directory. I moved the current install to a temporary directory and then moved my staging install to the /usr/share/ directory to replace it.

mv /usr/share/wordpress /usr/share/wordpress-old
mv wordpress /usr/share/wordpress

Replace the installed wordpress with the new version.

Once all this was done, I was able to get to my web page, and wordpress prompted me to upgrade my database. Once this was done my sites were back online. In total, this site and its sister sites were down for a total of about forty-five minutes. It was a long day yesterday and I was exhausted but I did get it done and you can now see the results.

I hope you enjoyed my story about hacking UNIX. Please note, I am available for hire if you like what you see!