2019-05-10 15:41:24 +02:00
#!/usr/bin/env bash
2018-01-12 09:30:54 +02:00
2022-11-22 19:38:38 +02:00
DEBIAN_DOCKER_IMAGE = "mailcow/backup:latest"
2020-04-18 20:13:38 +02:00
2018-10-15 11:37:10 +02:00
if [ [ ! -z ${ MAILCOW_BACKUP_LOCATION } ] ] ; then
BACKUP_LOCATION = " ${ MAILCOW_BACKUP_LOCATION } "
fi
2018-01-12 09:30:54 +02:00
if [ [ ! ${ 1 } = ~ ( backup| restore) ] ] ; then
echo "First parameter needs to be 'backup' or 'restore'"
exit 1
fi
2019-10-23 21:41:19 +02:00
if [ [ ${ 1 } = = "backup" && ! ${ 2 } = ~ ( crypt| vmail| redis| rspamd| postfix| mysql| all| --delete-days) ] ] ; then
echo "Second parameter needs to be 'vmail', 'crypt', 'redis', 'rspamd', 'postfix', 'mysql', 'all' or '--delete-days'"
2018-01-12 09:30:54 +02:00
exit 1
fi
if [ [ -z ${ BACKUP_LOCATION } ] ] ; then
while [ [ -z ${ BACKUP_LOCATION } ] ] ; do
read -ep "Backup location (absolute path, starting with /): " BACKUP_LOCATION
done
fi
if [ [ ! ${ BACKUP_LOCATION } = ~ ^/ ] ] ; then
echo "Backup directory needs to be given as absolute path (starting with /)."
exit 1
fi
if [ [ -f ${ BACKUP_LOCATION } ] ] ; then
echo " ${ BACKUP_LOCATION } is a file! "
exit 1
fi
if [ [ ! -d ${ BACKUP_LOCATION } ] ] ; then
echo " ${ BACKUP_LOCATION } is not a directory "
read -p "Create it now? [y|N] " CREATE_BACKUP_LOCATION
if [ [ ! ${ CREATE_BACKUP_LOCATION ,, } = ~ ^( yes| y) $ ] ] ; then
exit 1
else
2019-02-08 19:11:46 +02:00
mkdir -p ${ BACKUP_LOCATION }
2018-01-12 09:30:54 +02:00
chmod 755 ${ BACKUP_LOCATION }
fi
else
if [ [ ${ 1 } = = "backup" ] ] && [ [ -z $( echo $( stat -Lc %a ${ BACKUP_LOCATION } ) | grep -oE '[0-9][0-9][5-7]' ) ] ] ; then
echo " ${ BACKUP_LOCATION } is not write-able for others, that's required for a backup. "
exit 1
fi
fi
2020-03-28 20:50:15 +02:00
2018-01-12 09:30:54 +02:00
BACKUP_LOCATION = $( echo ${ BACKUP_LOCATION } | sed 's#/$##' )
SCRIPT_DIR = " $( cd " $( dirname " ${ BASH_SOURCE [0] } " ) " && pwd ) "
COMPOSE_FILE = ${ SCRIPT_DIR } /../docker-compose.yml
2020-10-03 11:11:48 +02:00
ENV_FILE = ${ SCRIPT_DIR } /../.env
2022-10-21 11:48:29 +02:00
THREADS = $( echo ${ THREADS :- 1 } )
2023-04-26 10:37:20 +02:00
ARCH = $( uname -m)
2022-10-21 11:48:29 +02:00
2024-01-09 23:03:24 +02:00
if ! [ [ " ${ THREADS } " = ~ ^[ 1-9] [ 0-9] ?$ ] ] ; then
2022-10-25 09:55:29 +02:00
echo "Thread input is not a number!"
exit 1
2024-01-09 23:03:24 +02:00
elif [ [ " ${ THREADS } " = ~ ^[ 1-9] [ 0-9] ?$ ] ] ; then
2022-11-22 19:38:38 +02:00
echo " Using ${ THREADS } Thread(s) for this run. "
2022-10-25 09:55:29 +02:00
echo "Notice: You can set the Thread count with the THREADS Variable before you run this script."
fi
2020-03-28 20:50:15 +02:00
if [ ! -f ${ COMPOSE_FILE } ] ; then
echo "Compose file not found"
exit 1
fi
2020-10-03 11:11:48 +02:00
if [ ! -f ${ ENV_FILE } ] ; then
echo "Environment file not found"
exit 1
fi
2018-01-12 09:30:54 +02:00
echo " Using ${ BACKUP_LOCATION } as backup/restore location. "
echo
2020-03-28 20:50:15 +02:00
2018-01-12 09:30:54 +02:00
source ${ SCRIPT_DIR } /../mailcow.conf
2020-03-28 20:50:15 +02:00
if [ [ -z ${ COMPOSE_PROJECT_NAME } ] ] ; then
echo "Could not determine compose project name"
exit 1
else
echo " Found project name ${ COMPOSE_PROJECT_NAME } "
2020-03-29 10:45:27 +02:00
CMPS_PRJ = $( echo ${ COMPOSE_PROJECT_NAME } | tr -cd "[0-9A-Za-z-_]" )
2020-03-28 20:50:15 +02:00
fi
2018-01-12 09:30:54 +02:00
2022-06-07 08:53:08 +02:00
if grep --help 2>& 1 | head -n 1 | grep -q -i "busybox" ; then
>& 2 echo -e "\e[31mBusyBox grep detected on local system, please install GNU grep\e[0m"
exit 1
fi
2018-01-12 09:30:54 +02:00
function backup( ) {
DATE = $( date +"%Y-%m-%d-%H-%M-%S" )
mkdir -p " ${ BACKUP_LOCATION } /mailcow- ${ DATE } "
chmod 755 " ${ BACKUP_LOCATION } /mailcow- ${ DATE } "
2018-07-29 14:27:51 +02:00
cp " ${ SCRIPT_DIR } /../mailcow.conf " " ${ BACKUP_LOCATION } /mailcow- ${ DATE } "
2023-04-26 10:37:20 +02:00
touch " ${ BACKUP_LOCATION } /mailcow- ${ DATE } /. $ARCH "
2022-07-08 13:29:05 +02:00
for bin in docker; do
if [ [ -z $( which ${ bin } ) ] ] ; then
>& 2 echo -e " \e[31mCannot find ${ bin } in local PATH, exiting...\e[0m "
exit 1
fi
done
2018-01-12 09:30:54 +02:00
while ( ( " $# " ) ) ; do
case " $1 " in
vmail| all)
2020-04-14 14:20:05 +02:00
docker run --name mailcow-backup --rm \
2020-12-06 10:29:25 +02:00
-v ${ BACKUP_LOCATION } /mailcow-${ DATE } :/backup:z \
2021-05-16 08:19:52 +02:00
-v $( docker volume ls -qf name = ^${ CMPS_PRJ } _vmail-vol-1$) :/vmail:ro,z \
2022-10-19 11:15:12 +02:00
${ DEBIAN_DOCKER_IMAGE } /bin/tar --warning= 'no-file-ignored' --use-compress-program= " pigz --rsyncable -p ${ THREADS } " -Pcvpf /backup/backup_vmail.tar.gz /vmail
2018-01-12 09:30:54 +02:00
; ; &
[Docker API] Use TLS encryption for communication with "on-the-fly" created key paris (non-exposed)
[Docker API] Create pipe to pass Rspamd UI worker password
[Dovecot] Pull Spamassassin ruleset to be read by Rspamd (MANY THANKS to Peer Heinlein!)
[Dovecot] Garbage collector for deleted maildirs (set keep time via MAILDIR_GC_TIME which defaults to 1440 minutes)
[Web] Flush memcached after mailbox item changes, fixes #1808
[Web] Fix duplicate IDs, fixes #1792
[Compose] Use SQL sockets
[PHP-FPM] Update APCu and Redis libs
[Dovecot] Encrypt maildir with global key pair in crypt-vol-1 (BACKUP!), also fixes #1791
[Web] Fix deletion of spam aliases
[Helper] Add "crypt" to backup script
[Helper] Override file for external SQL socket (not supported!)
[Compose] New images for Rspamd, PHP-FPM, SOGo, Dovecot, Docker API, Watchdog, ACME, Postfix
2018-09-29 22:01:23 +02:00
crypt| all)
2020-04-14 14:20:05 +02:00
docker run --name mailcow-backup --rm \
2020-12-06 10:29:25 +02:00
-v ${ BACKUP_LOCATION } /mailcow-${ DATE } :/backup:z \
2021-05-16 08:19:52 +02:00
-v $( docker volume ls -qf name = ^${ CMPS_PRJ } _crypt-vol-1$) :/crypt:ro,z \
2022-10-19 11:15:12 +02:00
${ DEBIAN_DOCKER_IMAGE } /bin/tar --warning= 'no-file-ignored' --use-compress-program= " pigz --rsyncable -p ${ THREADS } " -Pcvpf /backup/backup_crypt.tar.gz /crypt
[Docker API] Use TLS encryption for communication with "on-the-fly" created key paris (non-exposed)
[Docker API] Create pipe to pass Rspamd UI worker password
[Dovecot] Pull Spamassassin ruleset to be read by Rspamd (MANY THANKS to Peer Heinlein!)
[Dovecot] Garbage collector for deleted maildirs (set keep time via MAILDIR_GC_TIME which defaults to 1440 minutes)
[Web] Flush memcached after mailbox item changes, fixes #1808
[Web] Fix duplicate IDs, fixes #1792
[Compose] Use SQL sockets
[PHP-FPM] Update APCu and Redis libs
[Dovecot] Encrypt maildir with global key pair in crypt-vol-1 (BACKUP!), also fixes #1791
[Web] Fix deletion of spam aliases
[Helper] Add "crypt" to backup script
[Helper] Override file for external SQL socket (not supported!)
[Compose] New images for Rspamd, PHP-FPM, SOGo, Dovecot, Docker API, Watchdog, ACME, Postfix
2018-09-29 22:01:23 +02:00
; ; &
2018-01-12 09:30:54 +02:00
redis| all)
2018-01-14 21:53:26 +02:00
docker exec $( docker ps -qf name = redis-mailcow) redis-cli save
2020-04-14 14:20:05 +02:00
docker run --name mailcow-backup --rm \
2020-12-06 10:29:25 +02:00
-v ${ BACKUP_LOCATION } /mailcow-${ DATE } :/backup:z \
2021-05-16 08:19:52 +02:00
-v $( docker volume ls -qf name = ^${ CMPS_PRJ } _redis-vol-1$) :/redis:ro,z \
2022-10-19 11:15:12 +02:00
${ DEBIAN_DOCKER_IMAGE } /bin/tar --warning= 'no-file-ignored' --use-compress-program= " pigz --rsyncable -p ${ THREADS } " -Pcvpf /backup/backup_redis.tar.gz /redis
2018-01-12 09:30:54 +02:00
; ; &
rspamd| all)
2020-04-14 14:20:05 +02:00
docker run --name mailcow-backup --rm \
2020-12-06 10:29:25 +02:00
-v ${ BACKUP_LOCATION } /mailcow-${ DATE } :/backup:z \
2021-05-16 08:19:52 +02:00
-v $( docker volume ls -qf name = ^${ CMPS_PRJ } _rspamd-vol-1$) :/rspamd:ro,z \
2022-10-19 11:15:12 +02:00
${ DEBIAN_DOCKER_IMAGE } /bin/tar --warning= 'no-file-ignored' --use-compress-program= " pigz --rsyncable -p ${ THREADS } " -Pcvpf /backup/backup_rspamd.tar.gz /rspamd
2018-01-12 09:30:54 +02:00
; ; &
postfix| all)
2020-04-14 14:20:05 +02:00
docker run --name mailcow-backup --rm \
2020-12-06 10:29:25 +02:00
-v ${ BACKUP_LOCATION } /mailcow-${ DATE } :/backup:z \
2021-05-16 08:19:52 +02:00
-v $( docker volume ls -qf name = ^${ CMPS_PRJ } _postfix-vol-1$) :/postfix:ro,z \
2022-10-19 11:15:12 +02:00
${ DEBIAN_DOCKER_IMAGE } /bin/tar --warning= 'no-file-ignored' --use-compress-program= " pigz --rsyncable -p ${ THREADS } " -Pcvpf /backup/backup_postfix.tar.gz /postfix
2018-01-12 09:30:54 +02:00
; ; &
mysql| all)
SQLIMAGE = $( grep -iEo '(mysql|mariadb)\:.+' ${ COMPOSE_FILE } )
2020-03-28 20:50:15 +02:00
if [ [ -z " ${ SQLIMAGE } " ] ] ; then
echo "Could not determine SQL image version, skipping backup..."
shift
continue
else
echo " Using SQL image ${ SQLIMAGE } , starting... "
2020-04-14 14:20:05 +02:00
docker run --name mailcow-backup --rm \
2021-05-16 08:19:52 +02:00
--network $( docker network ls -qf name = ^${ CMPS_PRJ } _mailcow-network$) \
-v $( docker volume ls -qf name = ^${ CMPS_PRJ } _mysql-vol-1$) :/var/lib/mysql/:ro,z \
2021-04-20 21:24:31 +02:00
-t --entrypoint= \
2021-01-01 00:26:03 +02:00
--sysctl net.ipv6.conf.all.disable_ipv6= 1 \
2020-12-06 10:29:25 +02:00
-v ${ BACKUP_LOCATION } /mailcow-${ DATE } :/backup:z \
2020-04-06 18:46:31 +02:00
${ SQLIMAGE } /bin/sh -c " mariabackup --host mysql --user root --password ${ DBROOT } --backup --rsync --target-dir=/backup_mariadb ; \
mariabackup --prepare --target-dir= /backup_mariadb ; \
2020-11-04 11:17:59 +02:00
chown -R 999:999 /backup_mariadb ; \
2020-06-26 22:09:43 +02:00
/bin/tar --warning= 'no-file-ignored' --use-compress-program= 'gzip --rsyncable' -Pcvpf /backup/backup_mariadb.tar.gz /backup_mariadb ; "
2020-03-28 20:50:15 +02:00
fi
2019-10-23 21:41:19 +02:00
; ; &
--delete-days)
shift
if [ [ " ${ 1 } " = ~ ^[ 0-9] +$ ] ] ; then
2020-06-15 07:28:42 +02:00
find ${ BACKUP_LOCATION } /mailcow-* -maxdepth 0 -mmin +$(( ${ 1 } * 60 * 24 )) -exec rm -rvf { } \;
2019-10-23 21:41:19 +02:00
else
echo "Parameter of --delete-days is not a number."
fi
2018-01-12 09:30:54 +02:00
; ;
esac
shift
done
}
function restore( ) {
2022-08-22 10:24:38 +02:00
for bin in docker; do
2022-07-08 13:29:05 +02:00
if [ [ -z $( which ${ bin } ) ] ] ; then
>& 2 echo -e " \e[31mCannot find ${ bin } in local PATH, exiting...\e[0m "
exit 1
fi
2022-08-22 10:24:38 +02:00
done
if [ " ${ DOCKER_COMPOSE_VERSION } " = = "native" ] ; then
COMPOSE_COMMAND = "docker compose"
elif [ " ${ DOCKER_COMPOSE_VERSION } " = = "standalone" ] ; then
COMPOSE_COMMAND = "docker-compose"
2022-11-22 19:38:38 +02:00
2022-08-22 10:24:38 +02:00
else
echo -e "\e[31mCan not read DOCKER_COMPOSE_VERSION variable from mailcow.conf! Is your mailcow up to date? Exiting...\e[0m"
exit 1
fi
2020-03-28 20:50:15 +02:00
echo
echo "Stopping watchdog-mailcow..."
2018-01-12 09:30:54 +02:00
docker stop $( docker ps -qf name = watchdog-mailcow)
2020-03-28 20:50:15 +02:00
echo
2018-01-12 09:30:54 +02:00
RESTORE_LOCATION = " ${ 1 } "
shift
while ( ( " $# " ) ) ; do
case " $1 " in
vmail)
docker stop $( docker ps -qf name = dovecot-mailcow)
2020-04-14 14:20:05 +02:00
docker run -it --name mailcow-backup --rm \
2020-12-06 10:29:25 +02:00
-v ${ RESTORE_LOCATION } :/backup:z \
2021-05-16 08:19:52 +02:00
-v $( docker volume ls -qf name = ^${ CMPS_PRJ } _vmail-vol-1$) :/vmail:z \
2022-10-25 10:06:53 +02:00
${ DEBIAN_DOCKER_IMAGE } /bin/tar --use-compress-program= " pigz -d -p ${ THREADS } " -Pxvf /backup/backup_vmail.tar.gz
2018-01-12 09:30:54 +02:00
docker start $( docker ps -aqf name = dovecot-mailcow)
echo
echo "In most cases it is not required to run a full resync, you can run the command printed below at any time after testing wether the restore process broke a mailbox:"
echo
echo " docker exec $( docker ps -qf name = dovecot-mailcow) doveadm force-resync -A '*' "
echo
read -p "Force a resync now? [y|N] " FORCE_RESYNC
if [ [ ${ FORCE_RESYNC ,, } = ~ ^( yes| y) $ ] ] ; then
docker exec $( docker ps -qf name = dovecot-mailcow) doveadm force-resync -A '*'
else
echo "OK, skipped."
fi
; ;
redis)
docker stop $( docker ps -qf name = redis-mailcow)
2020-04-14 14:20:05 +02:00
docker run -it --name mailcow-backup --rm \
2020-12-06 10:29:25 +02:00
-v ${ RESTORE_LOCATION } :/backup:z \
2021-05-16 08:19:52 +02:00
-v $( docker volume ls -qf name = ^${ CMPS_PRJ } _redis-vol-1$) :/redis:z \
2022-10-25 10:06:53 +02:00
${ DEBIAN_DOCKER_IMAGE } /bin/tar --use-compress-program= " pigz -d -p ${ THREADS } " -Pxvf /backup/backup_redis.tar.gz
2018-01-12 09:30:54 +02:00
docker start $( docker ps -aqf name = redis-mailcow)
; ;
[Docker API] Use TLS encryption for communication with "on-the-fly" created key paris (non-exposed)
[Docker API] Create pipe to pass Rspamd UI worker password
[Dovecot] Pull Spamassassin ruleset to be read by Rspamd (MANY THANKS to Peer Heinlein!)
[Dovecot] Garbage collector for deleted maildirs (set keep time via MAILDIR_GC_TIME which defaults to 1440 minutes)
[Web] Flush memcached after mailbox item changes, fixes #1808
[Web] Fix duplicate IDs, fixes #1792
[Compose] Use SQL sockets
[PHP-FPM] Update APCu and Redis libs
[Dovecot] Encrypt maildir with global key pair in crypt-vol-1 (BACKUP!), also fixes #1791
[Web] Fix deletion of spam aliases
[Helper] Add "crypt" to backup script
[Helper] Override file for external SQL socket (not supported!)
[Compose] New images for Rspamd, PHP-FPM, SOGo, Dovecot, Docker API, Watchdog, ACME, Postfix
2018-09-29 22:01:23 +02:00
crypt)
docker stop $( docker ps -qf name = dovecot-mailcow)
2020-04-14 14:20:05 +02:00
docker run -it --name mailcow-backup --rm \
2020-12-06 10:29:25 +02:00
-v ${ RESTORE_LOCATION } :/backup:z \
2021-05-16 08:19:52 +02:00
-v $( docker volume ls -qf name = ^${ CMPS_PRJ } _crypt-vol-1$) :/crypt:z \
2022-10-25 10:06:53 +02:00
${ DEBIAN_DOCKER_IMAGE } /bin/tar --use-compress-program= " pigz -d -p ${ THREADS } " -Pxvf /backup/backup_crypt.tar.gz
[Docker API] Use TLS encryption for communication with "on-the-fly" created key paris (non-exposed)
[Docker API] Create pipe to pass Rspamd UI worker password
[Dovecot] Pull Spamassassin ruleset to be read by Rspamd (MANY THANKS to Peer Heinlein!)
[Dovecot] Garbage collector for deleted maildirs (set keep time via MAILDIR_GC_TIME which defaults to 1440 minutes)
[Web] Flush memcached after mailbox item changes, fixes #1808
[Web] Fix duplicate IDs, fixes #1792
[Compose] Use SQL sockets
[PHP-FPM] Update APCu and Redis libs
[Dovecot] Encrypt maildir with global key pair in crypt-vol-1 (BACKUP!), also fixes #1791
[Web] Fix deletion of spam aliases
[Helper] Add "crypt" to backup script
[Helper] Override file for external SQL socket (not supported!)
[Compose] New images for Rspamd, PHP-FPM, SOGo, Dovecot, Docker API, Watchdog, ACME, Postfix
2018-09-29 22:01:23 +02:00
docker start $( docker ps -aqf name = dovecot-mailcow)
; ;
2018-01-12 09:30:54 +02:00
rspamd)
2023-04-26 10:37:20 +02:00
if [ [ $( find " ${ RESTORE_LOCATION } " \( -name '*x86*' -o -name '*aarch*' \) -exec basename { } \; | sed 's/^\.//' | sed 's/^\.//' ) = = "" ] ] ; then
echo -e "\e[33mCould not find a architecture signature of the loaded backup... Maybe the backup was done before the multiarch update?"
sleep 2
echo -e " Continuing anyhow. If rspamd is crashing opon boot try remove the rspamd volume with docker volume rm ${ CMPS_PRJ } _rspamd-vol-1 after you've stopped the stack.\e[0m "
sleep 2
docker stop $( docker ps -qf name = rspamd-mailcow)
docker run -it --name mailcow-backup --rm \
-v ${ RESTORE_LOCATION } :/backup:z \
-v $( docker volume ls -qf name = ^${ CMPS_PRJ } _rspamd-vol-1$) :/rspamd:z \
${ DEBIAN_DOCKER_IMAGE } /bin/tar --use-compress-program= " pigz -d -p ${ THREADS } " -Pxvf /backup/backup_rspamd.tar.gz
docker start $( docker ps -aqf name = rspamd-mailcow)
elif [ [ $ARCH != $( find " ${ RESTORE_LOCATION } " \( -name '*x86*' -o -name '*aarch*' \) -exec basename { } \; | sed 's/^\.//' | sed 's/^\.//' ) ] ] ; then
echo -e "\e[31mThe Architecture of the backed up mailcow OS is different then your restoring mailcow OS..."
sleep 2
echo -e "Skipping rspamd due to compatibility issues!\e[0m"
else
docker stop $( docker ps -qf name = rspamd-mailcow)
docker run -it --name mailcow-backup --rm \
-v ${ RESTORE_LOCATION } :/backup:z \
-v $( docker volume ls -qf name = ^${ CMPS_PRJ } _rspamd-vol-1$) :/rspamd:z \
${ DEBIAN_DOCKER_IMAGE } /bin/tar --use-compress-program= " pigz -d -p ${ THREADS } " -Pxvf /backup/backup_rspamd.tar.gz
docker start $( docker ps -aqf name = rspamd-mailcow)
fi
2018-01-12 09:30:54 +02:00
; ;
postfix)
docker stop $( docker ps -qf name = postfix-mailcow)
2020-04-14 14:20:05 +02:00
docker run -it --name mailcow-backup --rm \
2020-12-06 10:29:25 +02:00
-v ${ RESTORE_LOCATION } :/backup:z \
2021-05-16 08:19:52 +02:00
-v $( docker volume ls -qf name = ^${ CMPS_PRJ } _postfix-vol-1$) :/postfix:z \
2022-10-25 10:06:53 +02:00
${ DEBIAN_DOCKER_IMAGE } /bin/tar --use-compress-program= " pigz -d -p ${ THREADS } " -Pxvf /backup/backup_postfix.tar.gz
2018-01-12 09:30:54 +02:00
docker start $( docker ps -aqf name = postfix-mailcow)
; ;
2020-06-03 08:22:55 +02:00
mysql| mariadb)
2018-01-12 09:30:54 +02:00
SQLIMAGE = $( grep -iEo '(mysql|mariadb)\:.+' ${ COMPOSE_FILE } )
2020-03-29 15:50:29 +02:00
if [ [ -z " ${ SQLIMAGE } " ] ] ; then
echo "Could not determine SQL image version, skipping restore..."
2020-03-28 20:50:15 +02:00
shift
continue
2020-03-29 15:50:29 +02:00
elif [ ! -f " ${ RESTORE_LOCATION } /mailcow.conf " ] ; then
echo " Could not find the corresponding mailcow.conf in ${ RESTORE_LOCATION } , skipping restore. "
echo " If you lost that file, copy the last working mailcow.conf file to ${ RESTORE_LOCATION } and restart the restore process. "
shift
continue
else
read -p " mailcow will be stopped and the currently active mailcow.conf will be modified to use the DB parameters found in ${ RESTORE_LOCATION } /mailcow.conf - do you want to proceed? [Y|n] " MYSQL_STOP_MAILCOW
if [ [ ${ MYSQL_STOP_MAILCOW ,, } = ~ ^( no| n| N) $ ] ] ; then
echo "OK, skipped."
shift
continue
else
echo "Stopping mailcow..."
2022-08-22 10:24:38 +02:00
${ COMPOSE_COMMAND } -f ${ COMPOSE_FILE } --env-file ${ ENV_FILE } down
2020-03-29 15:50:29 +02:00
fi
#docker stop $(docker ps -qf name=mysql-mailcow)
if [ [ -d " ${ RESTORE_LOCATION } /mysql " ] ] ; then
2020-04-14 14:20:05 +02:00
docker run --name mailcow-backup --rm \
2021-05-16 08:19:52 +02:00
-v $( docker volume ls -qf name = ^${ CMPS_PRJ } _mysql-vol-1$) :/var/lib/mysql/:rw,z \
2020-03-29 15:50:29 +02:00
--entrypoint= \
2020-12-06 10:29:25 +02:00
-v ${ RESTORE_LOCATION } /mysql:/backup:z \
2020-03-29 15:50:29 +02:00
${ SQLIMAGE } /bin/bash -c "shopt -s dotglob ; /bin/rm -rf /var/lib/mysql/* ; rsync -avh --usermap=root:mysql --groupmap=root:mysql /backup/ /var/lib/mysql/"
elif [ [ -f " ${ RESTORE_LOCATION } /backup_mysql.gz " ] ] ; then
docker run \
2020-04-14 14:20:05 +02:00
-it --name mailcow-backup --rm \
2021-05-16 08:19:52 +02:00
-v $( docker volume ls -qf name = ^${ CMPS_PRJ } _mysql-vol-1$) :/var/lib/mysql/:z \
2020-03-29 15:50:29 +02:00
--entrypoint= \
-u mysql \
2020-12-06 10:29:25 +02:00
-v ${ RESTORE_LOCATION } :/backup:z \
2020-03-29 15:50:29 +02:00
${ SQLIMAGE } /bin/sh -c " mysqld --skip-grant-tables & \
until mysqladmin ping; do sleep 3; done && \
echo Restoring... && \
gunzip < backup/backup_mysql.gz | mysql -uroot && \
mysql -uroot -e SHUTDOWN; "
2020-04-06 18:46:31 +02:00
elif [ [ -f " ${ RESTORE_LOCATION } /backup_mariadb.tar.gz " ] ] ; then
2020-04-14 14:20:05 +02:00
docker run --name mailcow-backup --rm \
2021-05-16 08:19:52 +02:00
-v $( docker volume ls -qf name = ^${ CMPS_PRJ } _mysql-vol-1$) :/backup_mariadb/:rw,z \
2020-04-06 18:46:31 +02:00
--entrypoint= \
2020-12-06 10:29:25 +02:00
-v ${ RESTORE_LOCATION } :/backup:z \
2020-04-06 18:46:31 +02:00
${ SQLIMAGE } /bin/bash -c " shopt -s dotglob ; \
/bin/rm -rf /backup_mariadb/* ; \
2020-04-13 21:35:20 +02:00
/bin/tar -Pxvzf /backup/backup_mariadb.tar.gz"
2020-03-29 15:50:29 +02:00
fi
echo "Modifying mailcow.conf..."
source ${ RESTORE_LOCATION } /mailcow.conf
2020-09-20 22:07:37 +02:00
sed -i --follow-symlinks " /DBNAME/c\DBNAME= ${ DBNAME } " ${ SCRIPT_DIR } /../mailcow.conf
sed -i --follow-symlinks " /DBUSER/c\DBUSER= ${ DBUSER } " ${ SCRIPT_DIR } /../mailcow.conf
sed -i --follow-symlinks " /DBPASS/c\DBPASS= ${ DBPASS } " ${ SCRIPT_DIR } /../mailcow.conf
sed -i --follow-symlinks " /DBROOT/c\DBROOT= ${ DBROOT } " ${ SCRIPT_DIR } /../mailcow.conf
2020-03-29 15:50:29 +02:00
source ${ SCRIPT_DIR } /../mailcow.conf
echo "Starting mailcow..."
2022-08-22 10:24:38 +02:00
${ COMPOSE_COMMAND } -f ${ COMPOSE_FILE } --env-file ${ ENV_FILE } up -d
2020-03-29 15:50:29 +02:00
#docker start $(docker ps -aqf name=mysql-mailcow)
2020-03-28 20:50:15 +02:00
fi
2018-01-12 09:30:54 +02:00
; ;
esac
shift
done
2020-03-28 20:50:15 +02:00
echo
echo "Starting watchdog-mailcow..."
2018-01-12 09:30:54 +02:00
docker start $( docker ps -aqf name = watchdog-mailcow)
}
if [ [ ${ 1 } = = "backup" ] ] ; then
backup ${ @,, }
elif [ [ ${ 1 } = = "restore" ] ] ; then
i = 1
declare -A FOLDER_SELECTION
if [ [ $( find ${ BACKUP_LOCATION } /mailcow-* -maxdepth 1 -type d 2> /dev/null| wc -l) -lt 1 ] ] ; then
echo "Selected backup location has no subfolders"
exit 1
fi
for folder in $( ls -d ${ BACKUP_LOCATION } /mailcow-*/) ; do
echo " [ ${ i } ] - ${ folder } "
FOLDER_SELECTION[ ${ i } ] = " ${ folder } "
( ( i++) )
done
echo
input_sel = 0
while [ [ ${ input_sel } -lt 1 || ${ input_sel } -gt ${ i } ] ] ; do
read -p "Select a restore point: " input_sel
done
i = 1
echo
declare -A FILE_SELECTION
RESTORE_POINT = " ${ FOLDER_SELECTION [ ${ input_sel } ] } "
2020-04-19 09:56:56 +02:00
if [ [ -z $( find " ${ FOLDER_SELECTION [ ${ input_sel } ] } " -maxdepth 1 \( -type d -o -type f \) -regex ".*\(redis\|rspamd\|mariadb\|mysql\|crypt\|vmail\|postfix\).*" ) ] ] ; then
2018-01-12 09:30:54 +02:00
echo "No datasets found"
exit 1
fi
2019-09-08 10:54:21 +02:00
2019-11-14 10:35:57 +02:00
echo "[ 0 ] - all"
# find all files in folder with *.gz extension, print their base names, remove backup_, remove .tar (if present), remove .gz
2020-04-19 09:56:56 +02:00
FILE_SELECTION[ 0] = $( find " ${ FOLDER_SELECTION [ ${ input_sel } ] } " -maxdepth 1 \( -type d -o -type f \) \( -name '*.gz' -o -name 'mysql' \) -printf '%f\n' | sed 's/backup_*//' | sed 's/\.[^.]*$//' | sed 's/\.[^.]*$//' )
2018-01-12 09:30:54 +02:00
for file in $( ls -f " ${ FOLDER_SELECTION [ ${ input_sel } ] } " ) ; do
if [ [ ${ file } = ~ vmail ] ] ; then
echo " [ ${ i } ] - Mail directory (/var/vmail) "
FILE_SELECTION[ ${ i } ] = "vmail"
( ( i++) )
[Docker API] Use TLS encryption for communication with "on-the-fly" created key paris (non-exposed)
[Docker API] Create pipe to pass Rspamd UI worker password
[Dovecot] Pull Spamassassin ruleset to be read by Rspamd (MANY THANKS to Peer Heinlein!)
[Dovecot] Garbage collector for deleted maildirs (set keep time via MAILDIR_GC_TIME which defaults to 1440 minutes)
[Web] Flush memcached after mailbox item changes, fixes #1808
[Web] Fix duplicate IDs, fixes #1792
[Compose] Use SQL sockets
[PHP-FPM] Update APCu and Redis libs
[Dovecot] Encrypt maildir with global key pair in crypt-vol-1 (BACKUP!), also fixes #1791
[Web] Fix deletion of spam aliases
[Helper] Add "crypt" to backup script
[Helper] Override file for external SQL socket (not supported!)
[Compose] New images for Rspamd, PHP-FPM, SOGo, Dovecot, Docker API, Watchdog, ACME, Postfix
2018-09-29 22:01:23 +02:00
elif [ [ ${ file } = ~ crypt ] ] ; then
echo " [ ${ i } ] - Crypt data "
FILE_SELECTION[ ${ i } ] = "crypt"
( ( i++) )
2018-01-12 09:30:54 +02:00
elif [ [ ${ file } = ~ redis ] ] ; then
echo " [ ${ i } ] - Redis DB "
FILE_SELECTION[ ${ i } ] = "redis"
( ( i++) )
elif [ [ ${ file } = ~ rspamd ] ] ; then
2023-04-26 10:37:20 +02:00
if [ [ $( find " ${ FOLDER_SELECTION [ ${ input_sel } ] } " \( -name '*x86*' -o -name '*aarch*' \) -exec basename { } \; | sed 's/^\.//' | sed 's/^\.//' ) = = "" ] ] ; then
echo " [ ${ i } ] - Rspamd data (unkown Arch detected, restore with caution!) "
FILE_SELECTION[ ${ i } ] = "rspamd"
( ( i++) )
elif [ [ $ARCH != $( find " ${ FOLDER_SELECTION [ ${ input_sel } ] } " \( -name '*x86*' -o -name '*aarch*' \) -exec basename { } \; | sed 's/^\.//' | sed 's/^\.//' ) ] ] ; then
echo -e "\e[31m[ NaN ] - Rspamd data (incompatible Arch, cannot restore it)\e[0m"
else
echo " [ ${ i } ] - Rspamd data "
FILE_SELECTION[ ${ i } ] = "rspamd"
( ( i++) )
fi
2018-01-12 09:30:54 +02:00
elif [ [ ${ file } = ~ postfix ] ] ; then
echo " [ ${ i } ] - Postfix data "
FILE_SELECTION[ ${ i } ] = "postfix"
( ( i++) )
2020-04-06 18:46:31 +02:00
elif [ [ ${ file } = ~ mysql ] ] || [ [ ${ file } = ~ mariadb ] ] ; then
2018-01-12 09:30:54 +02:00
echo " [ ${ i } ] - SQL DB "
FILE_SELECTION[ ${ i } ] = "mysql"
( ( i++) )
fi
done
echo
2019-09-08 12:21:12 +02:00
input_sel = -1
2019-09-08 10:54:21 +02:00
while [ [ ${ input_sel } -lt 0 || ${ input_sel } -gt ${ i } ] ] ; do
2018-01-12 09:30:54 +02:00
read -p "Select a dataset to restore: " input_sel
done
echo " Restoring ${ FILE_SELECTION [ ${ input_sel } ] } from ${ RESTORE_POINT } ... "
restore " ${ RESTORE_POINT } " ${ FILE_SELECTION [ ${ input_sel } ] }
2022-11-22 19:38:38 +02:00
fi