🔖 Run linkding on fly.io. Backup the bookmark DB to cloud storage with litestream.
🔖 Run the self-hosted bookmark service linkding on fly.io. Automatically backup the bookmark database to Backblaze B2 with litestream.
Assuming one 256MB VM and a 3GB volume, this setup fits within Fly's free tier. [^0] Backups with Backblaze B2 are free as well. [^1]
[^0]: Otherwise the VM is ~$2 per month. $0.15/GB per month for the persistent volume. [^1]: The first 10GB are free, then $0.005 per GB.
Instructions below assume that you have cloned this repository to your local computer:
git clone https://github.com/fspoettel/linkding-on-fly.git && cd linkding-on-fly
Log into Backblaze B2 and create a bucket. Once created, you will see the bucket's name and endpoint. You will use these later to populate LITESTREAM_REPLICA_BUCKET
and LITESTREAM_REPLICA_ENDPOINT
in the fly.toml
configuration.
Next, create an application key for the bucket. Once created, you will see the keyID
and applicationKey
. You will add these later to Fly's secret store, save them for step 3 below.
Note
If you want to use another storage provider, check litestream's "Replica Guides" section and adjust the config as needed.
Login to flyctl
:
flyctl auth login
Generate fly app and create the fly.toml
:
You can generate the fly.toml
from the template provided in this repository.
Install envsubst
if you don't have it already:
# macOS
brew install gettext
Copy the .env.sample file to .env
, fill in the values and source them:
cp .env.sample .env
# vim .env
source .env
Generate the fly.toml
from the template:
envsubst < templates/fly.toml > fly.toml
Proceed to step 3.
# Generate the initial fly.toml
# When asked, don't setup Postgres or Redis.
flyctl launch
Next, open the fly.toml
and add the following env
and mounts
sections (populating LITESTREAM_REPLICA_ENDPOINT
and LITESTREAM_REPLICA_BUCKET
):
[env]
# linkding's internal port, should be 8080 on fly.
LD_SERVER_PORT="8080"
# Path to linkding's sqlite database.
DB_PATH="/etc/linkding/data/db.sqlite3"
# B2 replica path.
LITESTREAM_REPLICA_PATH="linkding_replica.sqlite3"
# B2 endpoint.
LITESTREAM_REPLICA_ENDPOINT="<Backblaze B2 endpoint>"
# B2 bucket name.
LITESTREAM_REPLICA_BUCKET="<Backblaze B2 bucket name>"
[mounts]
source="linkding_data"
destination="/etc/linkding/data"
Add the Backblaze application key to fly's secret store
flyctl secrets set LITESTREAM_ACCESS_KEY_ID="<keyId>" LITESTREAM_SECRET_ACCESS_KEY="<applicationKey>"
Create a persistent volume to store the linkding
application data:
# List available regions via: flyctl platform regions
flyctl volumes create linkding_data --region <region code> --size 1
Note
Fly's free tier includes3GB
of storage across your VMs. Sincelinkding
is very light on storage, a1GB
volume will be more than enough for most use cases. It's possible to change volume size later. A how-to can be found in the "Verify Backups / Scale Persistent Volume" section below.
Add the linkding
superuser credentials to fly's secret store:
flyctl secrets set LD_SUPERUSER_NAME="<username>" LD_SUPERUSER_PASSWORD="<password>"
Deploy linkding
to fly:
flyctl deploy
Note
The Dockerfile contains overridable build arguments:ALPINE_IMAGE_TAG
,LINKDING_IMAGE_TAG
andLITESTREAM_VERSION
which can overridden by passing them toflyctl deploy
like--build-arg LITESTREAM_VERSION=v0.3.11
etc.
That's it! 🚀 - If all goes well, you can now access linkding
by running flyctl open
. You should see the linkding
login page and be able to log in with the superuser credentials you set in step 5.
If you wish, you can configure a custom domain for your install.
Litestream continuously backs up your database by persisting its WAL to the Backblaze B2 bucket, once per second.
There are two ways to verify these backups:
We will focus on 2 as it simulates an actual data loss scenario. This procedure can also be used to scale your volume to a different size.
Start by making a manual backup of your data:
Now list all fly volumes and note the id of the linkding_data
volume. Then, delete the volume:
flyctl volumes list
flyctl volumes delete <id>
This will result in a dead VM after a few seconds. Create a new linkding_data
volume. Your application should automatically attempt to restart. If not, restart it manually.
When the application starts, you should see the successful restore in the logs:
[info] No database found, attempt to restore from a replica.
[info] Finished restoring the database.
[info] Starting litestream & linkding service.
Check that your B2 secrets and environment variables are correct.
Check the output of flyctl doctor
, every line should be marked as PASSED. If Pinging WireGuard
fails, try flyctl wireguard reset
and flyctl agent restart
.
LINKDING_IMAGE_TAG
: flyctl deploy --build-arg LINKDING_IMAGE_TAG=<tag>
flyctl deploy
with the --no-cache
option.If you have never used fly's SSH console before, begin by setting up fly's ssh-agent:
flyctl ssh establish
# use agent if possible, otherwise follow on-screen instructions.
flyctl ssh issue --agent
Then, run flyctl ssh console
to get an interactive shell in your running container. You can now create a superuser by running the createsuperuser
command and entering a password.
cd /etc/linkding
python manage.py createsuperuser --username=<your_username> --email=<your_email>
exit