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.

Intro

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.

Initial Setup

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.

Key Security

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
...

The context line under build (LINE A) defines the subdirectory containinig a Dockerfile for the Tarsnap container; in our case the subdirectory is called Backuper.

Under 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.

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.

The 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).

The 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 back-up-postgres.sh:

#!/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.

Finally, the 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).

Conclusion

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