One of my goals this year is to stop spending time maintaining my own private code.
I have a pile of apps and scripts and learn a great deal writing them, but I’d rather focus on sharing and improving code instead of being a hoarder. Another goal is to spend more time on code and techniques I’d offer to clients and fewer rabbit-hole learning quests. So this one’s a two-fer.
After a thorough comparison of VPS providers and ways of provisioning I’ve decided to simplify my live and embrace Laravel Forge. I have a few hosting accounts with smaller providers that don’t offer backup service, so I’ve spiffed up my pre-Forge backup scheme for quick setup on a newly-provisioned Forge server.
It stores data offsite with Backblaze B2 using a command line app called restic.
The combination is stable, inexpensive, efficient and encrypted. A nice perk is that the backups are snapshots, meaning you can choose a specific backup point to browse/restore much like Apple’s Time Machine. This and the built-in encryption make it better than just rsyncing data. (Credit goes to The Full Stack Blog for pointing me toward restic!)
Good news, dear reader: if you’re using Forge, you can probably use this too! Grab it from GitHub (workingconcept/forge-backup), and let’s take a quick look at how it works in the wild.
Requirements
- Server provisioned with Laravel Forge running Ubuntu 18+.
- Backblaze account.
Quick Version
You can clone the repository to start, but everything’s built into one shell script so you can run a one-liner as root:
Note that you must be root here and not just use sudo
.
It’s a good idea to be wary of downloading and running shell scripts as root because some random internet guy said it’s cool on his blog. So let’s examine what happens one step at a time.
Step 0: Ready the Things
Provision a Forge server and keep track of the sudo and database passwords you get. You can safely run this on an existing server as long as it’s Ubuntu 18+, because restic
isn’t included in Ubuntu’s default packages for lower versions.
Create a Backblaze B2 bucket under B2 Cloud Storage → Buckets. Pick (and remember) the name and keep it Private.
Now choose Show Account ID and Application Key just above the big Create a Bucket button. Create a key and limit it to your new bucket, and grab the resulting key (large) and keyId (small) you’ll find at the bottom in this screenshot:
We’re ready to continue.
Step 1: Initialize
SSH into your new server and become root.
Copy and paste that one-liner and hit return.
This will download restic-setup.sh
from GitHub, make it executable, and then run it. That’ll look something like this:
It’s going to ask for your B2 application key ID, application key and bucket. Then it’ll install restic (apt-get install restic
) which will look like this:
Now you’ll be prompted for your default forge
MySQL password, which will used (without being stored) to create a new read-only backup
user with access to all databases.
Note the two passwords that were generated and stored, preceded with !!
in the setup output.
Answer y
to have restic to connect to B2 and establish its backup base. You’ll be prompted for that newly-generated restic repository password, which will be required for interacting with any of that backup data. It’s stored in /root/restic/conf
along with the B2 and backup MySQL credentials and an exclude list for the backup set. (If there’s a way to automate backups without storing these secrets please drop me a line or submit a pull request!)
That’s it. If everything worked, you’ve established an encrypted B2 store and set up the pieces you can use to run and automate backups. Let’s try them!
Step 2: Test
Run a MySQL dump with the included shell script.
This will create a compressed dump for each database and store it in /home/forge/backup/mysql/YYYY-MM-DD/DBNAME-{timestamp}.gz
.
The timestamp will keep your dump archives from overwriting each other unless you can somehow run your backups more than once per second. By default, the backup routine will prune dumps that are more than seven days old.
Now run the backup script, which will ignore .git directories and otherwise back up everything in /home/forge to a new snapshot stored in your B2 bucket.
Result:
As you can see from the output, it’s thoroughly scanning the backup target and making snapshots. It also prunes (removing duplicate data) and double-checks backup metadata against what’s actually stored. It’s nice.
Now try mounting your backup data like you’ve plugged in a thumb drive. (This happens via fuse
, if you’re curious, which is included by default with Ubuntu.)
Result:
Now you can cd /mnt/restic
to browse your snapshots.
When you’re done unmount that data with umount
, which is not a typo.
Step 3: Automate
Add a scheduled task to run /root/restic/restic-backup.sh >/dev/null 2>&1
at whatever interval you want.
I adore that Forge makes it easy to check scheduled log output from its interface, so it’s easy to confirm that the routine is running like you’d expect.
As with all backups, it’s a good idea to mount and verify them every now and then to be sure they’re actually working. I set a monthly calendar reminder to do this.
Consider leaving a comment or sending an email if you have questions or suggestions!