Automatically Back up WordPress to Dropbox with WP-CLI Bash Script

There is a crazy amount of WordPress backup plugins out there. One of my favorites is UpdraftPlus available on the repository for when I have to move sites between shared hosting accounts. When I back up my own sites from my VPS, I replicate the behavior of many plugins: package up the whole site, database and send it to Cloud Storage. This is lighter on resources and isn’t prone to PHP timeouts or other nonsense.

In this tutorial I will be using WP-CLI and bash to back up WordPress or WooCommerce sites (entire folder and database) and upload those packages to Dropbox from your VPS or dedicated server. We’ll also be deleting old backups too.

Note: Dropbox provides 2 GB of space for free, if your site is larger consider using Google Drive instead with this guide.

Update: bugfix to delete old scripts and $SITENAME variable (thanks Ahmad)

Automatically Back up WordPress to Dropbox with WP-CLI and Bash

Installation overview

  • Create the Dropbox app for the access token
  • Test the bash Dropbox uploader
  • Create the Backup script
    • Schedule the backup script to run daily

Create Dropbox App

Log in to the Dropbox Developer section

Under My apps click Create app.
dropbox-create-app

Under Choose an API, select Dropbox API.

Under Choose the type of access you need, select App folder.

Name your app whatever you want. This will become the folder name in your Dropbox folder.

Check I agree and click Create app.

dropbox-app-settings

Now we can generate the access token that the Dropbox Uploader bash program needs.

Under the OAuth2 section, click Generate.

dropbox-generate-access-token

You will need this access token for the Dropbox Uploader.

Install Dropbox Uploader

The Dropbox Uploader requires curl so make sure it is installed.

sudo apt-get update
sudo apt-get install curl -y

Now download the dropbox_uploader and place it into /usr/bin.

sudo curl "https://raw.githubusercontent.com/andreafabrizi/Dropbox-Uploader/master/dropbox_uploader.sh" -o /usr/bin/dropbox_uploader

If you want to run dropbox_uploader as a regular user you can change the ownership of the program to that user.

sudo chown user /usr/bin/dropbox_uploader

Make sure the dropbox_uploader allows its owner to read, write and execute (7)

sudo chmod 755 /usr/bin/dropbox_uploader

Now you can start the initial setup wizard by executing

dropbox_uploader

When you see this prompt, paste your Dropbox Access token created earlier.

This is the first time you run this script, please follow the instructions:

 1) Open the following URL in your Browser, and log in using your account: https://www.dropbox.com/developers/apps
 2) Click on "Create App", then select "Dropbox API app"
 3) Now go on with the configuration, choosing the app permissions and access restrictions to your DropBox folder
 4) Enter the "App Name" that you prefer (e.g. MyUploader267311959129698)

 Now, click on the "Create App" button.

 When your new App is successfully created, please click on the Generate button
 under the 'Generated access token' section, then copy and paste the new access token here:

 # Access token: w4xJFA74LXAAAAAAAAABZDI7k7NZSYrk1yvAynXzQTv4mHA8uMuYvIB73fa9MgZo

Confirm it’s all good by pressing y

The access token is w4xJFA74LXAAAAAAAAABZDI7k7NZSYrk1yvAynXzQTv4mHA8uMuYvIB73fa9MgZo. Looks ok? [y/N]: y
   The configuration has been saved.

Your Access token can now be found in your home folder’s hidden file ~/.dropbox_uploader.

Time to test the Dropbox Uploader.

Test Dropbox Uploader

Enter the temorary directory and create a test file

cd /tmp
echo "test" > testfile.txt

Upload that test file to Dropbox

dropbox_uploader upload testfile.txt /
 > Uploading "/tmp/testfile.txt" to "/testfile.txt"... DONE

You can verify that testfile.txt is there by checking the Dropbox App folder.

dropbox-verify-test-file

Now let’s delete the testfile.txt since we know it works

dropbox_uploader delete testfile.txt /
 > Deleting "/testfile.txt"... DONE

If you want a quick way to see all the files in the App folder this command will help

dropbox_uploader list / | awk '{print $3}'
"/"...
testfile.txt

To get all the directories

dropbox_uploader list / | awk '{print $2}'
Listing
guides.wp-bullet.com

Now we can use this along with WP-CLI to back up WordPress and WooCommerce sites.

Create the Dropbox Backup Script

Install WP-CLI and make the user own it with the executable permissions.

sudo wget -q https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar -O /usr/bin/wp
sudo chown user /usr/bin/wp
sudo chmod 755 /usr/bin/wp

Create the Dropbox backup script

nano ~/scripts/dropboxbackup.sh

Paste this script which backs up WordPress with tar, the database with wp-cli (and gzips it), then uploads the packages to Dropbox.

It will go through all WordPress folders in the SITESTORE path.

The script also deletes old backups based on the DAYSKEEP variable from both the local system and Dropbox.

At the end the script will fix any permissions, if you are on a non-standard Debian/Ubuntu setup that doesn’t use the www-data user you should comment these lines out with #

#!/usr/bin/env bash
# Source: https://guides.wp-bullet.com
# Author: Mike

#define local path for backups
BACKUPPATH=/tmp/backups

#path to WordPress installation folders
SITESTORE=/var/www

#date prefix
DATEFORM=$(date +"%Y-%m-%d")

#Days to retain
DAYSKEEP=7

#calculate days as filename prefix
DAYSKEPT=$(date +"%Y-%m-%d" -d "-$DAYSKEEP days")

#create array of sites based on folder names
SITELIST=($(ls -d $SITESTORE/* | awk -F '/' '{print $NF}'))

#make sure the backup folder exists
mkdir -p $BACKUPPATH

#start the loop
for SITE in ${SITELIST[@]}; do
    #check if there are old backups and delete them
    EXISTS=$(dropbox_uploader list /$SITE | grep -E $DAYSKEPT.*.tar.gz | awk '{print $3}') 
    if [ ! -z $EXISTS ]; then
        dropbox_uploader delete /$SITE/$DAYSKEPT-$SITE.tar.gz /$SITE/
        dropbox_uploader delete /$SITE/$DAYSKEPT-$SITE.sql.gz /$SITE/
    fi

    echo Backing up $SITE
    #enter the WordPress folder
    cd $SITESTORE/$SITE
    if [ ! -e $BACKUPPATH/$SITE ]; then
        mkdir $BACKUPPATH/$SITE
    fi

    #back up the WordPress folder
    tar -czf $BACKUPPATH/$SITE/$DATEFORM-$SITE.tar.gz .

    #back up the WordPress database
    wp db export $BACKUPPATH/$SITE/$DATEFORM-$SITE.sql --all-tablespaces --single-transaction --quick --lock-tables=false --allow-root --skip-themes --skip-plugins
    cat $BACKUPPATH/$SITE/$DATEFORM-$SITE.sql | gzip > $BACKUPPATH/$SITE/$DATEFORM-$SITE.sql.gz
    # remove the uncompressed sql file
    rm $BACKUPPATH/$SITE/$DATEFORM-$SITE.sql

    #upload packages
    dropbox_uploader upload $BACKUPPATH/$SITE/$DATEFORM-$SITE.tar.gz /$SITE/
    dropbox_uploader upload $BACKUPPATH/$SITE/$DATEFORM-$SITE.sql.gz /$SITE/
done

#if you want to delete all local backups
#rm -rf $BACKUPPATH/*

#delete old backups locally over DAYSKEEP days old
find $BACKUPPATH -type d -mtime +$DAYSKEEP -exec rm -rf {} \;

#Fix permissions for standard Debian and Ubuntu installations
sudo chown -R www-data:www-data $SITESTORE
sudo find $SITESTORE -type f -exec chmod 644 {} +
sudo find $SITESTORE -type d -exec chmod 755 {} +

I recommend testing the WordPress Dropbox backup script

sudo bash ~/scripts/dropboxbackup.sh

Now add the script as a cronjob so it runs every day

crontab -e

Enter this so the script runs at midnight daily, you may want to use absolute paths to the script (e.g. /home/user/scripts or /root/scripts)

@daily /bin/bash ~/scripts/dropboxbackup.sh

Ctrl+X, Y and Enter to Save and Exit

Now every day the Dropbox backup script will run exporting your database with WP-CLI, your WordPress installation with tar and upload them to Dropbox without any plugins while deleting old backups!

Sources

Formatting Times and Dates
Date calculation with Bash

9 thoughts on “Automatically Back up WordPress to Dropbox with WP-CLI Bash Script”

    • btw I found a bug in the script so it doesn’t delete old files (the EXISTS variable turns into an array)

      This seems to solve the problem

      EXISTS=$(dropbox_uploader list /$SITE | grep -E $DAYSKEPT.*.tar.gz | awk ‘{print $3}’)

        • That would be cool, there is definitely a use case for it especially for larger sites that don’t necessarily change that much. I am just busy atm preparing other guides (there are plenty more coming!) so I don’t have too much time to look at it. I would love to see an implementation on it if you are working on one and help out if I can.

          • I also don’t have time at the moment, but if I decide to implement this in the future will post it here.
            And looking forward to the new guides 🙂

Comments are closed.