#+TITLE: Mastodon Backup #+DATE: 2023-07-26 * Prologue People on the Fediverse like to point out how you have to backup your data regularly in case of a catastrophic failure effecting your instance, the host of your instance, the data centre of your instance or maybe your admin. Heck, even a catastrophic failure effecting an admin of /another/ instance might make you wish you had a backup of your follows list[fn::If a remote admin decides to de-federate your instance it will sever all your connections with people on that instance.]. Remembering to make a backup manually is already difficult enough[fn::My last manual backup was over a year old.], but then you also need to remember *how* to make that backup... * Manual Backups Got to "App Settings". You do not know where "App Settings" are? I know the feeling... They are behind the three cogs on the top left. Navigate to "Import and export". Click "Data export". Click the "CSV" link. Click the other "CSV" link. Click the other other "CSV" link. You have now downloaded your "follows", "muted" and "blocked" accounts lists. * Automatic Backups I have recently discovered [[https://toot.bezdomni.net/introduction.html][toot - Mastodon CLI client]] which can output a list of your follows and people following you. I have [[https://github.com/ihabunek/toot/pull/390][contributed code for "muted" and "blocked" commands]] which got accepted and released in version 0.38. We first need to authenticate to our instance by running ~toot login~. This is only needed once. For more information [[https://toot.bezdomni.net/usage.html][see the official documentation]]. I am running the following script from cron once a day: #+begin_src shell #! /bin/ksh ACCOUNT=@florian@bsd.network INSTANCE=bsd.network BACKUPDIR=/home/mastodonbackup/backup set -e set -o pipefail exit_if_nonzero_or_stderr() { ( set -o pipefail { "$@" 1>&3 ;} 2>&1 | { if IFS= read -r line; then printf "%s\n" "$line" cat exit 1 fi } >&2 ) 3>&1 } exit_if_nonzero_or_stderr /usr/local/bin/toot muted | \ awk '$2 !~ /^@.*@/ {print $2 "@'${INSTANCE}'"; next} {print $2}' \ > ${BACKUPDIR}/muted.new mv ${BACKUPDIR}/muted{.new,} exit_if_nonzero_or_stderr /usr/local/bin/toot blocked | \ awk '$2 !~ /^@.*@/ {print $2 "@'${INSTANCE}'"; next} {print $2}' \ > ${BACKUPDIR}/blocked.new mv ${BACKUPDIR}/blocked{.new,} exit_if_nonzero_or_stderr /usr/local/bin/toot following ${ACCOUNT} | \ awk '$2 !~ /^@.*@/ {print $2 "@'${INSTANCE}'"; next} {print $2}' \ > ${BACKUPDIR}/following.new mv ${BACKUPDIR}/following{.new,} exit_if_nonzero_or_stderr /usr/local/bin/toot followers ${ACCOUNT} | \ awk '$2 !~ /^@.*@/ {print $2 "@'${INSTANCE}'"; next} {print $2}' \ > ${BACKUPDIR}/followers.new mv ${BACKUPDIR}/followers{.new,} #+end_src ~toot~ outputs accounts from the local instance without /@instance/. ~awk(1)~ checks for the existence of two /@/ characters and if they are not present outputs /@instance@/ after the account name. Unfortunately ~toot~ always exits with 0, even if there is an error so we need to check if there is some output on =stderr= so that we do not replace our backup with empty files. For that I copy-pasted =exit_if_nonzero_or_stderr= from [[https://stackoverflow.com/a/61468182][stackoverflow]] like a pro. My crontab entry looks like this: #+begin_src crontab ~ 9 * * * -sn su -s /bin/sh mastodonbackup -c /home/mastodonbackup/backup.sh #+end_src =-sn= ensures that the script is only run once and that no mail is sent after a successful run. See [[https://man.openbsd.org/crontab.5][crontab(5)]] for details. * Epilogue I have automated backing up the most important lists from my mastodon account. My mastodon account is running on somebody else's computer. The backup data is written as text files on a system that I control. That system is hooked up to my standard backup solution to have daily, multiple-redundant backups. I expire my toots after 90 days using [[https://ephemetoot.hugh.run/][ephemetoot]]. I have configured it to save the toots and media before deleting them from my account.