zmbkposev3 is a Bash tool for Zimbra backup and restore automation. It
supports hot backup and restore of Zimbra Collaboration Open Source Edition
accounts, including full backups, incremental backups, verification, scheduled
backups, and optional remote copy to rsync or SFTP storage.
It backs up:
- account LDAP data to
acct.ldif - mailbox data to
mailbox.tgz - full and incremental backup cycles
It installs as zmbkposev3, not zmbkpose, so it can live beside an existing
legacy zmbkpose installation.
This tool is for account-level backup and restore. It is not full disaster recovery for a Zimbra server.
It does not replace VM snapshots, storage snapshots, OS backup, Zimbra server configuration backup, SSL certificate backup, DNS backup, or a documented bare-metal recovery plan.
- Full backup for all accounts or selected accounts
- Incremental backup based on the previous backup time
- Restore existing or deleted accounts
- Restore all accounts found in backup storage
- Backup archive verification
- CSV backup and restore audit logs
- init.d scheduler service
- Scheduled full and incremental backup times
- Retry handling for failed scheduled backups
- Backup retention before full backups start
- Optional remote copy by
rsyncorsftp - Optional SFTP SSH key generation during install
- Safe uninstaller
Use Zmbkpose v3 when you need a practical Zimbra Open Source Edition backup tool for daily mail operations, including:
- Zimbra OSE mailbox backup and restore
- Zimbra full backup and incremental backup automation
- Zimbra account-level restore from backup archives
- Zimbra backup verification before marking a backup as usable
- Scheduled Zimbra backups on Ubuntu or similar Linux servers
- Remote Zimbra backup copy to SFTP, TrueNAS, FreeNAS, or rsync storage
Tested for Ubuntu-style Linux servers. The scripts expect Bash and common Unix tools.
Required commands:
awk curl date diff du egrep find grep gzip ldapadd ldapsearch ln mktemp printf rm sed sort stat tar uniq readlinkOptional commands:
rsync # only when REMOTE_COPY_METHOD=rsync
sftp # only when REMOTE_COPY_METHOD=sftp
ssh-keygen # only when installer generates an SFTP keyOn some Zimbra installs, ldapsearch is under Zimbra paths instead of the
system path. EXTRA_COMMAND_PATHS handles that.
Run the installer as root:
chmod +x install.sh
sudo ./install.shThe installer copies:
/usr/local/bin/zmbkposev3
/usr/local/bin/zmbkposev3-main
/usr/local/bin/zmbkposev3-uninstall
/etc/init.d/zmbkposev3
/etc/zmbkposev3/zmbkpose.conf
During install it asks for:
- backup working directory
- service user, normally
zimbra - full backup time
- incremental backup times
- how many full backup cycles to keep
- retry count and retry wait time
- optional remote copy method,
rsyncorsftp - optional SFTP key generation
Main config file:
/etc/zmbkposev3/zmbkpose.confMinimal example:
WORKDIR="/opt/mailbackup-files"
ADMINUSER="admin@example.com"
ADMINPASS="change-this"
LDAPMASTERSERVER="ldap://mail.example.com:389"
LDAPZIMBRADN="uid=zimbra,cn=admins,cn=zimbra"
LDAPZIMBRAPASS="change-this"
VERIFY_BACKUP_AFTER_CREATE=yesZimbra LDAP values can usually be found on the Zimbra server:
su - zimbra -c 'zmlocalconfig zimbra_ldap_userdn'
su - zimbra -c 'zmlocalconfig -s zimbra_ldap_password'Do not commit a real production zmbkpose.conf with passwords.
Backups are stored under WORKDIR using this layout:
WORKDIR/domain/user/YYYYMMDDhhmmss:FULL.tar
WORKDIR/domain/user/YYYYMMDDhhmmss:INC.tar
Example:
/opt/mailbackup-files/example.com/alice/20260904120000:FULL.tar
/opt/mailbackup-files/example.com/alice/20260904180000:INC.tar
Each backup tar contains:
acct.ldif LDAP account data
mailbox.tgz mailbox export from Zimbra
Distribution lists and non-mailbox entries may contain only LDAP data.
Full backup for all accounts:
sudo -u zimbra zmbkposev3 -fFull backup for one account:
sudo -u zimbra zmbkposev3 -f -a alice@example.comFull backup for multiple accounts:
sudo -u zimbra zmbkposev3 -f -a alice@example.com,bob@example.comIncremental backup:
sudo -u zimbra zmbkposev3 -i -a alice@example.comIncremental backup, but create a full backup if no previous backup exists:
sudo -u zimbra zmbkposev3 -i -t -a alice@example.comConditional full backup, only when the last full backup is older than 7 days:
sudo -u zimbra zmbkposev3 -F 7dConditional incremental backup, only when the last backup is older than 4 hours:
sudo -u zimbra zmbkposev3 -I 4h -tUseful limits:
sudo -u zimbra zmbkposev3 -f -C 6h -c 400 -e 5sMeaning:
-C 6hstops starting new account backups after 6 hours-c 400limits this run to 400 accounts-e 5swaits 5 seconds between accounts
By default, new backup files are verified before the LAST symlink is updated.
Verification checks:
- outer tar readability
acct.ldifexists and has valid Zimbra LDAP data- mailbox accounts contain a readable
mailbox.tgz
Verify all backups:
sudo -u zimbra zmbkposev3 -vVerify one account:
sudo -u zimbra zmbkposev3 -v -a alice@example.comVerify one file:
sudo -u zimbra zmbkposev3 --vf /opt/mailbackup-files/example.com/alice/20260904120000:FULL.tarSkip verification for one backup run:
sudo -u zimbra zmbkposev3 -f --no-verifyBACKUP_KEEP_FULL controls how many full backup cycles are kept per account.
The check runs before a new full backup starts, which saves disk space.
Examples:
BACKUP_KEEP_FULL=3Before a new full backup, old cycles are deleted until only two existing full cycles remain. After the new full backup completes, the account has three full cycles.
BACKUP_KEEP_FULL=0All existing valid backup cycles for that account are deleted before the new full backup is created. The new full backup still gets created.
Be careful with BACKUP_KEEP_FULL=0: if old cycles are deleted and the new full
backup fails, there may be no previous backup cycle left for that account.
Manual count-based rotation:
sudo -u zimbra zmbkposev3 --rotate-full-count 3
sudo -u zimbra zmbkposev3 --rotate-full-count 0 -a alice@example.comDelete backups older than a time expression while keeping restore consistency:
sudo -u zimbra zmbkposev3 -d 30dRestore one account from the latest full cycle and later incrementals:
sudo -u zimbra zmbkposev3 -r -a alice@example.comRestore all accounts found in WORKDIR:
sudo -u zimbra zmbkposev3 -rWhen -a is not specified, accounts are restored from backup storage in
domain/user A-Z order.
Restore from a specific file:
sudo -u zimbra zmbkposev3 -r --rf /path/to/20260904120000:FULL.tarRestore up to a point in time:
sudo -u zimbra zmbkposev3 -R 20260904180000 -a alice@example.comRestore behavior:
- if the account exists, missing messages are restored into it
- if the account does not exist, LDAP data is used to create it
- LDAP entries that already exist are not merged
- use
-uto continue with the next account after a restore failure
Start, stop, restart, and check status:
sudo /etc/init.d/zmbkposev3 start
sudo /etc/init.d/zmbkposev3 stop
sudo /etc/init.d/zmbkposev3 restart
sudo /etc/init.d/zmbkposev3 statusEnable at boot on Debian/Ubuntu:
sudo update-rc.d zmbkposev3 defaultsScheduler settings:
SCHEDULER_ENABLED=yes
FULL_BACKUP_TIME=00:00
INCREMENTAL_BACKUP_TIMES="06:00 09:00 18:00 21:00"
FULL_BACKUP_ARGS="-f"
INCREMENTAL_BACKUP_ARGS="-i -t"
BACKUP_RETRY_COUNT=3
BACKUP_RETRY_WAIT_SECONDS=300
MAILBOX_EXPORT_RETRY_COUNT=4
MAILBOX_EXPORT_RETRY_WAIT_SECONDS=3The scheduler reloads backup times and retry settings while it is running.
Restart is still recommended after changing service-level settings such as
SERVICE_USER, SCHEDULER_PID_FILE, or MAIN_LOG_FILE:
sudo /etc/init.d/zmbkposev3 restartTest a schedule match without waiting for the real time:
sudo -u zimbra env ZMBKPOSE_TEST_DATE=2026-09-07 ZMBKPOSE_TEST_HM=18:00 /usr/local/bin/zmbkposev3-main --run-once dueThe service checks Zimbra before start/restart:
CHECK_ZIMBRA_ON_SERVICE_START=yes
ZIMBRA_CONTROL=/opt/zimbra/bin/zmcontrolIf this scheduler is installed on a non-Zimbra backup host, set:
CHECK_ZIMBRA_ON_SERVICE_START=noScheduler markers are stored in SCHEDULER_STATE_DIR:
.runningwhile a scheduled job is active.doneonly after success.failedafter failure
Failed scheduled jobs retry according to BACKUP_RETRY_COUNT and
BACKUP_RETRY_WAIT_SECONDS.
Remote copy runs after a successful scheduled backup.
Choose the method:
REMOTE_COPY_ENABLED=yes
REMOTE_COPY_METHOD=rsyncor:
REMOTE_COPY_ENABLED=yes
REMOTE_COPY_METHOD=sftpRemote copy failures are logged, but they do not delete local backup files.
Example:
REMOTE_COPY_ENABLED=yes
REMOTE_COPY_METHOD=rsync
RSYNC_TARGET=backupuser@192.0.2.10:/backup/mailbackup-files/
RSYNC_OPTIONS="-a --partial --delay-updates"
RSYNC_DELETE=no
RSYNC_SSH_PORT=22
RSYNC_BWLIMIT=RSYNC_DELETE=yes adds --delete-after. Use it carefully because it can delete
remote files that no longer exist locally.
Example:
REMOTE_COPY_ENABLED=yes
REMOTE_COPY_METHOD=sftp
SFTP_TARGET=backupuser@192.0.2.10:/backup/mailbackup-files/
SFTP_PORT=22
SFTP_IDENTITY_FILE=/opt/zimbra/.ssh/zmbkposev3_sftp
SFTP_OPTIONS="-oBatchMode=yes -oStrictHostKeyChecking=accept-new"The username is in SFTP_TARGET. Passwords are not stored in the config.
For SFTP, use SSH key or passwordless login. During install, the script can
generate an SSH key for the service user. The private key stays on the mail
server. Copy the .pub key to the SFTP server user's authorized keys.
TrueNAS/FreeNAS example flow:
- Create a dataset or folder for backups.
- Create an SFTP user, for example
backupuser. - Give that user write permission to the backup dataset or folder.
- Enable/start the SSH service.
- Paste the generated public key into that user's SSH Authorized Keys field.
- Test login from the mail server:
sudo -u zimbra sftp -i /opt/zimbra/.ssh/zmbkposev3_sftp -P 22 backupuser@192.0.2.10The installer creates:
/var/log/zmbkpose
Log files:
/var/log/zmbkpose/zmbkpose-installation.log
/var/log/zmbkpose/zmbkpose-main.log
/var/log/zmbkpose/zmbkpose-backup.log
/var/log/zmbkpose/zmbkpose-restore.log
Backup CSV fields:
start_time,email,backup_location,backup_size,end_time,zmbkpose_command
Restore CSV fields:
start_time,email,backup_location,backup_size,end_time,zmbkpose_command,status
Passwords passed with --admpw or --ldappw are hidden in logged command
lines.
If an account backup fails:
- the incomplete backup tar is removed
LASTis not updated- no successful backup CSV line is written for that account
- scheduled remote copy does not run for that failed backup job
If a scheduled backup fails:
- the scheduler writes a
.failedmarker - it retries based on
BACKUP_RETRY_COUNT - it writes
.doneonly after success - the scheduler service keeps running
If SFTP or rsync remote copy fails:
- the error is logged in
zmbkpose-main.log - local backup files remain untouched
ERROR: You don't have "ldapsearch" command, or it is not in your PATH
Set or check:
EXTRA_COMMAND_PATHS="/opt/zimbra/bin:/opt/zimbra/common/bin:/opt/zimbra/openldap/bin:/opt/zimbra/postfix/sbin"Then restart the service:
sudo /etc/init.d/zmbkposev3 restartVERIFY: "...FULL.tar" contains an invalid mailbox.tgz
The mailbox export returned something that is not a valid tar-gzip mailbox archive. Common causes:
- wrong admin username or password
- unquoted password in
zmbkpose.conf, especially if it contains#,$, or spaces - Zimbra mailbox service is not running
- mailbox export URL failed
- proxy or certificate problem
- account/mailhost mismatch
Try a manual backup for one account. Manual runs print the details to the
terminal. Scheduled runs write the same details to zmbkpose-main.log.
Newer versions log the HTTP status, content type, download size, and the first
line of the invalid response:
sudo -u zimbra zmbkposev3 -f -a alice@example.com
tail -100 /var/log/zmbkpose/zmbkpose-main.loghttp_code=204 size_download=0 means Zimbra returned no mailbox content. This
can happen for an empty mailbox or an incremental backup where no messages match
the time query. Zmbkpose v3 treats this as a successful empty mailbox export and
creates a valid empty mailbox.tgz.
Incremental schedule does not run
Check what the scheduler loaded:
tail -100 /var/log/zmbkpose/zmbkpose-main.logYou should see a line similar to:
INFO: Loaded scheduler config: enabled=yes full=00:00 incremental="06:00 09:00 18:00 21:00"
If the config was edited recently, restart the service or wait up to
SCHEDULER_SLEEP_SECONDS for the scheduler to reload it:
sudo /etc/init.d/zmbkposev3 restartRemove service and program files:
sudo zmbkposev3-uninstallRemove service, program files, config, logs, state files, and configured SFTP key:
sudo zmbkposev3-uninstall --purge-allBackup files in WORKDIR are never removed by the uninstaller.
- Do not commit real
zmbkpose.conffiles containing passwords. - Keep
/etc/zmbkposev3/zmbkpose.confreadable only by trusted users. - Keep SFTP private keys on the mail server only.
- Copy only
.pubkeys to remote backup servers. - Protect backup storage because mailbox archives contain user mail.
This project is distributed under the GNU General Public License. See
COPYING for details.