James Thorpe

Dovecot mailbox backups

Feb 05, 2020 dovecot linux restic

I've been using the same provider for my web and email hosting for a number of years. For a variety of reasons (the main one being increases in price vs what I can achieve on AWS), I've been working to move away from them. This website is already hosted on S3 - I don't have any other website needs that aren't met right now. That just leaves my email.

To facilitate this - I wondered "how hard can it be to run a mailserver for a couple of domains and a handful of users?". Well, I now have a mailserver running Postfix and Dovecot, and a handful of plugins - there's plenty of guides around doing this, such as this one. One area I had a hard time figuring out was how to do mailbox backups for all users. I'm using virtual mailboxes, so no actual users on the mailserver.

My goal here was to use restic for backups - I'm using it for other backups already. First thought was to just target the mail storage directory directly with restic to backup, but apparently you shouldn't do that - especially when using the mdbox format - as the indexes may change halfway through and the backup be corrupted. Instead it's safer to use doveadm to sync the mailbox elsewhere, then backup that.

So - first job, backing up all the mailboxes. Seems straightforward enough using doveadm backup, right? It even has an option to iterate all users:

doveadm backup -A maildir:/var/backups/mail/mailboxes/

Nope - when you use -A to iterate over all users, it literally runs the backup for each user one after the other, all of them overwriting the others in the target directory. Ok... so the docs say that the maildir is the same as the mail_location setting. That allows you to use %u, %d and %n as placeholders for user name, domain and name respectively - let's try that:

doveadm backup -A maildir:/var/backups/mail/mailboxes/%u

Nope again! Now you just get a directory called %u, with the same each-user-overwriting-the-previous-one problem (%d and %n have the same issue, before you try). I spent a good amount of time looking around to see if there was a way to get the backup working with -A into separate directories, but just couldn't find one. At this point I figured it was probably best to just script around it.

First up - let's get a list of users:

doveadm user *@*

Works for me - get one user per line in the output. Now to do something useful with it:

doveadm user *@* | while read user; do
  echo Backing up mail for $user
  doveadm backup -u $user maildir:/var/backups/mail/mailboxes/$user
done

Perfect! I also scripted the dumping of the database holding the config for the virtual domains/users, and added the restic backup part after initialising the repository. Here's my complete backup-mail script:

#!/usr/bin/bash
echo Backing up database
rm -f /var/backups/mail/db/dump.sql
mkdir -p /var/backups/mail/db
mysqldump -p<SQL PASSWORD> postfix > /var/backups/mail/db/dump.sql

doveadm user *@* | while read user ; do
  echo Backing up mail for $user
  doveadm backup -u $user maildir:/var/backups/mail/mailboxes/$user
done

export RESTIC_PASSWORD="<RESTIC PASSWORD>"
restic -r s3:s3.amazonaws.com/<MYBUCKET>/restic/mailserverdata backup /var/backups/mail
export RESTIC_PASSWORD="x"

Side note: if anyone has a way to pass in the repository password to restic on the command line rather than having to set it in the environment, I'm all ears...

Back to posts