How to: Backup a Mastodon instance

I recently started a new Mastodon instance and went through the joy of setting up a Mastodon server. It was easier than expected, the process is very streamlined and detailed in the docs:

But, of course, the backup process depends on your setup. The docs here, too, are very helpful—in the sense of what you need to backup:

My setup is based on a simple VPS, with AWS S3 for backup storage, and for schedule monitoring. Except for the environment secrets, which is just a static file and easily backup-able, the others are postgres, redis, and uploaded files.

This is the full script:


# postgres
echo "Postgres..."
runuser -l mastodon -c 'cd ~ && pg_dump -Fc mastodon_production -f postgres.dump'
aws s3 cp /home/mastodon/postgres.dump s3://sirodohtbucket/backup-postgres/$(date --iso-8601=seconds)/

# redis
echo "Redis..."
aws s3 cp /var/lib/redis/dump.rdb s3://sirodohtbucket/backup-redis/$(date --iso-8601=seconds)/

# uploads
echo "Uploads..."
now=$(date --iso-8601=seconds)

runuser -l mastodon -c 'cd ~ && tar -czvf accounts.tar.gz /home/mastodon/live/public/system/accounts/'
aws s3 cp /home/mastodon/accounts.tar.gz s3://sirodohtbucket/backup-uploads/$now/

runuser -l mastodon -c 'cd ~ && tar -czvf media_attachments.tar.gz /home/mastodon/live/public/system/media_attachments/'
aws s3 cp /home/mastodon/media_attachments.tar.gz s3://sirodohtbucket/backup-uploads/$now/

runuser -l mastodon -c 'cd ~ && tar -czvf site_uploads.tar.gz /home/mastodon/live/public/system/site_uploads/'

aws s3 cp /home/mastodon/site_uploads.tar.gz s3://sirodohtbucket/backup-uploads/$now/


  • For postgres, we just use pg_dump with the postgres custom format -Fc.
  • For redis, we just copy the periodically disk-written database dump.
  • For the uploaded files, we archive three directories accounts/, media_attachments/, and site_uploads/ and then upload them to S3 with the aws s3 copy command.
  • For all commands we use runuser so that they run as if the mastodon user is executing them.
  • Also, we upload them into datetime directories nested in the bucket, with date --iso-8601=seconds.

As for the crontab entry, we follow the Healthchecks docs on the dot:

0 3 * * * /home/sirodoht/ && curl -fsS -m 10 --retry 5 -o /dev/null