In the previous chapter, I walked you through WordPress caching. In this chapter I will demonstrate how to configure WordPress cron, outgoing email and automatic backups.

Cron

WordPress has built-in support for scheduled tasks, which allows certain processes to be performed in the background at designated times. Out-of-the-box WordPress performs the following scheduled tasks:

  • Automatic updates which are pushed out by the WordPress core team to fix security vulnerabilities
  • Check WordPress is running the latest stable release
  • Check for plugin updates
  • Check for theme updates
  • Publish any posts scheduled for future release

However, the cron system used by WordPress isn’t the most performant or accurate of
implementations
. Scheduled tasks in WordPress are triggered during the lifecycle of a page request, therefore if your site doesn’t receive any visits for a set period of time, no cron events will be triggered during this time.

This is especially true of sites that use page caching, such as Nginx FastCGI cache introduced in the previous chapter. With page caching enabled, WordPress is no longer processing each page request if the page cache is hit. This means that cron will not fire until the page cache expires. If you have configured the cache to expire after 60 minutes this may not be an issue, however, if you are caching for longer periods of time this may become problematic.

Using page requests to execute the cron is also problematic on sites without page caching that receive a lot of traffic. Checking if the cron needs to be executed on every page request is hard on server resources and several simultaneous requests could cause the cron to execute multiple times.

To overcome these issues cron should be configured using the operating system daemon (background process), available on Linux and all Unix-based systems. Because cron runs as a daemon it will run based on the server’s system time and no longer requires a user to visit the site.

Before configuring cron it’s recommended that you disable WordPress from automatically handling cron. Add the following line to your wp-config.php file:

define('DISABLE_WP_CRON', true);

Introducing Crontab

Scheduled tasks on a server are added to a text file called crontab and each line within the file represents one cron event. If your server hosts multiple sites you will need one entry per site.

Begin by connecting to your server.

ssh ashley@pluto.ashleyrich.com

Open the crontab using the following command. If this is the first time you have opened the crontab, you may be asked to select an editor. Option 2 (nano) is usually the easiest.

crontab -e

crontab1

I’m not going to go into detail on the crontab syntax, but adding the following to the end of the file will trigger WordPress cron every 5 minutes. Remember to update the file path to point to your WordPress install and to repeat the entry for each site.

*/5 * * * * cd /home/ashley/ashleyrich.com/public; /usr/local/bin/wp cron event run --due-now >/dev/null 2>&1

Some articles suggest using wget or curl for triggering cron, but using WP-CLI is recommended. Both wget and cURL make requests through Nginx and are subject to the same timeout limits as web requests. However, you may want your cron jobs to run for longer periods of time, for example if a plugin is uploading hundreds or thousands of media to Amazon S3 as a background process. There is no timeout limit when running WordPress cron via WP-CLI, it will execute until complete.

The >/dev/null 2>&1 part ensures that no emails are sent to the Unix user account initiating the cron job.

Save the file by hitting CTRL X followed by Y.

Cron is now configured using the Unix system cron tool, but I’ll demonstrate how to check it’s running correctly later on.

Email

Email servers are notoriously difficult to set up. Not only do you need to ensure that emails successfully hit recipient inboxes, but you also have to consider how you’ll handle spam and viruses (sent as email attachments). Installing the required software to run your own mail server can also eat up valuable system resources and potentially open up your server to more security vulnerabilities. This DigitalOcean article discusses in more detail why you may not want to host your own mail server.

I do not recommend that you configure your server to handle email and instead use a ‘best of breed’ service provider, such as G Suite. However, WordPress still needs to send outgoing emails:

  • Admin notifications
  • New user signups
  • Password resets
  • Auto update notifications

And that’s just WordPress core. Add plugins to the mix and the volume and importance of emails sent from your site can balloon. Think WooCommerce and order receipts.

Outgoing Email

Although it’s popular to configure WordPress to use SMTP for outgoing email, we do not recommend it. Instead, you should use a WordPress plugin that connects directly to an email sending service via an API.

Preferably a plugin that queues emails to be sent later when the API is unreachable instead of never sending them. WP Offload SES and WP Offload SES Lite are such plugins. In addition to simplifying the setup process WP Offload SES sends emails via Amazon SES, so you can be sure of high deliverability and low costs.

Testing Cron and Outgoing Email

In order to test that both cron and outgoing emails are working correctly, I have written a small plugin that will send an email to the admin user every 5 minutes. This isn’t something that you’ll want to keep enabled indefinitely, so once you have established that everything is working correctly, remember to disable the plugin!

Create a new file called cron-test.php within your plugins directory, with the following contents:

<?php
/**
 * Plugin Name: Cron & Email Test
 * Plugin URI: https://spinupwp.com/hosting-wordpress-yourself-cron-email-automatic-backups/
 * Description: WordPress cron and email test.
 * Author: SpinupWP
 * Version: 1.0
 * Author URI: http://spinupwp.com
 */

/**
 * Schedules
 *
 * @param array $schedules
 *
 * @return array
 */
function db_crontest_schedules( $schedules ) {
    $schedules['five_minutes'] = array(
        'interval' => 300,
        'display'  => 'Once Every 5 Minutes',
    );

    return $schedules;
}
add_filter( 'cron_schedules', 'db_crontest_schedules', 10, 1 );

/**
 * Activate
 */
function db_crontest_activate() {
    if ( ! wp_next_scheduled( 'db_crontest' ) ) {
        wp_schedule_event( time(), 'five_minutes', 'db_crontest' );
    }
}
register_activation_hook( __FILE__, 'db_crontest_activate' );

/**
 * Deactivate
 */
function db_crontest_deactivate() {
    wp_unschedule_event( wp_next_scheduled( 'db_crontest' ), 'db_crontest' );
}
register_deactivation_hook( __FILE__, 'db_crontest_deactivate' );

/**
 * Crontest
 */
function db_crontest() {
    wp_mail( get_option( 'admin_email' ), 'Cron Test', 'All good in the hood!' );
}
add_action( 'db_crontest', 'db_crontest' );

Upon activating the plugin, you should receive an email shortly after. If not, check your crontab configuration and WP Offload SES settings.

Automatic Backups

Performing backups on a regular basis is essential. It’s inevitable that at some point in the future you will need to restore data – whether that be due to user error, corruption or a security breach. You never know what could go wrong, so having a recent backup to hand can really make your life easier as a systems administrator.

There are generally two types of backups I like to perform. The first is a full system backup and the second is a backup of each individual site hosted on the server.

Full system backups are best performed by your VPS provider but they are not usually enabled by default. Both DigitalOcean and Linode offer this service for a nominal fee. This sort of backup is generally only used when a rare, catastrophic failure occurs where all the data on your server was lost. You won’t want to restore the entire system if only a single site needs restoring, hence the reason for single site backups.

Single site backups only backup the items required to restore a single site and in terms of WordPress this usually consists of the database and the uploads directory. If you’re using a plugin such as WP Offload Media, you can skip the need to backup the uploads directory as the files are automatically sent to your configured storage provider when added to the media library.

For sites that aren’t updated often, a weekly backup should suffice, but you may want to perform them more frequently. For example, you may want to perform backups for an e-commerce site every few hours depending on how often new orders are received.

To set up single site backups, first create a new directory within the site’s root directory.

mkdir backups

This will sit alongside the existing cache, logs and public directories.

backup1

Now create a new file called backup.sh.

nano backup.sh

Paste the following contents into the file, ensuring you update the path to your site.

#!/bin/bash

cd /home/ashley/ashleyrich.com/public

# Backup database
wp db export ../backups/`date +%Y%m%d`_database.sql --add-drop-table

# Backup uploads directory
tar -zcf ../backups/`date +%Y%m%d`_uploads.tar.gz wp-content/uploads

Hit CTR X followed by Y to save the file.

backup2

Ensure the newly created file has execute permissions.

chmod u+x backup.sh

The last step is to schedule the backup script to run at a designated time. Begin by opening the crontab.

crontab -e

Add the following line to the end of the file.

0 5 * * 0 sh /home/ashley/ashleyrich.com/backup.sh >/dev/null 2>&1

This will run backups every Monday morning at 05:00, server time. Just remember that you’ll need to add this script and crontab entry for each individual site you wish to backup. Check out Brad’s post on how to send the backup files to Amazon S3 and automatically remove old backups.

That concludes this chapter. In the next chapter we’ll improve the security of our server with tweaks to the Nginx configuration.


Subscribe to get the latest news, updates and optimizations in performance and security.

Thanks for subscribing 👍

To receive awesome stuff, you'll need to head to your inbox and click on the verification link we sent you.
Make sure to check your "spam" folder or your "promotions" tab (if you have Gmail).
If you're still having trouble, then messages us at sudo@spinupwp.com.