Linkding backups (with a sidecar and S3)
I’ve started using Linkding1 for storing links in a more curated and deliberate capacity. I have Raindrop which is basically just a mess now, but it’s easy to navigate when there’s lots of things. Linkding isn’t designed that way however, so I’m being cautious. Whatever my usage(s), there is one concern: backing up the data.
There’s a couple of ways to do this. The first would be some calls via the REST API to build something that could be imported. Too much effort. The sceond was to manually backup through the export function on the settings page. Ick. The third and final option boils down to what was conveniently written in the docs. Since I’m using Linkding in SQLite mode, the ‘full backup’ option sounds the nicest. It just involves running a command on the container and then moving the data somewhere. Dead simple, unless you’re running it on something like Kubernetes, which I am. My plan is fairly simple:
- Run the ‘full backup’ command on a cron
- Send the data to some S3 bucket
Thankfully, setting up a sidecar container to handle the backup and data shovelling is dead simple.
Let’s start with the Dockerfile:
FROM ghcr.io/sissbruecker/linkding:latest-alpine@sha256:04e67acd04f1f1b3edd1bdd36fcf0dd5efaf8cdd99444e14be92c608575fa87a
# add mcli
RUN apk add --no-cache minio-client
COPY init-script.sh /usr/local/bin/init-script.sh
COPY backup-script.sh /usr/local/bin/backup-script.sh
RUN chmod +x /usr/local/bin/backup-script.sh
CMD ["/bin/sh", "/usr/local/bin/init-script.sh"]We start with the linkding image since that will be guaranteed to have everything we need on it. I’m then using the MinIO client for S3 interactions mainly due to the fact that Garage suggests it’s the best for compatibility with their S3 implementation. I use both mc/mcli and s3cmd at work for different tasks and I’ve never seen issues with either, but I’ll follow the docs.
Then there’s the matter of the two scripts: one for on start, and one that runs the backup logic. Those are copied, the cronnable one is chmod +xd and set the CMD. Here’s the init script:
# set alias
mcli alias set "$S3_BUCKET" "$S3_ENDPOINT" "$S3_ACCESS_KEY" "$S3_SECRET_KEY"
# set cron
echo "$CRON_SCHEDULE /usr/local/bin/backup-script.sh" >/etc/crontabs/root
# start cron
crond -l 2 -fSets up the MinIO client to point to the right bucket, the cron schedule, and the start the cron daemon. Dead simple. The backup script is about as simple:
# setup useful vars
TIME=$(date '+%Y-%m-%dT%T')
FILENAME="backup-$TIME.zip"
BACKUP_FILE="$BACKUP_TARGET_DEST/$FILENAME"
# run the backup logic
cd "/etc/linkding" || exit 1
python manage.py full_backup "$BACKUP_FILE"
# copy to S3
mcli cp "$BACKUP_FILE" "$S3_NAME/$S3_BUCKET/$FILENAME" || exit 1
# remove backup file
rm "$BACKUP_FILE"Build some nice name for the backup (it could be nicer), run the backup script, copy to S3. Now mcli has a mirror function and since this is a sidecar (i.e. always running in the pod), that would be a viable option instead of cp. However, I do want this sidecar to be as dormant as possible until backup time. Adding it as a sidecar container (i.e. just a second container in the pod) is very standard: set up some new env vars that match those in the scripts, and then mount the same volume as the main container and a new one for backups (either a new PVC or an emptyDir).
And that’s really it. Ideally you’d be backing up to some S3 that’s not on the same cluster as your Linkding installation, but mc replicate is a command that also exists and I will probably be running at sometime soon in some other pod once I get some external S3 storage.
You can find the container image on Docker hub. I haven’t made the Helm chart public yet, but that’s in the pile of making my other Helm charts public and easily usable.
PS: I think the worst part of this was that it took about 10 minutes to write up the solution, 10 minutes to test it, and then 20 minutes to write this post (partially because I found 2 ways to improve it)