<< Outfucking the sky - April 17, 2023

My backups are stored on multiple disks at once to fulfill basic redundancy. There is the issue of lightning strikes, which I have not yet solved. Thus I came up with a half-assed solution to store backups on the cloud without exactly exposing them to surveillance or abuse.

For syncing files to the cloud you can use Rclone. It is great because you can mount a GDrive to the file-system - same as an ordinary disk. The solution consists of encrypting the backups with AES-256 (or some other manifestation of it) before fully uploading them.

/bin/bash

First you have to setup Rclone and hook it up with your account. This will allow it to call Google's API and read your GDrive files. I would also suggest you use a spare Google account for this so there is no risk of mistakenly deleting anything important.

After you have the API thing figured out, you can mount the GDrive:

rclone mount main_gdrive: /mnt

Finally, to upload any backup file, simply tell your script to cp -rf $LATEST_BACKUP_FILE /mnt/backups. Make sure to encrypt the backup file beforehand of course - I would suggest openssl for that.

If you are curious, this is how I did it.

. . .
now = datetime.now().strftime("%d_%m_%y_%H_%M_%S")
backup_filename = f"{sys.argv[4]}_{now}"
remote_destination = sys.argv[3]

os.system(f"zip -r - {to_backup} | openssl aes-256-cbc -a -salt -pbkdf2 -in - -out /dev/stdout -pass pass:$ENC_PASSWORD | RCLONE_CONFIG_PASS=$RCLONE rclone rcat {destination_drive}:{remote_destination}/{backup_filename}.enc ")

# number of items in folder
number_of_backups_command = f"RCLONE_CONFIG_PASS=$RCLONE rclone ls {destination_drive}:{remote_destination} | wc -l"
backups_number = int(os.popen(number_of_backups_command).read())
print("Number of backups " + str(backups_number))

while (backups_number > int(sys.argv[5])):
awk_subcommand = "awk '{print $2 \" \" $3 \" \" $4}'"
awk_second_subcommand = "awk '{print $3}'"
oldest = os.popen(f"RCLONE_CONFIG_PASS=$RCLONE rclone lsl {destination_drive}:{remote_destination} | {awk_subcommand} | sort --stable --key=1,2 | {awk_second_subcommand} | head -n 1").read()
os.system(f"RCLONE_CONFIG_PASS=$RCLONE rclone delete {destination_drive}:{remote_destination}/{oldest}")
backups_number = int(os.popen(number_of_backups_command).read())
. . .