Backup for mailcow — user guide
Installation
- The module ships in mailcow Toolkit 0.7.0 or newer (one package, one license per product). On the mailcow host, as root, run the Toolkit installer as usual:
sudo ./install.sh --mailcow-dir /opt/mailcow-dockerized --name <instance>, or update the Toolkit from System → Updates (Toolkit). The installer copiesdata/web/mlw-backup/, installs the host script/usr/local/sbin/mlw-mailcow-backup-<instance>, creates the history table and the timermlw-mailcow-backup-<instance>.timer(every 5 minutes it checks whether a backup is due). - Install GnuPG on the host if it is missing:
apt install gnupg. - Open System → Backup in the mailcow admin menu.
License
Open System → Updates (Toolkit) and find the Backup for mailcow card: paste the key and activate it, or start the 30-day trial. On the shell: php /web/mlw-toolkit/cli.php activate mailcow-backup <KEY> inside php-fpm-mailcow.
Without a valid license the scheduled backups and the Google Drive uploads stop. Verify, restore and delete keep working, so you can always get your data back.
First setup
- Settings → Local folder: an absolute path on the host, ideally on another disk than mailcow (for example
/srv/backup/mailcowor a mounted disk). It is created readable by root only. Leave room for about two backups. - Encryption: press Set with generated (recommended): the passphrase is shown once — store it outside the server (password manager, paper). Or choose my own and type one of at least 12 characters twice.
- Back up now in the Status card makes the first backup; the progress and the log show live.
Schedule, components and retention
In Settings:
- Scheduled backups on or off; Times (server time, several allowed, e.g.
03:15, 15:15) and Days. - What is backed up: mail (vmail), encryption keys (crypt — needed to read encrypted mail), redis, rspamd, postfix, database (SQL). All are on by default.
- Local copies kept and Copies kept on Drive: the newest N stay; older ones are deleted after each backup.
- Compression threads for mailcow's script.
- E-mail: on failure only (default), after every backup, or never; empty address = the Toolkit's notification address.
A backup missed while the server was off runs once when it is back. Scheduled backups run at a low CPU and disk priority.
What a backup is
mailcow's own backup_and_restore.sh writes the chosen components; the module packs them into one archive and encrypts it with GnuPG (AES-256, with integrity protection) under your passphrase:
| File | Content |
|---|---|
mailcow-<host>-<date>.tar.gpg |
the encrypted archive (mailcow's backup_*.tar.zst files and its mailcow.conf) |
mailcow-<host>-<date>.json |
the manifest: components and sizes, SHA-256 of the archive, passphrase id, mailcow and Toolkit versions |
Without mailcow: gpg -d mailcow-…tar.gpg > backup.tar asks for the passphrase and gives back mailcow's usual backup folder.
Google Drive
The module uses your own Google OAuth client, so the access to your Drive stays on your server:
- In Google Cloud Console, create (or pick) a project and enable the Google Drive API.
- OAuth consent screen: type External, your e-mail as support and developer contact; then Publish app ("In production"). In testing mode Google expires the access after 7 days.
- Credentials → Create credentials → OAuth client ID, type Web application, with the redirect URI shown on the page:
https://<your mailcow UI host>/mlw-backup/oauth.php. - Paste the Client ID and the client secret into Google Drive on the page, Save, then Connect Google Drive and allow access. Google may warn that the app is not verified: it is your own app, continue.
- In Settings, turn on Upload every backup to Google Drive and choose the folder name.
The scope is drive.file: the module sees only the files it created, never the rest of your Drive. Uploads go in 32 MiB parts and continue after a network error. Test lists the folder; Disconnect revokes the access (the backups stay on Drive).
Verify and restore
In Backups every backup shows where it is (local, Drive or both):
- Verify: decrypts and reads the whole archive (downloaded from Drive if it is not local) without restoring anything.
- Restore…: tick the components, type
RESTORE, confirm. The archive's SHA-256 is checked against its manifest, it is decrypted and its paths checked, then each component is restored with the steps of mailcow's own restore: the containers concerned are stopped and started again; the database stops the whole mailcow for a few minutes and takes the SQL credentials of the backup'smailcow.conf. What changed in those components after the backup date is lost. No forced mail resync is run; if a mailbox looks wrong afterwards:docker exec $(docker ps -qf name=dovecot-mailcow) doveadm force-resync -A '*'. - Delete: removes the backup locally and from Drive.
A new server
- Install mailcow and the Toolkit, activate the license (or restore without one).
- Encryption → my own: type the old passphrase (on a server that already has one, tick for older backups only).
- Google Drive: use the same Google OAuth client and connect; the old backups appear (the module sees the files its client created).
- Restore… the newest backup, all components.
Shell and files
The host script can be run by hand (as root): MLW_TK_CONF=/etc/mlw-mailcow-toolkit/<instance>.conf mlw-mailcow-backup-<instance> backup|verify NAME|list. The progress is in data/hooks/phpfpm/.mlw-toolkit/backup/run.json and run.log; the history in the mlw_bk_run table of mailcow's database. uninstall.sh keeps the local backups and the ones on Drive.