Wordpress
Wordpress Plugins
- No Self Pings - remove self pings
- Contact Form 7 - easy to maintain contact form
- Efficient Related Posts - shows related posts by tags
- Enhanced Recent Posts - shows recent posts, can exclude posts from categories
- Like - Facebook like button for posts
- MailChimp Widget - easy and free newsletter by Mailchimp
- Really Simple CAPTCHA - needed for Contact Form 7
- Semisecure Login Reimagined - for more secure login into your Wordpress
- Social Media Widget - Adds links to all of your social media and sharing site as a widget
- W3 Total Cache - for caching (performance)
- XCloner - Backup and Restore - schedule backups with cron jobs
OSE Website - Known Bugs
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:
- vhost dir = /var/www/html/osemain
- wp docroot = /var/www/html/osemain/htdocs
Then the ideal permissions are:
- Files containing passwords (ie: wp-config.php) should be located outside the wp docroot with apache:apache-admins 0440
- Files in the wp-content dir should be apache:apache 0660
- Directories in the wp-content dir should be apache:apache 0770
- All other files in the vhost dir should be apache:apache 0640
- 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: 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/:
vhostDir=/var/www/html/osemain 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 2: Permissions
TODO link to other section
Step 3: SVN Update
TODO update with svn
Step 4: Update Plugins and Themes
TODO update with wp-cli
Step 5: Database Upgrade
TODO: login to wp & update (or is it upgrade?)
Step 6: 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 DB_NAME, DB_USER, DB_PASSWORD, WP_HOME, & WP_SITEURL 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 # 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/ # finally, log into the new wordpress site. After authenticating, wp will ask you to update, if necessary. Then you can test.