aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCarlo Landmeter <clandmeter@alpinelinux.org>2018-01-29 15:31:27 +0000
committerCarlo Landmeter <clandmeter@alpinelinux.org>2018-01-29 15:35:06 +0000
commit05f986658bc04e2dc514b2c3e7777007cb6fb65c (patch)
treedb49882a6aac4ea68b7fa6285c340c09466abcc5
downloadalpine-backup-05f986658bc04e2dc514b2c3e7777007cb6fb65c.tar.bz2
alpine-backup-05f986658bc04e2dc514b2c3e7777007cb6fb65c.tar.xz
Initial commit
-rw-r--r--LICENSE21
-rw-r--r--README.md81
-rwxr-xr-xalpine-backup47
-rwxr-xr-xprofiles/backup-archive13
-rwxr-xr-xprofiles/backup-cleanup4
-rwxr-xr-xprofiles/backup-list4
-rwxr-xr-xprofiles/backup-mysql10
-rwxr-xr-xprofiles/backup-sync19
-rw-r--r--rbu.conf22
9 files changed, 221 insertions, 0 deletions
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..e45ac6b
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2018 Carlo Landmeter
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..caddbbd
--- /dev/null
+++ b/README.md
@@ -0,0 +1,81 @@
+# Alpine Linux Backup
+
+## Introduction
+
+Alpine remote backup (RBU) is a set of scripts based on LBU
+(Alpine Local Backup). It consist of a main script which need to be run from
+cron and a set of profiles which can be used as pre/post scripts for LBU.
+The idea of profiles is to simplify the backup process and to make sure
+services inside Alpine infrastructure are setup in a similar way. Some of the
+features/profiles of RBU are:
+
+* Dump databases to a cache directory
+* Synchronise backups to remote location
+* Copy backup status log to remote location
+* Send status notifications over mqtt
+
+## Usage
+
+### Prerequisite
+
+* POSIX shell
+* LBU (default on Alpine installation)
+* rsync `apk add rsync`
+* mosquitto-pub `apk add mosquitto-clients`
+
+### Configuration
+
+RBU needs a configuration file named `rbu.conf`. This configuration should
+(by default) be put in the lbu configuration directory `/etc/lbu`. Inside this
+configuration should be a list of exported configuration variables which are
+needed for lbu and its pre/post scripts to function properly.
+
+### Profiles
+
+Profiles are a setup of LBU pre/post scripts. To use these scripts you should
+symlink (or copy) them from the profile directory to one of the following dirs:
+
+* `pre-package.d` (scripts run before LBU creates its backup)
+* `post-package.d` (scripts run after LBU created its backup)
+
+These profiles/scripts will be run by busybox run-parts which means they cannot
+have an extension and need to be executable. If you need to run these scripts
+in a specific order you should prefix them with a number like `10-scriptname`.
+
+### Encryption
+
+To make sure the backups are safe we use openssl encryption option provided by
+LBU. Please make sure you provide a secure password in `rbu.conf` and make sure
+you have a backup of that password in case you will need it when restoring.
+
+### Include non etc files
+
+By default LBU will only backup files located in the `/etc` directory and have
+been modified. To include other files you need to lbu_include files and
+directories. Exclusion is possible via lbu_exclude. Please check Alpine wiki for
+more information regarding LBU usage.
+
+### Backup server
+
+Backups will be kept in the specified backup location in rbu.conf. After the
+backup is successful these backups will be rsynced to the remote backup server.
+To be able to automatically rsync backups a ssh key needs to be generated per
+backup. For generating a Ed25519 key exec: `ssh-keygen -t ed25519` and copy the
+public key to the backup server.
+
+### Enable daily backups
+
+Copy the provided `alpine-backup.cron` as `/etc/periodic/daily/alpine-backup` to
+make the backup run every night.
+
+## Backup monitoring
+
+Backups are are automatically monitored by Alpine monitoring system. After the
+backup has finished it will send a message with metadata to our mqtt server
+which will be picked up by Alpine monitoring system.
+
+## NOTE
+
+Older version of LBU have a bug which prevents the cleanup of older local
+encrypted backups. see:
+https://git.alpinelinux.org/cgit/alpine-conf/commit/?id=cd395b \ No newline at end of file
diff --git a/alpine-backup b/alpine-backup
new file mode 100755
index 0000000..22af5a5
--- /dev/null
+++ b/alpine-backup
@@ -0,0 +1,47 @@
+#!/bin/sh
+
+RBU_CONF=/etc/lbu/rbu.conf
+
+if [ -f "$RBU_CONF" ]; then
+ . "$RBU_CONF"
+else
+ echo "Cannot read $RBU_CONF"
+ exit 1
+fi
+
+# set the suffix of backup files when ecryptions is enabled
+[ -n "$ENCRYPTION" ] && export SUFFIX=".$ENCRYPTION"
+
+# convert hostname to intra FQDN
+HOSTNAME=$(hostname)
+if [ -n $HOST ]; then
+ export FQDN="${HOSTNAME}.${HOST}.intra.alpinelinux.org"
+else
+ export FQDN="${HOSTNAME}.intra.alpinelinux.org"
+fi
+
+START_TS=$(date +%s)
+
+LOGFILE="$BACKUP_CACHE/$FQDN-$(date -u "+%Y%m%d%H%M%S").log"
+lbu_commit >>"$LOGFILE" 2>&1
+ret=$?
+
+DURATION=$(($(date +%s)-$START_TS))
+SIZE=0
+STATUS=failed
+
+if [ $ret = 0 ]; then
+ [ -n "$ENCRYPTION" ] && SUFFIX=".$ENCRYPTION"
+ BACKUP="$BACKUP_LOCATION/$(hostname).apkovl.tar.gz${SUFFIX}"
+ SIZE=$(stat -c %s $BACKUP)
+ STATUS=success
+fi
+
+ssh "$BACKUP_SERVER" mkdir -p $FQDN/logs
+scp -q $LOGFILE "$BACKUP_SERVER:$FQDN/logs"
+
+PAYLOAD=$(printf '{ "status": "%s", "size": %u, "duration": %u }' "$STATUS" "$SIZE" "$DURATION")
+JSON=$(printf '{ "host": "%s", "key": "backup", "payload": %s }' "$FQDN" "$PAYLOAD")
+
+mosquitto_pub -h msg.alpinelinux.org -t "monitoring/updates" -m "$JSON"
+
diff --git a/profiles/backup-archive b/profiles/backup-archive
new file mode 100755
index 0000000..ed72be6
--- /dev/null
+++ b/profiles/backup-archive
@@ -0,0 +1,13 @@
+#!/bin/sh
+
+DATE=$(date -u "+%Y%m%d%H%M%S")
+SRC="$(hostname).apkovl.tar.gz${SUFFIX}"
+DEST="$(hostname).${DATE}.tar.gz${SUFFIX}"
+
+# Keep a montly copy of the first day of the month
+if [ "$(date +%d)" = "01" ]; then
+ echo "Archiving montly backup"
+ echo "$SRC"
+ echo "$DEST"
+ ssh "$BACKUP_SERVER" install -Dm644 "$FQDN"/week/"$SRC" "$FQDN"/month/"$DEST"
+fi
diff --git a/profiles/backup-cleanup b/profiles/backup-cleanup
new file mode 100755
index 0000000..b590b22
--- /dev/null
+++ b/profiles/backup-cleanup
@@ -0,0 +1,4 @@
+#!/bin/sh
+
+echo "Removing mysqldump file"
+rm -f $BACKUP_CACHE/mysql.sql
diff --git a/profiles/backup-list b/profiles/backup-list
new file mode 100755
index 0000000..30afb37
--- /dev/null
+++ b/profiles/backup-list
@@ -0,0 +1,4 @@
+#!/bin/sh
+echo "Files included in this backup:"
+apk audit --backup --quiet --recursive --check-permissions
+echo ""
diff --git a/profiles/backup-mysql b/profiles/backup-mysql
new file mode 100755
index 0000000..ff6edd6
--- /dev/null
+++ b/profiles/backup-mysql
@@ -0,0 +1,10 @@
+#!/bin/sh
+
+if [ -n "$MYSQL_PASSWORD" ]; then
+ echo "Dumping databases to: $BACKUP_CACHE/mysql.sql"
+ [ -d "$CACHE_DIR" ] || mkdir -p "$BACKUP_CACHE"
+ mysqldump -u root -p${MYSQL_PASSWORD} --all-databases -r \
+ $BACKUP_CACHE/mysql.sql
+else
+ echo "MySQL password not set, skipping mysqldump."
+fi
diff --git a/profiles/backup-sync b/profiles/backup-sync
new file mode 100755
index 0000000..d4514ea
--- /dev/null
+++ b/profiles/backup-sync
@@ -0,0 +1,19 @@
+#!/bin/sh
+
+echo "Sending backup to backup server"
+
+# make sure the destination directory exists
+ssh "$BACKUP_SERVER" mkdir -p $FQDN/week
+
+# get the name of the renamed backup and also rename
+# this backup on the remote to prevent dulpicate upload
+CURR_BACKUP=$(ls -t "$BACKUP_LOCATION" | sed -n 2p)
+if [ -n "$CURR_BACKUP" ]; then
+ HOSTNAME=$(hostname)
+ ssh "$BACKUP_SERVER" mv -f \
+ $FQDN/week/$HOSTNAME.apkovl.tar.gz${SUFFIX} \
+ $FQDN/week/$CURR_BACKUP
+fi
+
+rsync -av --delete-after "$BACKUP_LOCATION/" \
+ "$BACKUP_SERVER":"$FQDN"/week
diff --git a/rbu.conf b/rbu.conf
new file mode 100644
index 0000000..c54e2af
--- /dev/null
+++ b/rbu.conf
@@ -0,0 +1,22 @@
+# enable and set encryption
+export ENCRYPTION=aes-256-cbc
+# Encryption password
+export PASSWORD=mysecurepassword
+# backup location
+export LBU_BACKUPDIR=/var/lib/backup
+# amount of backups to store
+export BACKUP_LIMIT=7
+# if this host is a guest set HOST to hostname of host
+# export HOST=
+# the location of the backup cache
+export BACKUP_CACHE=/var/cache/backup
+# backup directory to be picked up by pre script
+export BACKUP_LOCATION="$LBU_BACKUPDIR"
+# ssh backup server to send backups to
+export BACKUP_SERVER="user@backupserver.tld"
+
+# Custom profile settings
+
+# the mysql password to be picked up by pre script
+# export MYSQL_PASSWORD=mysecurepasword
+