aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xalpine-diskless.sh5
-rwxr-xr-xalpine.sh27
-rwxr-xr-xbackup.sh101
-rwxr-xr-xclean.sh12
-rwxr-xr-xopenbsd.sh34
-rw-r--r--readme.md41
6 files changed, 220 insertions, 0 deletions
diff --git a/alpine-diskless.sh b/alpine-diskless.sh
new file mode 100755
index 0000000..d360bdd
--- /dev/null
+++ b/alpine-diskless.sh
@@ -0,0 +1,5 @@
+#!/bin/sh
+# alpine diskless backup...
+# Save the tarball to <hostname>.apkovl.tar.gz to restore
+set -e
+lbu package -
diff --git a/alpine.sh b/alpine.sh
new file mode 100755
index 0000000..11ab4b1
--- /dev/null
+++ b/alpine.sh
@@ -0,0 +1,27 @@
+#!/bin/sh
+# this requires the gnu tools:
+# apk add coreutils tar
+IFS='
+'
+_paths='/etc
+/home
+/root
+/var/acme
+/var/service
+/var/sshkeys
+/var/spool/cron'
+
+_file_list="$(mktemp)"
+ref="$(mktemp)"
+trap 'rm "$list" "$ref"' EXIT INT
+touch -d '-24 hours' "$ref"
+trap 'rm -f "$_file_list"' EXIT INT
+
+if [ "$1" = daily ] ; then
+ find $_paths -newer "$ref" -print0 > "$_file_list"
+else
+ find $_paths -print0 > "$_file_list"
+fi
+
+tar --null -T "$_file_list" -cf - \
+ | zstd -3c
diff --git a/backup.sh b/backup.sh
new file mode 100755
index 0000000..5aa1f96
--- /dev/null
+++ b/backup.sh
@@ -0,0 +1,101 @@
+#!/bin/sh
+set -e
+svr=""
+ssh_conf="ssh/config"
+ssh_key="ssh/id_ed25519"
+_backup_type="daily"
+_suffix="tar.zst"
+force=false
+
+
+_date_for_type() {
+case "$1" in
+daily) date +%Y-%m-%d ;;
+weekly) date +%Y-%U ;;
+monthly) date +%Y-%m ;;
+*) date +%s ;; # somehow, a bad type so just default to unix timestamp
+esac
+}
+
+__help() {
+cat <<EOF
+$0 -svr <server> [opts]
+
+Create a backup for <server>, defaults to daily. Calls <server>/backup.sh
+on the remote host and saves the stdout. It's up to the server's
+specific backup script to determine the specifics of that format. Tarballs
+are suggested, but snapshots, cpio archives, etc can all be used.
+
+Where [opts] are one of:
+
+-ssh_conf <filename> # For ssh configuration i.e. -F flag on ssh
+-ssh_key <filename> # SSH key to use, passed in as -i to ssh
+-type <daily|monthly|weekly> # Passed to the subscript, and changes output dir
+-suffix <suffix> # Defaults to 'tar.zst', but could be anything, should match
+ # the output of the server's specific backup script
+-force # Normally we bail if a backup exists, this will force overwrite
+
+Normal usage is that weekly and monthly backups are full, and the daily
+backups only include files that were changed in the past 24 hours, usually
+via find command and piping a list of input files to tar.
+
+A separate ./cleanup.sh script can take care of removing the old backups
+on a schedule that you prefer.
+EOF
+exit 2
+}
+
+while [ $# -gt 0 ] ; do case $1 in
+ -svr) svr="$2"; shift ; shift ;;
+ -ssh_conf) ssh_conf="$2"; shift ; shift ;;
+ -ssh_key) ssh_key="$2"; shift ; shift ;;
+ -type) _backup_type="$2"; shift ; shift ;;
+ -suffix) _suffix="$2"; shift ; shift ;;
+ -force) force=true ; shift ;;
+ *) __help ;;
+esac ; done
+
+_err=0
+if [ -z "$svr" ] ; then
+ echo "-svr flag needs to be set"
+ _err=1
+fi
+if [ -z "$ssh_conf" ] ; then
+ echo "-ssh_conf flag needs to be set"
+ _err=1
+fi
+if [ -z "$ssh_key" ] ; then
+ echo "-ssh_key flag needs to be set"
+ _err=1
+fi
+
+if ! [ -x "$svr/backup.sh" ] ; then
+ echo "$svr/backup.sh should exist and be executable!"
+ _err=1
+fi
+
+case "$_backup_type" in
+ daily|weekly|monthly) true ;;
+ *) echo "Bad backup type: '$_backup_type' valid options are daily, weekly, or monthly"; _err=1 ;;
+esac
+
+if [ "$_err" -ne 0 ] ; then
+ exit "$_err"
+fi
+
+ssh -F "$ssh_conf" -i "$ssh_key" "$svr" "mkdir -p /root/.backup"
+ssh -F "$ssh_conf" -i "$ssh_key" "$svr" "cat > /root/.backup/script.sh" < "$svr/backup.sh"
+ssh -F "$ssh_conf" -i "$ssh_key" "$svr" "chmod +x /root/.backup/script.sh"
+
+
+outfile="$svr/$_backup_type/$(_date_for_type "$_backup_type").$_suffix"
+mkdir -p "$(dirname "$outfile")"
+if [ -e "$outfile" ] ; then
+ echo "BACKUP FILE EXISTS ALREADY: $outfile"
+ if $force ; then
+ echo "OVERWRITING"
+ else
+ exit 1
+ fi
+fi
+ssh -F "$ssh_conf" -i "$ssh_key" "$svr" "/root/.backup/script.sh \"$_backup_type\"" | pv > "$outfile"
diff --git a/clean.sh b/clean.sh
new file mode 100755
index 0000000..a6b85fc
--- /dev/null
+++ b/clean.sh
@@ -0,0 +1,12 @@
+#!/bin/sh
+
+svrs='change
+me
+example.com
+weeeee.example.com'
+
+for _svr in $svrs ; do
+ find ./"$_svr"/monthly -type f -mtime +$((30*6)) -delete
+ find ./"$_svr"/weekly -type f -mtime +$((7*4)) -delete
+ find ./"$_svr"/daily -type f -mtime +7 -delete
+done
diff --git a/openbsd.sh b/openbsd.sh
new file mode 100755
index 0000000..a876f14
--- /dev/null
+++ b/openbsd.sh
@@ -0,0 +1,34 @@
+#!/bin/sh
+# OpenBSD backup script. Symlink into <svr>/backup.sh for use.
+# Make sure you update /etc/fstab appropriately before rebooting after
+# restore
+# To restore packages: pkg_add -l /root/packages.lst
+IFS='
+'
+_paths='/root
+/etc
+/home
+/var/redis
+/var/cron
+/var/mail
+/var/nsd
+/var/service
+/var/sshkeys
+/var/unbound
+/var/www/htdocs
+/var/rspamd
+/var/spool/smtpd'
+
+
+list="$(mktemp)"
+ref="$(mktemp)"
+trap 'rm "$list" "$ref"' EXIT INT
+touch -d $(date -r $(($(date +%s) - 86400)) +%Y-%m-%dT%H:%M:%S) "$ref"
+pkg_info -mz > /root/packages.lst
+if [ "$1" = daily ] ; then
+ find $_paths -newer "$ref" -type f > "$list"
+else
+ find $_paths -type f > "$list"
+fi
+tar -I "$list" -cf - \
+ | zstd -3c
diff --git a/readme.md b/readme.md
new file mode 100644
index 0000000..2df285f
--- /dev/null
+++ b/readme.md
@@ -0,0 +1,41 @@
+# Backup scripts
+
+Annoyed by complicated backup solutions, I've written my own simple scripts
+to back up only what I care about in a format that's easily unpacked on a fresh
+install of the system, that is, a tarball. There's no reason you couldn't
+use `dump`, `btrfs send`, `zfs send` or similar, though and this script
+supports handling that as long as you can pipe it over stdout and save to a file.
+
+Not for everyone, and I don't even use it for backups of my largest files, for
+instance photos, videos, etc I use rclone and rsync instead of these scripts.
+
+## HOW TO
+
+Clone this repo down to the system that'll run the backups, set up a
+ssh key in `ssh/id_ed25519` ( `ssh-keygen -t ed25519 -f ssh/id_ed25519` or so )
+and then set up your SSH config ( jump boxes, etc ) in `ssh/config`
+
+From there create a directory for each server that you're backing up, for
+instance if I want to back up a server called `example.com`, `mkdir example.com`.
+
+From there, we need a script that will generate a tarball, examples can be
+found in `openbsd.sh`, and `alpine.sh`, copy it to `example.com/backup.sh`,
+and then `chmod +x` the file. This will be copied and then executed as root
+on the remote machine.
+
+Another example worth calling out directly since it utilizes a slightly
+different method, `alpine-diskless.sh` can be used to back up the config
+using alpine's built in `lbu`, though it's worth passing in `-suffix tar.gz`
+to the backup script.
+
+
+Example crontab:
+
+```
+@monthly sh -c 'set -e;cd /home/backupdir;./backup.sh -type monthly -svr example.com'
+@weekly sh -c 'set -e;cd /home/backupdir;./backup.sh -type weekly -svr example.com'
+@daily sh -c 'set -e;cd /home/backupdir;./backup.sh -type daily -svr example.com'
+
+# Clean up the old backups daily, see the clean.sh for an example
+@daily sh -c 'set -e;cd /home/backupdir;./clean.sh
+```