11 Commits

Author SHA1 Message Date
Asif Bacchus 1334975cab fix(BACKUP): fix colour var usage
SQL dump success and REDIS dump success msg printed 'cyan' instead of
using the colour var
2021-03-08 00:50:55 -07:00
Asif Bacchus 19d1eb1587 refactor(BACKUP): prevent alias cmds
- prefix cp and cd with \ to prevent alias cmd
- fix typo in comment
2021-03-08 00:40:11 -07:00
Asif Bacchus 4aae61f97e feature(BACKUP): allow non-default borg location
- parameter to specify non-default borg program location

Closes github #10
2021-03-08 00:36:32 -07:00
Asif Bacchus 5ea25529b9 feature(BACKUP): add SSH port customization
- borgSSHPort variable in details file
- read and appended to RSH connection string
- default to standard port 22

Closes github #9
2021-03-08 00:08:22 -07:00
Asif Bacchus de76918e81 feature(BACKUP): parameterize log colourization
Closes github #9
2021-03-07 23:54:32 -07:00
Asif Bacchus 16f4c11f91 fix(BACKUP): remove extraneous mailcow dir in xtraLocation 2021-02-15 15:43:18 -07:00
Asif Bacchus 0bc0f8e5f9 refactor(BACKUP): update xtraLocation sample 2021-02-15 15:39:43 -07:00
Asif Bacchus 21e4a6774c docs(BACKUP): change xtraListPath description
- description was misleading, this is not a required variable
- holdover from importing
2021-02-15 15:37:32 -07:00
Asif Bacchus 7e739d96a1 feature(LOGWATCH): Update logwatch scripts
- add trailing newlines
- update search phrases to match logfile output
2021-02-15 15:31:05 -07:00
Asif Bacchus 61e505952d update TOC 2021-02-10 08:30:13 -07:00
Asif Bacchus 1939962b75 [README] add restore section 2021-02-10 08:08:18 -07:00
7 changed files with 88 additions and 32 deletions
+11 -2
View File
@@ -1,4 +1,4 @@
# Mailcow Backup Using borgbackup <!-- omit in toc --> # Mailcow Backup Using borgbackup
This script automates backing up your Mailcow installation using borgbackup and a remote ssh-capable storage system. I suggest using rsync.net since they This script automates backing up your Mailcow installation using borgbackup and a remote ssh-capable storage system. I suggest using rsync.net since they
have great speeds and a special pricing structure for borgbackup/attic users ([details here](https://www.rsync.net/products/attic.html)). have great speeds and a special pricing structure for borgbackup/attic users ([details here](https://www.rsync.net/products/attic.html)).
@@ -14,14 +14,19 @@ This script automates the following tasks:
- Runs 'borg prune' to make sure you are trimming old backups on your schedule - Runs 'borg prune' to make sure you are trimming old backups on your schedule
- Creates a clear, easy to parse log file so you can keep an eye on your backups and any errors/warnings - Creates a clear, easy to parse log file so you can keep an eye on your backups and any errors/warnings
## Contents <!-- omit in toc --> ## contents
<!-- toc -->
- [quick start](#quick-start) - [quick start](#quick-start)
- [configuration file](#configuration-file) - [configuration file](#configuration-file)
- [running the script](#running-the-script) - [running the script](#running-the-script)
- [scheduling your backup via cron](#scheduling-your-backup-via-cron) - [scheduling your backup via cron](#scheduling-your-backup-via-cron)
- [restoring backups](#restoring-backups)
- [final notes](#final-notes) - [final notes](#final-notes)
<!-- tocstop -->
## quick start ## quick start
Clone this repo or download a release file into a directory of your choosing. For all examples in this document, I will assume you will run the script from */scripts/backup*. Make sure the script file is executable and you protect the *.details* file since it contains things like your repo password: Clone this repo or download a release file into a directory of your choosing. For all examples in this document, I will assume you will run the script from */scripts/backup*. Make sure the script file is executable and you protect the *.details* file since it contains things like your repo password:
@@ -111,6 +116,10 @@ Edit your root user's crontab and add an entry like this which would run the scr
7 1 * * * /scripts/backup/backup.sh -l /var/log/mailcow_backup.log > /dev/null 2>&1 7 1 * * * /scripts/backup/backup.sh -l /var/log/mailcow_backup.log > /dev/null 2>&1
``` ```
## restoring backups
Starting with version 3.0, a *restore.sh* file has been included to semi-automate restoring your backups to a clean mailcow instance. There are a few steps required and they are better explained in the wiki than would be possible in a short write-up like this. Please check out the [restore process overview](https://git.asifbacchus.app/asif/MailcowBackup/wiki/8.0-Restore-overview) for more information.
## final notes ## final notes
I think that's everything. For detailed information, please review the [wiki](https://git.asifbacchus.app/asif/MailcowBackup/wiki/_pages). If I've forgotten to document something there, please let me know. I know the wiki is long but, I hate how much stuff for Linux and open-source programs/scripts in general are so poorly documented especially for newbies and I didn't want to make that same mistake. I think that's everything. For detailed information, please review the [wiki](https://git.asifbacchus.app/asif/MailcowBackup/wiki/_pages). If I've forgotten to document something there, please let me know. I know the wiki is long but, I hate how much stuff for Linux and open-source programs/scripts in general are so poorly documented especially for newbies and I didn't want to make that same mistake.
+12 -8
View File
@@ -18,14 +18,17 @@
# base configuration directory for borg, all borg parameters use this directory # base configuration directory for borg, all borg parameters use this directory
# as their 'root'. I recommend setups with this being "/var/borgbackup", the # as their 'root'. I recommend setups with this being "/var/borgbackup", the
# default is "$HOME" or "~$USER" in that order. If you're unsure, try "$HOME" # default is "$HOME" or "~$USER" in that order. If you're unsure, try "$HOME"
borgBaseDir="/var/borgbackup" borgBaseDir = "/var/borgbackup"
# SSH port on which your borg server listens. By default, this is port 22.
borgSSHPort = 22
# full path to the SSH key used to connect to your remote backup server # full path to the SSH key used to connect to your remote backup server
borgSSHKey="/var/borgbackup/private.key" borgSSHKey = "/var/borgbackup/private.key"
# connection string to access the borg repo on your remote backup server # connection string to access the borg repo on your remote backup server
# this is usually in the form user@servername.tld:repoName/ # this is usually in the form user@servername.tld:repoName/
borgConnectRepo="jdoe123@borg.server.net:mailcow/" borgConnectRepo = "jdoe123@borg.server.net:mailcow/"
# password to access repo # password to access repo
# this was set when the repo was initialized and, while optional, is HIGHLY # this was set when the repo was initialized and, while optional, is HIGHLY
@@ -36,12 +39,13 @@ borgRepoPassphrase="p@ssW0rd"
# FULL PATH where the associated keyfile for your repo is located -- relevant # FULL PATH where the associated keyfile for your repo is located -- relevant
# only if your repo requires a keyfile (i.e. 'keyfile' vs 'repokey') and if you # only if your repo requires a keyfile (i.e. 'keyfile' vs 'repokey') and if you
# are not using the default keyfile location # are not using the default keyfile location
borgKeyfileLocation="/var/borgbackup/.config/borg/keys/server_address__repo_name" #borgKeyfileLocation="/var/borgbackup/.config/borg/keys/server_address__repo_name"
# REQUIRED: path to text file containing a list (one per line) of files/ # additional files to backup
# directories to include in your backup. Since this is a generic backup script, # by default, the script will only backup your mailcow program directory
# nothing is defined by default. Therefore, ONLY files specified in this file # (e.g. /opt/mailcow-dockerized) and your mailcow data volumes. If you would
# will be backed up! # like additional files included (perhaps certificates, system configuration,
# etc.) include those locations listed one item per line in the file below
# see repo wiki for more details # see repo wiki for more details
borgXtraListPath="/scripts/backup/xtraLocations.borg" borgXtraListPath="/scripts/backup/xtraLocations.borg"
+54 -11
View File
@@ -153,6 +153,10 @@ scriptHelp() {
newline newline
textblock "${magenta}--- script related parameters ---${norm}" textblock "${magenta}--- script related parameters ---${norm}"
newline newline
switchTextblock "-b | --borg"
textblock "FULL path to borg executable file if not in the default location."
defaultsTextblock "(/usr/bin/borg)"
newline
switchTextblock "-c | --config | --details" switchTextblock "-c | --config | --details"
textblock "Path to the configuration key/value-pair file for this script." textblock "Path to the configuration key/value-pair file for this script."
defaultsTextblock "(scriptPath/scriptName.details)" defaultsTextblock "(scriptPath/scriptName.details)"
@@ -164,6 +168,10 @@ scriptHelp() {
textblock "Path to write log file" textblock "Path to write log file"
defaultsTextblock "(scriptPath/scriptName.log)" defaultsTextblock "(scriptPath/scriptName.log)"
newline newline
switchTextblock "[SWITCH] --nc | --no-color | --no-colour"
textblock "Do NOT use ANSI colourization in the log file (in case your preferred log viewer does not support it)."
defaultsTextblock "(use ANSI colourization to make log file look good)"
newline
switchTextblock "--compression" switchTextblock "--compression"
textblock "Compression algorithm(s) that borg should use. Please run 'borg help compression' for details." textblock "Compression algorithm(s) that borg should use. Please run 'borg help compression' for details."
defaultsTextblock "(not specified, use borg default of lz4)" defaultsTextblock "(not specified, use borg default of lz4)"
@@ -249,14 +257,16 @@ trapExit() {
## script related ## script related
# store logfile in the same directory as this script file using the same file # store logfile in the same directory as this script file using the same file
# name as the script but with the extension '.log' # name as the script but with the extension '.log'
scriptPath="$( CDPATH='' cd -- "$( dirname -- "$0" )" && pwd -P )" scriptPath="$( CDPATH='' \cd -- "$( dirname -- "$0" )" && pwd -P )"
scriptName="$( basename "$0" )" scriptName="$( basename "$0" )"
logFile="$scriptPath/${scriptName%.*}.log" logFile="$scriptPath/${scriptName%.*}.log"
colourizeLogFile=1
warnCount=0 warnCount=0
configDetails="$scriptPath/${scriptName%.*}.details" configDetails="$scriptPath/${scriptName%.*}.details"
err503Copied=0 err503Copied=0
sqlDumpDirCreated=0 sqlDumpDirCreated=0
exclusions=0 exclusions=0
borgPath="/usr/bin/borg"
# borg output verbosity -- normal # borg output verbosity -- normal
borgCreateParams='--stats' borgCreateParams='--stats'
borgPruneParams='--list' borgPruneParams='--list'
@@ -291,6 +301,19 @@ while [ $# -gt 0 ]; do
badParam empty "$@" badParam empty "$@"
fi fi
;; ;;
--nc|--no-color|--no-colour)
# do NOT colourize log file
colourizeLogFile=0
;;
-b|--borg)
# specify non-default borg path
if [ -n "$2" ]; then
borgPath="${2%/}"
shift
else
badParam empty "$@"
fi
;;
-c|--config|--details) -c|--config|--details)
# location of config details file # location of config details file
if [ -n "$2" ]; then if [ -n "$2" ]; then
@@ -412,8 +435,8 @@ if [ ! -f "$configDetails" ]; then
badParam dne "(--details default)" "$configDetails" badParam dne "(--details default)" "$configDetails"
fi fi
# is borg installed? # is borg installed?
if ! command -v borg > /dev/null; then if ! find "$borgPath" -type f -executable > /dev/null 2>&1; then
printf "\n%sERROR: BORG is not installed on this system!%s\n\n" "$err" "$norm" printf "\n%sERROR: BORG cannot be found in the specified or default location on this system!%s\n\n" "$err" "$norm"
exit 3 exit 3
fi fi
# if 503 functionality is enabled, do 503 related files exist? # if 503 functionality is enabled, do 503 related files exist?
@@ -436,6 +459,17 @@ fi
if [ -n "$borgCompression" ]; then if [ -n "$borgCompression" ]; then
borgCreateParams="${borgCreateParams} --compression ${borgCompression}" borgCreateParams="${borgCreateParams} --compression ${borgCompression}"
fi fi
# remove colourization if parameter specified
if [ "$colourizeLogFile" -eq 0 ]; then
bold=""
cyan=""
err=""
magenta=""
norm=""
ok=""
warn=""
yellow=""
fi
### read mailcow.conf and set vars as needed ### read mailcow.conf and set vars as needed
# shellcheck source=./mailcow.conf.shellcheck # shellcheck source=./mailcow.conf.shellcheck
@@ -509,7 +543,16 @@ elif [ ! -f "${borgSSHKey}" ]; then
fi fi
printf "%sdetails:borgSSHKey %s-- %s[OK]%s\n" \ printf "%sdetails:borgSSHKey %s-- %s[OK]%s\n" \
"$magenta" "$norm" "$ok" "$norm" >> "$logFile" "$magenta" "$norm" "$ok" "$norm" >> "$logFile"
export BORG_RSH="ssh -i ${borgSSHKey}" ## check SSH port
if [ -z "${borgSSHPort}" ]; then
borgSSHPort=22
printf "%sdetails:borgSSHPort %s-- %s[DEFAULT]%s\n" \
"$magenta" "$norm" "$ok" "$norm" >> "$logFile"
else
printf "%sdetails:borgSSHPort %s-- %s[CUSTOM]%s\n" \
"$magenta" "$norm" "$ok" "$norm" >> "$logFile"
fi
export BORG_RSH="ssh -i ${borgSSHKey} -p ${borgSSHPort}"
## check borg repo connect string ## check borg repo connect string
if [ -z "${borgConnectRepo}" ]; then if [ -z "${borgConnectRepo}" ]; then
@@ -550,7 +593,7 @@ fi
## export borg remote path, if specified ## export borg remote path, if specified
if [ -n "${borgRemote}" ]; then export BORG_REMOTE_PATH="${borgRemote}"; fi if [ -n "${borgRemote}" ]; then export BORG_REMOTE_PATH="${borgRemote}"; fi
## check if exlusion list file is specified ## check if exclusion list file is specified
if [ -n "${borgExcludeListPath}" ]; then if [ -n "${borgExcludeListPath}" ]; then
# check if the file actually exists # check if the file actually exists
if [ ! -f "${borgExcludeListPath}" ]; then if [ ! -f "${borgExcludeListPath}" ]; then
@@ -618,7 +661,7 @@ if [ "$use503" -eq 1 ]; then
printf "%s[%s] -- [INFO] Copying 503 error page to " \ printf "%s[%s] -- [INFO] Copying 503 error page to " \
"$cyan" "$(stamp)" >> "$logFile" "$cyan" "$(stamp)" >> "$logFile"
printf "webroot -- %s\n" "$norm">> "$logFile" printf "webroot -- %s\n" "$norm">> "$logFile"
if ! cp --force "${err503Path}" "${webroot}/${err503File}" 2>> "$logFile" if ! \cp --force "${err503Path}" "${webroot}/${err503File}" 2>> "$logFile"
then then
printf "%s[%s] -- [WARNING] Failed to copy 503 error page. " \ printf "%s[%s] -- [WARNING] Failed to copy 503 error page. " \
"$warn" "$(stamp)" >> "$logFile" "$warn" "$(stamp)" >> "$logFile"
@@ -660,7 +703,7 @@ docker-compose exec -T mysql-mailcow mysqldump --default-character-set=utf8mb4 \
dumpResult=$( docker-compose exec -T mysql-mailcow echo "$?" ) dumpResult=$( docker-compose exec -T mysql-mailcow echo "$?" )
if [ "$dumpResult" -eq 0 ]; then if [ "$dumpResult" -eq 0 ]; then
printf "%s[%s] -- [INFO] SQL database dumped successfully --%s\n" \ printf "%s[%s] -- [INFO] SQL database dumped successfully --%s\n" \
"cyan" "$(stamp)" "$norm" >> "$logFile" "$cyan" "$(stamp)" "$norm" >> "$logFile"
else else
exitError 118 'There was an error dumping the mailcow SQL database.' exitError 118 'There was an error dumping the mailcow SQL database.'
fi fi
@@ -678,7 +721,7 @@ docker-compose exec -T redis-mailcow redis-cli save >> "$logFile" 2>&1
rdumpResult=$( docker-compose exec -T redis-mailcow echo "$?" ) rdumpResult=$( docker-compose exec -T redis-mailcow echo "$?" )
if [ "$rdumpResult" -eq 0 ]; then if [ "$rdumpResult" -eq 0 ]; then
printf "%s[%s] -- [INFO] mailcow redis dumped successfully --%s\n" \ printf "%s[%s] -- [INFO] mailcow redis dumped successfully --%s\n" \
"cyan" "$(stamp)" "$norm" >> "$logFile" "$cyan" "$(stamp)" "$norm" >> "$logFile"
else else
exitError 119 'There was an error dumping the mailcow redis database.' exitError 119 'There was an error dumping the mailcow redis database.'
fi fi
@@ -690,7 +733,7 @@ printf "%s[%s] -- [INFO] Pre-backup tasks completed, calling borgbackup --%s\n"
## construct the proper borg commandline ## construct the proper borg commandline
# base command # base command
if [ "$exclusions" -eq 0 ]; then if [ "$exclusions" -eq 0 ]; then
borgCMD="borg create --show-rc ${borgCreateParams} \ borgCMD="${borgPath} create --show-rc ${borgCreateParams} \
::$(date +%Y-%m-%d_%H%M%S) \ ::$(date +%Y-%m-%d_%H%M%S) \
${mcConfig%/*} \ ${mcConfig%/*} \
${sqlDumpDir} \ ${sqlDumpDir} \
@@ -701,7 +744,7 @@ if [ "$exclusions" -eq 0 ]; then
${dockerVolumeCrypt} \ ${dockerVolumeCrypt} \
${xtraList}" ${xtraList}"
elif [ "$exclusions" -eq 1 ]; then elif [ "$exclusions" -eq 1 ]; then
borgCMD="borg create --show-rc ${borgCreateParams} \ borgCMD="${borgPath} create --show-rc ${borgCreateParams} \
--exclude-from ${borgExcludeListPath} \ --exclude-from ${borgExcludeListPath} \
::$(date +%Y-%m-%d_%H%M%S) \ ::$(date +%Y-%m-%d_%H%M%S) \
${mcConfig%/*} \ ${mcConfig%/*} \
@@ -745,7 +788,7 @@ fi
if [ -n "${borgPruneSettings}" ]; then if [ -n "${borgPruneSettings}" ]; then
printf "%s[%s] -- [INFO] Executing borg prune operation --%s\n" \ printf "%s[%s] -- [INFO] Executing borg prune operation --%s\n" \
"$cyan" "$(stamp)" "$norm" >> "$logFile" "$cyan" "$(stamp)" "$norm" >> "$logFile"
borg prune --show-rc -v ${borgPruneParams} ${borgPruneSettings} \ "${borgPath}" prune --show-rc -v ${borgPruneParams} ${borgPruneSettings} \
2>> "$logFile" 2>> "$logFile"
borgPruneResult="$?" borgPruneResult="$?"
else else
+4 -4
View File
@@ -49,12 +49,12 @@
# include the paths to important configuration files/directories and/or # include the paths to important configuration files/directories and/or
# data directories # data directories
# mailcow configuration (example) # mailcow configuration
/opt/mailcow-dockerized/ # already backed-up by the script by default based on mailcow.conf location
# NGINX (example) # NGINX (if this host is a reverse proxy, for example)
/etc/nginx/ /etc/nginx/
/usr/share/nginx/html/ /usr/share/nginx/html/
# LetsEncrypt (example) # LetsEncrypt
/etc/letsencrypt/ /etc/letsencrypt/
+3 -3
View File
@@ -3,8 +3,8 @@
############################################################################# #############################################################################
# $Id$ # $Id$
############################################################################# #############################################################################
# Log: Backup script (backup) # Log: mailcow backup
# Revision 1.0 2018/10/16 # Revision 1.1 2019/07/20
# Written by Asif Bacchus # Written by Asif Bacchus
############################################################################# #############################################################################
@@ -34,7 +34,7 @@ if ($detailLevel == 0) {
elsif ($ThisLine =~ /\-- \[WARNING\] /) { elsif ($ThisLine =~ /\-- \[WARNING\] /) {
$summaryWarn++; $summaryWarn++;
} }
elsif ($ThisLine =~ /All processes completed successfully/) { elsif ($ThisLine =~ /All processes completed/) {
$summarySuccess++; $summarySuccess++;
} }
} }