|
#!/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 |
Hey @giulnz, really sorry for the late reply! Yes the md5 is to attach a signature of the original file for any verification purposes. Can be checked when the file is moved off the device, or later on when the file is being restored.
That
sed
command I believe removes the filename from the string that's returned whenmd5sum $SOURCEFILE
is run. If I remember correctly, it's to save just the md5 hash produced to the.md5
file and to remove any extra data that might have been added along.