Wordpress

From Open Source Ecology
Revision as of 20:51, 1 September 2017 by Maltfield (talk | contribs)
Jump to navigation Jump to search

Wordpress Plugins

OSE Website - Known Bugs

  • Fields not filled in - Wpbugs1.png

Proper File/Directory Ownership & Permissions

This section will describe how the file permissions should be set on an OSE wordpress site.

For the purposes of this documentation, let's assume:

  1. vhost dir = /var/www/html/osemain
  2. wp docroot = /var/www/html/osemain/htdocs

Then the ideal permissions are:

  1. Files containing passwords (ie: wp-config.php) should be located outside the wp docroot with apache:apache-admins 0440
  2. Files in the wp-content dir should be apache:apache 0660
  3. Directories in the wp-content dir should be apache:apache 0770
  4. All other files in the vhost dir should be apache:apache 0640
  5. All other directories in the vhost dir should be apache:apache 0750

This is achievable with the following idempotent commands:

vhostDir="/var/www/html/osemain"
wpDocroot="${vhostDir}/htdocs"

chown -R apache:apache "${vhostDir}"
find "${vhostDir}" -type d -exec chmod 0750 {} \;
find "${vhostDir}" -type f -exec chmod 0640 {} \;
find "${wpDocroot}/wp-content" -type f -exec chmod 0660 {} \;
find "${wpDocroot}/wp-content" -type d -exec chmod 0770 {} \;
chown apache:apache-admins "${vhostDir}/wp-config.php"
chmod 0440 "${vhostDir}/wp-config.php"

Updating Wordpress

First of all, it is not uncommon for an attempt to update wordpress to result in an entirely broken site. If you do not have linux and bash literacy, do not attempt to update wordpress. Moreover, you should be well-versed in how to work with mysqldump, tar, rsync, chmod, chown, & sudo. If you are not confident in how all of these commands work, do not proceed. Hire someone with sysops experience to follow this guide; it should take them less than a couple hours to update and/or revert if the update fails.

Step 0: Trigger Backup Scripts for System-Wide backup

For good measure, trigger a backup of the entire system's database & files:

sudo time /bin/nice /root/backups/backup.sh &>> /var/log/backups/backup.log

When finished, SSH into the dreamhost server to verify that the whole system backup was successful before proceeding

sudo bash -c 'source /root/backups/backup.settings; ssh $RSYNC_USER@$RSYNC_HOST du -sh backups/hetzner2/*'

Step 1: Set variables

Type these commands to set some variables, which will be used by the commands in the sections below. Replace 'osemain' with the corresponding directory for the wp site you're updating.

export vhostDir=/var/www/html/osemain

Step 2: Make Vhost-specific backups

The backups made in the previous step are huge. Because it's easier to work with vhost-specific backups, let's make a redundant copy available in /var/tmp/:

dbName=osemain_db
dbUser=osemain_user
 dbPass=CHANGEME
 rootDbPass=CHANGEME

stamp=`date +%Y%m%d_%T`
tmpDir=/var/tmp/dbChange.$stamp
sudo mkdir $tmpDir
sudo chown root:root $tmpDir
sudo chmod 0700 $tmpDir
sudo pushd $tmpDir
sudo service httpd stop

# create backup of all DBs for good measure
 sudo time nice mysqldump -uroot -p$rootDbPass --all-databases | gzip -c > preBackup.all_databases.$stamp.sql.gz

# dump wp DB contents
 sudo time nice mysqldump -u$dbUser -p$dbPass --database $dbName > $dbName.$stamp.sql

# files backup
sudo rsync -av --progress "${vhostDir}" "vhostDir.${stamp}.bak/"

Step 3: Permissions

TODO link to other section

Step 4: SVN Update

TODO update with svn

Step 5: Update Plugins and Themes

Run the following commands to have wp-cli update your plugins & themes.

# update wp plugins
sudo -u wp -i wp --path=${vhostDir}/htdocs plugin update --all

# update wp themes
sudo -u wp -i wp --path=${vhostDir}/htdocs theme update --all

Step 6: Database Upgrade

TODO: login to wp & update (or is it upgrade?)

Step 7: Validate

TODO describe a test for sanity of successful upgrade

Revert

TODO restore procedure

WP-CLI

Wordpress has been officially developing a tool for managing their software over CLI called wp-cli. This has been around since 2011, it's funded by big hosting companies that offer cheap wordpress shared hosting plans, and is actively developed (as of 2017-08-26, at the time of writing, the last commit was a few days ago, and releases come out every few months).

Unfortunately, wp-cli expects php to be more open than our hardened config allows, so we can't use it for updating the wp core software (instead we use svn), but it works great for most plugins & themes.

Here's how we install wp-cli on our server:

useradd wp
gpasswd -a wp apache
gpasswd -a wp apache-admins
su - wp
mkdir -p /$HOME/.wp-cli
cd /$HOME/.wp-cli
curl -O https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar
mkdir -p /$HOME/bin
ln -s /$HOME/.wp-cli/wp-cli.phar /$HOME/bin/wp
chown wp:wp -R /$HOME/.wp-cli
find /$HOME/.wp-cli -type d -exec chmod 0700 {} \;
find /$HOME/.wp-cli -type f -exec chmod 0600 {} \;
chmod 0700 /$HOME/.wp-cli/wp-cli.phar

Note that we should *not* be running wp as root. Doing so may allow a wp site that's been owned (which is very common) to escalate itself to having root privileges. This is why we use a special user 'wp', and all documentation on this wiki for `wp` command is preceded with `sudo -u wp -i wp ...`, so that someone following this guide doesn't accidentally run `wp` as root.

Here are some example wp-cli commands:

sudo -u wp -i wp --path=/var/www/html/osemain/htdocs theme list
sudo -u wp -i wp --path=/var/www/html/osemain/htdocs theme update --all

sudo -u wp -i wp --path=/var/www/html/osemain/htdocs plugin list
sudo -u wp -i wp --path=/var/www/html/osemain/htdocs plugin update --all

CLI guides

This section will provide commands to achieve certain actions for managing wordpress

replace strings everywhere in wp database backend

Use these commands to safely backup & do a string replacement for all occurrences from a given $fromString to $toString. This was used to replace links in the wordpress posts/pages to the ip address instead of using the domain name (which creates migration issues & https issues)

dbName=obi_db
dbUser=obi_user
 dbPass=CHANGEME
 rootDbPass=CHANGEME

fromString=138.201.84.223
toString=openbuildinginstitute.org

stamp=`date +%Y%m%d_%T`
tmpDir=/var/tmp/dbChange.$stamp
mkdir $tmpDir
chown root:root $tmpDir
chmod 0700 $tmpDir
pushd $tmpDir
service httpd stop

# create backup of everything for good measure
 time nice mysqldump -uroot -p$rootDbPass --all-databases | gzip -c > preBackup.all_databases.$stamp.sql.gz

# dump obi wordpress db contents
 time nice mysqldump -u$dbUser -p$dbPass --database $dbName > $dbName.$stamp.sql

# make backup
cp $dbName.$stamp.sql $dbName.$stamp.sql.orig

# sed
sed -i "s/$fromString/$toString/g" $dbName.$stamp.sql

# verify
grep "$fromString" $dbName.$stamp.sql | less
grep "$toString" obi_db.$stamp.sql | less

# delete db tables
 mysql -u$dbUser -p$dbPass $dbName -sNe 'show tables' | while read table; do mysql -u$dbUser -p$dbPass -sNe "DROP TABLE $dbName.$table;"; done

# verify
 mysql -u$dbUser -p$dbPass $dbName -sNe 'show tables' 

# import
 mysql -u$dbUser -p$dbPass < obi_db.$stamp.sql

# verify
 mysql -u$dbUser -p$dbPass $dbName -sNe 'show tables' 
service httpd start

migrate to svn-backed wordpress install

These commands were used to migrate the existing & outdated wordpress installs to a subversion-backed, ephemeral clone of the site. Changes were iterated to these commands documented here as validation by the site owners exposed issues with the upgrades, missing content, etc. Once the clone was validated entirely, the live site could be brought down & confidently updated per the findings with the ephemeral clone.

obi

oldVhostDir=/var/www/html/obi
newVhostDir=/var/www/html/obi2
oldDbName=obi_db
newDbName=obi2_db
newDbUser=obi2_user
 newDbPass=CHANGEME
 rootDbPass=CHANGEME

rm -rf $newVhostDir
mkdir -p $newVhostDir/htdocs
pushd $newVhostDir/htdocs

yum install subversion
svn co https://core.svn.wordpress.org/tags/4.8.1 .

find $newVhostDir -type d -exec chmod 750 {} \;
find $newVhostDIr -type f -exec chmod 640 {} \;
chown -R apache:apache $newVhostDir

stamp=`date +%Y%m%d_%T`
tmpDir=/var/tmp/dbChange.$stamp
mkdir $tmpDir
chown root:root $tmpDir
chmod 0700 $tmpDir
pushd $tmpDir
 time nice mysqldump -uroot -p$rootDbPass --all-databases | gzip -c > preBackup.all_databases.$stamp.sql.gz
 time nice mysqldump -uroot -p$rootDbPass --databases $oldDbName > $oldDbName.$stamp.sql
cp $oldDbName.$stamp.sql $newDbName.$stamp.sql

# replace the first 2 (non-comment) occurances of $OldDbName with $newDbName
vim $newDbName.$stamp.sql

# update links for 3Dmodels, which we're moving to the 'wp-content' dir
sed -i 's^/3Dmodels/^/wp-content/3Dmodels/^g' "$newDbName.$stamp.sql"

 time nice mysql -uroot -p$rootDbPass -sNe "DROP DATABASE IF EXISTS $newDbName;" 
 time nice mysql -uroot -p$rootDbPass -sNe "CREATE DATABASE $newDbName; USE $newDbName;"
 time nice mysql -uroot -p$rootDbPass < "$newDbName.$stamp.sql"
 time nice mysql -uroot -p$rootDbPass -sNe "GRANT ALL ON $newDbName.* TO '$newDbUser'@'localhost' IDENTIFIED BY '$newDbPass'; FLUSH PRIVILEGES;"

popd

rsync -av --progress $oldVhostDir/wp-config.php $newVhostDir/
chown apache:apache $newVhostDir/wp-config.php
chmod 400 $newVhostDir/wp-config.php

# change WP_HOME, WP_SITEURL, DB_NAME, DB_USER, & DB_PASSWORD
vim $newVhostDir/wp-config.php

# we want to copy files that don't exist yet in our new install dir. if a file exists in both, don't overwrite the new from the old
rsync -av --progress --ignore-existing $oldVhostDir/htdocs/wp-content/ $newVhostDir/htdocs/wp-content/

# delete unnecessary & empty upgrade dir
rm -rf $newVhostDir/htdocs/wp-content/upgrade

# delete unnecessary plugins
rm -rf $newVhostDir/htdocs/wp-content/plugins/hello.php
rm -rf $newVhostDir/htdocs/wp-content/plugins/password-protected
rm -rf $newVhostDir/htdocs/wp-content/plugins/simple-301-redirects

# migrate '3Dmodels' dir, but put it in 'wp-content' for future migrations (the wp upgrade docs migrate this dir already)
rsync -av --progress $oldVhostDir/htdocs/3Dmodels $newVhostDir/htdocs/wp-content/

# take the old .htaccess; overwrite existing if needed
rsync -av --progress $oldVhostDir/htdocs/.htaccess $newVhostDir/htdocs/

# set permissions
chown -R apache:apache "${newVhostDir}"
find "${newVhostDir}" -type d -exec chmod 0750 {} \;
find "${newVhostDir}" -type f -exec chmod 0640 {} \;
find "${newVhostDir}/htdocs/wp-content" -type f -exec chmod 0660 {} \;
find "${newVhostDir}/htdocs/wp-content" -type d -exec chmod 0770 {} \;
chown apache:apache-admins "${newVhostDir}/wp-config.php"
chmod 0440 "${newVhostDir}/wp-config.php"

# update wp plugins
sudo -u wp -i wp --path=$newVhostDir/htdocs plugin update --all

# update wp themes
#sudo -u wp -i wp --path=$newVhostDir/htdocs theme update --all

# install & configure 2FA plugins
sudo -u wp -i wp --path=$newVhostDir/htdocs plugin install google-authenticator --activate
sudo -u wp -i wp --path=$newVhostDir/htdocs plugin install google-authenticator-encourage-user-activation --activate
defaultOtpAccountDescription="`basename $newVhostDir` wp"
cd $newVhostDir/htdocs/wp-content/plugins/google-authenticator
sed -i "s^\$GA_description\s=\s(\s[\"'].*[\"']^\$GA_description = ( '$defaultOtpAccountDescription'^" google-authenticator.php

# install 'force-strong-passwords' plugin
sudo -u wp -i wp --path=$newVhostDir/htdocs plugin install force-strong-passwords --activate

# install rename-wp-login plugin
sudo -u wp -i wp --path=$newVhostDir/htdocs plugin install rename-wp-login --activate

# add vhosts dir to php.ini 'open_basedir'
vim /etc/php.ini

# create vhosts apache conf file w/ deny for 'wp-login.php'
#<LocationMatch .*wp-login.php>                                                  
#  Deny From All                                                                
#</LocationMatch>  

vim /etc/conf.d/TODO

# apply apache configs
service httpd reload

# finally, log into the new wordpress site (use '/login' instead of '/wp-login.php'. After authenticating, wp will ask you to update, if necessary. Then update settings:
# 1. "Settings" -> "Permalinks" -> "Rename wp-login.php" -> "Login url" = 'ose-hidden-login'
## added section to "deny from all" for anyone attempting to hit '.../wp-login.php' to vhost config