How To Securely Backup Your Website And Database With Tarsnap Inside Docker
This is a step-by-step guide on how to securely back up website files and database on your server with Tarsnap running inside a Docker container. If you need secure cloud backups from your computer to Dropbox or Google Drive, check out Rebel Backup.
Tarsnap is a secure online backup service. One of its main advantages is that the backups it makes are encrypted with a secret key accessible only to you. This means that neither Tarsnap itself, nor anyone with access to its servers, can decrypt your backups unless they have your secret key. While the backups themselves ensure that you don't lose the important data from your server, the encryption lets you not worry about an attacker getting hold of your backups and accessing the sensitive data inside them.
Tarsnap is ideal for running on a server that hosts a website and a database, allowing you to back up the contents of your database, as well as anything else that you would not want to lose, such as your SSL certificate and configuration files.
We assume you're running your web server and database inside Docker containers, and describe how to set up Tarsnap to run in a container alongside them to make periodic backups.
NOTE: We're in no way affiliated with Tarsnap, other than being a happy customer of the service.
First you would need a Tarsnap account - follow steps 3 and 4 of the Tarsnap Getting Started guide.
Next you need to generate your secret key. This requires Tarsnap to be installed on the system where the generation is to occur. Since we will be running Tarsnap inside a Docker container, we won't necessarily have (or want) Tarsnap on the server host itself. So here you have two options - either install Tarsnap on the server and generate the key there, placing it into an appropriate location, or install Tarsnap on your local computer, generate the key, and securely copy it to the server.
Installing Tarsnap is covered in step 1 of the Getting Started guide, and step 5 shows how to generate the key itself. You can use
scp or an sftp client to securely copy the key from your computer to the server.
This part is really important. You need to store your secret key somewhere safe. If you store it only on your server, and you lose the server for whatever reason, you won't be able to restore your backups. It happens - a cloud provider may accidentally wipe out your VPS; an attacker could purposefully destroy the contents of your server; an
rm command might be fed the wrong arguments during administrative work.
Step 6 of the Getting Started guide lists some good options for keeping your secret key safe. Please use more than one. Store it on multiple systems. Store it encrypted in Dropbox or Google Drive using Rebel Backup. Print it out and put it into several locations. If you're renting out a bank vault, put the printout there too.
Docker Compose Entry
We assume you're using docker-compose to configure your containers. If you're using some other method, adapt the following accordingly.
To define our Tarsnap container, first we have to add a corresponding entry to the
docker-compose.yml file. We will call the container
backuper, and the entry should look like this:
... backuper: build: context: Backuper # LINE A image: backuper # Adjust the image name if needed volumes: - ./Backuper/Main-bin:/Main/bin:ro # LINE B - /PATH/TO/TARSNAP/DATA:/tarsnap:rw # LINE C - /PATH/TO/WEBSITE/DATA:/backup/PATH/TO/WEBSITE/DATA:ro # LINE D - /SOME/OTHER/PATH/TO/SERVER/DATA:/backup/SOME/OTHER/PATH/TO/SERVER/DATA:ro # LINE E - /PATH/TO/DATABASE/BACKUP:/backup/PATH/TO/DATABASE/BACKUP:rw # LINE F ...
context line under
build (LINE A) defines the subdirectory containinig a
Dockerfile for the Tarsnap container; in our case the subdirectory is called
volumes, we have several items. We mount a directory with the scripts we will be using (more on that below) in LINE B. The Tarsnap directory from the host, which contains the secret key and cache, is mounted in LINE C. Unlike most other directories, this one as mounted as read-write, because it hosts the Tarsnap cache.
Next we have some data directories from the host (presumably used by your containers) that we want to back up (LINE D and E). Adjust these as needed, and use as many as you need. Note that they all are mounted inside the
/backup directory in the Tarsnap container.
If you're using a database, the important part is to make sure not to mount the live data directory of the database server into
/backups. Doing so will screw up your database backups, making them either corrupt or inconsistent.
Instead, during a backup process, we will be creating a database dump, and mounting that inside
/backup, as illustrated by LINE F. Note that the directory is also mounted read-write, since the dumping will be performed from the Tarsnap container.
Now we have to configure the Tarsnap container. In the
docker-compose.yml configuration file, we've specified the subdirectory for the container as
Backuper. The contents of that directory are as follows:
Backuper/ Main-bin/ back-up-postgres.sh back-up.sh run-tarsnap.sh usr/ local/ etc/ tarsnap.conf crontab Dockerfile install
Let's start with the
Dockerfile, which defines the Tarsnap container. Its contents are as follows:
FROM debian:stretch-slim RUN apt-get update && apt-get -y install wget && apt-get -y install gnupg # -------------------------------------------------------------------------------------------------- # This section (2) is copied from https://github.com/atmoz/tarsnap/Dockerfile and somewhat modified ENV TARSNAP_VERSION 1.0.39 ENV TARSNAP_SHA256 5613218b2a1060c730b6c4a14c2b34ce33898dd19b38fb9ea0858c5517e42082 ENV TARSNAP_MAKE_PACKAGES \ ca-certificates \ make \ gcc \ libssl-dev \ zlib1g-dev \ e2fslibs-dev ENV TARSNAP_RUN_PACKAGES \ locales \ openssl COPY . / RUN /install ENV LANG en_US.UTF-8 ENV LANGUAGE en_US.UTF-8 ENV LC_ALL en_US.UTF-8 # -------------------------------------------------------------------------------------------------- # This section (3) installs the proper postgresql-client # NOTE: For some reason "apt-get -y install gnupg" doesn't work here; doing it at the top works though. # NOTE: --no-check-certificate is required to avoid a GPG error. RUN wget --no-check-certificate -q https://www.postgresql.org/media/keys/ACCC4CF8.asc -O- | apt-key add - RUN echo "deb http://apt.postgresql.org/pub/repos/apt/ stretch-pgdg main" | tee /etc/apt/sources.list.d/postgresql.list RUN apt-get update && apt install -y postgresql-client-11 # -------------------------------------------------------------------------------------------------- # This section (4) is copied from our Dockerfile-cron RUN apt-get -y install cron ADD crontab /etc/crontab # NOTE: The stuff after cron lets us pass cron output to docker logs. CMD cron && \ echo -n "" && : >> /var/log/cron.log && \ tail -f /var/log/cron.log
Besides building and installing the Tarsnap client (section 2), we install a PostgreSQL client (section 3), and then install and launch
cron, to run our periodic backups (section 4).
If you're using a different database server, e.g. MySQL, adapt the third section to install the necessary database client.
install file is taken from atmoz/tarsnap on GitHub and is responsible for performing the Tarsnap installation inside the container.
The Tarsnap configuration file, under
Backuper/usr/local/etc/tarsnap.conf, has the following important bits:
... cachedir /tarsnap/cache keyfile /tarsnap/key ...
These should match the Tarsnap destination directory used in our
docker-compose.yml file (LINE C).
crontab file configures cron to run the backups periodically. In our case it has a single line:
15 0,6,12,18 * * * root /Main/bin/back-up.sh >> /var/log/cron.log 2>&1
This runs the backup script -
/Main/bin/back-up.sh - every six hours, at 00:15, 06:15, 12:15, and 18:15 (6:15 pm). Adjust as needed. If you're unfamiliar with
crontab syntax, you can use the following site to generate a timing configuration for you, and put it before the
" root" part of the line.
The backup script -
Backuper/Main-bin/back-up.sh - is called by
cron to do the backing up itself. For clarity, its job has been split into two different subscripts, though, of course, you can keep everything in a single file. Its contents:
#!/bin/sh echo "Backing up ..." /Main/bin/back-up-postgres.sh /Main/bin/run-tarsnap.sh
As you can see, the backing up is split into two parts. First, we create a dump of the database, and put it inside the
/backup directory. Next, with all the data ready inside
/backup, we run Tarsnap to perform the actual backing up.
The contents of
#!/bin/sh # NOTE: The /backup/PATH/TO/DATABASE/BACKUP must be the same as the destination in LINE F from the docker-compose.yml above. cd /backup/PATH/TO/DATABASE/BACKUP && \ rm -f postgres-dump.inprogress PGPASSWORD="YOUR-DATABASE-ROOT-PASSWORD" pg_dumpall -h postgres -U root > postgres-dump.inprogress rm -f postgres-dump && \ mv postgres-dump.inprogress postgres-dump
In this example we're hardcoding the root password for the database server in the script. This can be improved by passing appropriate environment variables to the container.
If you're using MySQL, you would need to use a similar
back-up-mysql.sh script instead, to dump the contents of your MySQL server.
run-tarsnap.sh script feeds
/backup to Tarsnap:
#!/bin/sh /usr/local/bin/tarsnap -c -f "server-$(date +%Y%m%d-%H%M%S)" /backup
You can adjust the backup file name (
server-...) as needed.
Verifying Your Backups
Once your setup is complete and the
cron job is running, you can verify your backups by listing them and extracting a recent one, as described in the Tarsnap Testing / restoring backups section (at end of the page).
We hope you've enjoyed this article, and although the setup might look a bit elaborate, your server will be properly backed up from now on.
And if you're looking for an easy way to securely back up important files on your computer, try Rebel Backup - it lets you make encrypted backups to Dropbox and Google Drive (which may be more cost-effective compared to Tarsnap if you have a lot of data to back up), uses state-of-the-art encryption, and is a breeze to use.
Written by Vasyl Smyrnov, July 9, 2019