#!/bin/sh
# Backs up the parts of the mail server that cannot be recreated:
#
#   - the user database (domains, mailboxes, password hashes, aliases)
#   - the private DKIM keys  (generating new ones would mean changing DNS and
#     waiting until the old signature has expired everywhere)
#   - the configuration files
#
# NOT included is the mail data under /var/vmail - depending on usage it can
# grow very large and needs a backup scheme of its own (restic or borg to
# remote storage, say).
#
# Runs daily from a systemd timer:  systemctl list-timers mailbackup

set -eu

DEST=/var/backups/mailserver
KEEP=30
STAMP=$(date +%Y-%m-%d_%H%M)
ARCHIVE="$DEST/mailserver_$STAMP.tar.gz"

mkdir -p "$DEST"
chmod 700 "$DEST"

TMP=$(mktemp -d)
trap 'rm -rf "$TMP"' EXIT

# Write the database out consistently - a plain copy would be unsafe if a
# write happened to be in progress.
sqlite3 /etc/mailserver/mail.db ".backup '$TMP/mail.db'"

mkdir -p "$TMP/config"
cp -a /etc/mailserver/schema.sql          "$TMP/config/" 2>/dev/null || true
# Carries the identity of the server (name, address, SSH port). Without it a
# restore does not know what the certificates were for, nor which address
# belongs in the DNS recommendations.
cp -a /etc/mailserver/server.conf         "$TMP/config/" 2>/dev/null || true
cp -a /etc/mailserver/README.md           "$TMP/config/" 2>/dev/null || true
cp -a /etc/postfix/main.cf                "$TMP/config/" 2>/dev/null || true
cp -a /etc/postfix/master.cf              "$TMP/config/" 2>/dev/null || true
cp -a /etc/postfix/sqlite                 "$TMP/config/" 2>/dev/null || true
cp -a /etc/dovecot/dovecot.conf           "$TMP/config/" 2>/dev/null || true
cp -a /etc/dovecot/sieve                  "$TMP/config/" 2>/dev/null || true
cp -a /etc/rspamd/local.d                 "$TMP/config/" 2>/dev/null || true
cp -a /etc/nftables.conf                  "$TMP/config/" 2>/dev/null || true
cp -a /etc/fail2ban/jail.d                "$TMP/config/" 2>/dev/null || true

mkdir -p "$TMP/dkim"
cp -a /var/lib/rspamd/dkim/. "$TMP/dkim/" 2>/dev/null || true

tar czf "$ARCHIVE" -C "$TMP" .
chmod 600 "$ARCHIVE"

# Clean up older backups. The names carry the date as YYYY-MM-DD_hhmm, so
# sorting them in reverse alphabetical order puts the newest on top - no
# "ls -t" needed, which could trip over a shell alias.
printf '%s\n' "$DEST"/mailserver_*.tar.gz 2>/dev/null | sort -r | tail -n +$((KEEP + 1)) | while read -r old; do
    [ -f "$old" ] && rm -f "$old"
done

logger -t mailbackup "Backup written: $ARCHIVE ($(du -h "$ARCHIVE" | cut -f1))"
echo "Backup written: $ARCHIVE"
