|
#!/bin/bash |
|
|
|
# SET GPG KEY FOR ENCRYPTING WITH (COMPRESSES AS WELL) |
|
GPG="" |
|
|
|
# SET DROPBOX API KEY FOR UPLOADS |
|
DROPBOX_APITOKEN="" |
|
|
|
# OPTIONAL SET A DEVICE NAME TO BE USED FOR BACKUPS (DEFAULTS TO /etc/hostname) |
|
DEVICE="" |
|
|
|
# INOTIFY CHECK |
|
# -------------- |
|
|
|
install_inotify () { |
|
sudo apt update |
|
sudo apt install -y inotify-tools |
|
} |
|
|
|
inotifycheck () { |
|
dpkg -s "inotify-tools" &> /dev/null |
|
if [ ! $? -eq 0 ]; then |
|
install_inotify |
|
fi |
|
} |
|
|
|
|
|
|
|
# SETUP |
|
# -------------- |
|
|
|
setup_files_and_folders () { |
|
# Setup remote folder name |
|
if [ -z "$DEVICE" ] ; then |
|
DEVICE=$(echo $(cat /etc/hostname)) |
|
fi |
|
DEVICE=$(echo $DEVICE | awk '{print tolower($0)}' | sed -e 's/ /-/g') |
|
REMOTE_BACKUP_FOLDER=.clnbackup-$DEVICE |
|
|
|
# Setup folders and filenames to upload from |
|
BACKUPS_DIR=/mnt/ext/apps-data/backups |
|
LIGHTNING_BACKUPS_DIR=$BACKUPS_DIR/lightning |
|
SOURCEFILE=$LIGHTNING_BACKUPS_DIR/lightningd.sqlite3.backup |
|
BACKUP_MD5SUM=$LIGHTNING_BACKUPS_DIR/backup.md5 |
|
TEMP_MD5="$BACKUP_MD5SUM.temp" |
|
|
|
ORIGINALFILE=/home/bitcoin/.lightning/bitcoin/lightningd.sqlite3 |
|
|
|
|
|
if [[ ! -e ${SOURCEFILE} ]]; then |
|
echo "Core-lightning backups not setup yet, exiting..." |
|
return 1 |
|
fi |
|
} |
|
|
|
|
|
# CHECKS |
|
# -------------- |
|
|
|
online_check () { |
|
wget -q --tries=10 --timeout=20 --spider http://google.com |
|
if [[ $? -eq 0 ]]; then |
|
ONLINE=true |
|
else |
|
ONLINE=false |
|
fi |
|
#echo "Online: "$ONLINE |
|
} |
|
|
|
dropbox_api_check () { |
|
VALID_DROPBOX_APITOKEN=false |
|
curl -s -X POST https://api.dropboxapi.com/2/users/get_current_account \ |
|
--header "Authorization: Bearer "$DROPBOX_APITOKEN | grep rror |
|
if [[ ! $? -eq 0 ]] ; then |
|
VALID_DROPBOX_APITOKEN=true |
|
else |
|
echo "Invalid Dropbox API Token!" |
|
fi |
|
} |
|
|
|
dropbox_upload_check () { |
|
UPLOAD_TO_DROPBOX=false |
|
if [ ! -z $DROPBOX_APITOKEN ] ; then |
|
online_check |
|
if [ $ONLINE = true ] ; then |
|
dropbox_api_check |
|
else |
|
echo "Please check that the internet is connected and try again." |
|
fi |
|
|
|
if [ $VALID_DROPBOX_APITOKEN = true ] ; then |
|
UPLOAD_TO_DROPBOX=true |
|
fi |
|
else |
|
echo "Missing value for 'DROPBOX_APITOKEN'" |
|
fi |
|
} |
|
|
|
# PREPARE |
|
# -------------- |
|
|
|
check_md5sum () { |
|
MD5SUM_FILENAME=$1 |
|
HASHFILE=$2 |
|
|
|
if [[ ! -e $MD5SUM_FILENAME ]]; then |
|
echo "File does not exist: $MD5SUM_FILENAME" |
|
return 1 |
|
fi |
|
|
|
if [[ ! -e "$HASHFILE" ]]; then |
|
return 1 |
|
fi |
|
|
|
if [[ ! $(md5sum "$MD5SUM_FILENAME" | awk '{print $1}') = $(cat "$HASHFILE") ]]; then |
|
return 1 |
|
fi |
|
} |
|
|
|
write_md5sum () { |
|
md5sum $1 | awk '{print $1}' > $2 |
|
} |
|
|
|
get_sizes () { |
|
DB_SIZE=$(du -m "$ORIGINALFILE" | awk '{print $1}') |
|
BACKUP_SIZE=$(du -m "$SOURCEFILE" | awk '{print $1}') |
|
if [ -z $DB_SIZE ]; then |
|
echo "# No $ORIGINALFILE is present" |
|
echo "# Make sure core-ln is setup first" |
|
return 1 |
|
fi |
|
} |
|
|
|
encrypt_backup () { |
|
FILE_TO_ENCRYPT=$1 |
|
ENCRYPTED_FILENAME=$2 |
|
|
|
if [[ -z $FILE_TO_ENCRYPT ]]; then echo "No file passed to encrypt"; return 1; fi |
|
rm $FILE_TO_ENCRYPT.gpg 2> /dev/null |
|
|
|
GPGNOTFOUND=$(gpg -k $GPG 2>&1 >/dev/null | grep -c error) |
|
if [ $GPGNOTFOUND -gt 0 ]; then |
|
gpg --recv-keys $GPG |
|
fi |
|
|
|
gpg --trust-model always -r $GPG -e $FILE_TO_ENCRYPT |
|
mv $FILE_TO_ENCRYPT.gpg $ENCRYPTED_FILENAME |
|
} |
|
|
|
prepare_file () { |
|
FILE_TO_PREPARE=$1 |
|
GPGFILE=$FILE_TO_PREPARE.gpg |
|
|
|
TEMPFILE=$2 |
|
BACKUP_TAR_FILE=$3 |
|
|
|
# Copy to get around the issue of incomplete file if |
|
# original file gets edited. |
|
echo "> Copying file to upload..." |
|
cp $FILE_TO_PREPARE $TEMPFILE |
|
write_md5sum "$TEMPFILE" "$BACKUP_MD5SUM.temp" |
|
echo "> Done copying." && echo |
|
|
|
|
|
UPLOAD_MD5=$(dirname $GPGFILE)/md5-full.txt |
|
echo "> Encrypting '$TEMPFILE'..." |
|
md5sum $TEMPFILE > $UPLOAD_MD5 |
|
encrypt_backup \ |
|
$TEMPFILE \ |
|
$GPGFILE |
|
rm $TEMPFILE |
|
echo "> Done encrypting." && echo |
|
|
|
echo "> Packing files into tar archive: $BACKUP_TAR_FILE ..." |
|
pushd $(dirname $GPGFILE) > /dev/null |
|
tar -czf $BACKUP_TAR_FILE \ |
|
$(basename $GPGFILE) \ |
|
$(basename $UPLOAD_MD5) |
|
rm $GPGFILE $UPLOAD_MD5 |
|
popd > /dev/null |
|
echo "> Done packing." && echo |
|
} |
|
|
|
run_compaction () { |
|
get_sizes || return 1 |
|
|
|
# https://github.com/lightningd/plugins/tree/master/backup#performing-backup-compaction |
|
echo "$DB_SIZE MB $ORIGINALFILE" |
|
echo "$BACKUP_SIZE MB $SOURCEFILE" |
|
if [ "$BACKUP_SIZE" -gt $((DB_SIZE+200)) ] ; then |
|
echo "# The backup is 200MB+ larger than the db, running 'lightning-cli backup-compact' ..." |
|
su - bitcoin -c 'lightning-cli backup-compact' |
|
else |
|
echo "The backup is not significantly larger than the db, there is no need to compact." |
|
fi |
|
} |
|
|
|
# UPLOAD |
|
# -------------- |
|
|
|
upload_to_dropbox_single () { |
|
echo "> Upload via single api ($BACKUP_SIZE MB packed in $BACKUP_TAR_FILE_SIZE MB archive)" |
|
FILENAME=$(basename $1) |
|
|
|
FINISH=$(curl -s -X POST https://content.dropboxapi.com/2/files/upload \ |
|
--header "Authorization: Bearer "${DROPBOX_APITOKEN}"" \ |
|
--header "Dropbox-API-Arg: {\"path\": \"/"$REMOTE_BACKUP_FOLDER"/"$FILENAME"\",\"mode\": \"overwrite\",\"autorename\": true,\"mute\": false,\"strict_conflict\": false}" \ |
|
--header "Content-Type: application/octet-stream" \ |
|
--data-binary @$1) |
|
# echo $FINISH | jq . |
|
UPLOADTIME=$(echo $FINISH | jq -r '.server_modified // empty') |
|
if [ ! -z $UPLOADTIME ] ; then |
|
echo "Successfully uploaded!" |
|
mv $TEMP_MD5 $BACKUP_MD5SUM |
|
else |
|
echo "Unknown error when uploading..." |
|
echo $FINISH | jq \ |
|
|| $FINISH |
|
rm $TEMP_MD5 |
|
return 1 |
|
fi |
|
} |
|
|
|
upload_to_dropbox_chunks () { |
|
echo "> Upload via chunks api ($BACKUP_SIZE MB packed in $BACKUP_TAR_FILE_SIZE MB archive)" |
|
FILENAME=$(basename $1) |
|
|
|
echo "Starting upload..." |
|
/usr/local/bin/dropbox_uploader.sh \ |
|
-f "/home/bitcoin/.dropbox_uploader" \ |
|
upload "$1" "$REMOTE_BACKUP_FOLDER/$FILENAME" |
|
# -p \ |
|
|
|
write_md5sum $TEMPFILE $BACKUP_MD5SUM |
|
} |
|
|
|
upload_to_dropbox () { |
|
FILENAME=$(basename $1) |
|
TEMPFILE=$1-temp |
|
BACKUP_TAR_FILE=$1.tar.gz |
|
|
|
echo "Starting file encrypt & archive: $1" |
|
prepare_file \ |
|
$1 \ |
|
$TEMPFILE \ |
|
$BACKUP_TAR_FILE |
|
if [[ ! "$?" -eq 0 ]]; then echo "Failed to prepare file"; return 1; fi |
|
|
|
if [[ ! -e $BACKUP_TAR_FILE ]]; then echo "Failed to prepare file" && return 1; fi |
|
BACKUP_TAR_FILE_SIZE=$(du -m "$BACKUP_TAR_FILE" | awk '{print $1}') |
|
|
|
if [ "$BACKUP_TAR_FILE_SIZE" -lt 290 ] ; then |
|
upload_to_dropbox_single $BACKUP_TAR_FILE || upload_to_dropbox_chunks $BACKUP_TAR_FILE |
|
else |
|
upload_to_dropbox_chunks $BACKUP_TAR_FILE |
|
fi |
|
UPLOAD_STATUS=$? |
|
|
|
rm $BACKUP_TAR_FILE |
|
return $UPLOAD_STATUS |
|
} |
|
|
|
# RUN CHECKS AND IF PASS, EXECUTE BACKUP TO DROPBOX |
|
run_dropbox_backup () { |
|
dropbox_upload_check |
|
if [ $UPLOAD_TO_DROPBOX = true ] ; then |
|
upload_to_dropbox $1 || return 1 |
|
fi |
|
} |
|
|
|
run_backup_on_change () { |
|
echo |
|
echo "Checking for compaction..." |
|
run_compaction || return 1 |
|
echo |
|
echo "Starting backup file upload: '"${SOURCEFILE}"'" |
|
run_dropbox_backup $SOURCEFILE || return 1 |
|
echo "---" |
|
} |
|
|
|
############## |
|
# RUN SCRIPT |
|
############## |
|
|
|
run () { |
|
inotifycheck |
|
setup_files_and_folders || return 1 |
|
|
|
while true; do |
|
while ! check_md5sum $SOURCEFILE $BACKUP_MD5SUM; do |
|
echo "File does not match last uploaded md5sum, running upload..." |
|
run_backup_on_change |
|
done |
|
|
|
inotifywait $SOURCEFILE |
|
run_backup_on_change |
|
echo |
|
done |
|
} |
|
|
|
run |
Hi thanks usuful and clean work. Can i ask you what's md5 purpose ?
Is it for integrity check in case of restore ?
Also i don't understand what
sed -i 's/\/.*\///g'
do.