{"id":13681296,"url":"https://github.com/fspoettel/linkding-on-fly","last_synced_at":"2025-03-23T16:22:40.147Z","repository":{"id":75718565,"uuid":"492022463","full_name":"fspoettel/linkding-on-fly","owner":"fspoettel","description":"🔖 Run linkding on fly.io. Backup the bookmark DB to cloud storage with litestream.","archived":false,"fork":false,"pushed_at":"2024-06-19T22:11:25.000Z","size":12,"stargazers_count":71,"open_issues_count":1,"forks_count":13,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-01-28T22:31:30.935Z","etag":null,"topics":["fly","flyio","linkding","litestream","self-hosted"],"latest_commit_sha":null,"homepage":"","language":"Dockerfile","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/fspoettel.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-05-13T19:47:54.000Z","updated_at":"2025-01-12T17:16:48.000Z","dependencies_parsed_at":"2024-01-14T15:25:02.051Z","dependency_job_id":"72d0468f-5fce-4959-b917-c10d91116df8","html_url":"https://github.com/fspoettel/linkding-on-fly","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fspoettel%2Flinkding-on-fly","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fspoettel%2Flinkding-on-fly/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fspoettel%2Flinkding-on-fly/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fspoettel%2Flinkding-on-fly/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/fspoettel","download_url":"https://codeload.github.com/fspoettel/linkding-on-fly/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245128981,"owners_count":20565371,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["fly","flyio","linkding","litestream","self-hosted"],"created_at":"2024-08-02T13:01:28.978Z","updated_at":"2025-03-23T16:22:40.121Z","avatar_url":"https://github.com/fspoettel.png","language":"Dockerfile","funding_links":[],"categories":["HarmonyOS","Dockerfile"],"sub_categories":["Windows Manager"],"readme":"# linkding on fly\n\n\u003e 🔖 Run the self-hosted bookmark service [linkding](https://github.com/sissbruecker/linkding) on [fly.io](https://fly.io/). Automatically backup the bookmark database to [Backblaze B2](https://www.backblaze.com/b2/cloud-storage.html) with [litestream](https://litestream.io/).\n\n### Pricing\n\nAssuming 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]\n\n[^0]: Otherwise the VM is ~$2 per month. $0.15/GB per month for the persistent volume.\n[^1]: The first 10GB are free, then $0.005 per GB.\n\n### Prerequisites\n\n- A [fly.io](https://fly.io/) account\n- A [Backblaze](https://www.backblaze.com/) account\n- `flyctl` CLI installed. [^2]\n\n[^2]: https://fly.io/docs/getting-started/installing-flyctl/\n\nInstructions below assume that you have cloned this repository to your local computer:\n\n```sh\ngit clone https://github.com/fspoettel/linkding-on-fly.git \u0026\u0026 cd linkding-on-fly\n```\n\n#### Litestream - Create Backblaze B2 Bucket and Application Key\n\nLog into [Backblaze B2](https://secure.backblaze.com/user_signin.htm) and [create a bucket](https://litestream.io/guides/backblaze/#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.\n\nNext, create [an application key](https://litestream.io/guides/backblaze/#create-a-user) 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.\n\n\n\n\u003e **Note**  \n\u003e If you want to use another storage provider, check litestream's [\"Replica Guides\"](https://litestream.io/guides/#replica-guides) section and adjust the config as needed.\n\n### Usage\n\n1. Login to [`flyctl`](https://fly.io/docs/getting-started/log-in-to-fly/):\n\n    ```sh\n    flyctl auth login\n    ```\n\n2. Generate fly app and create the [`fly.toml`](https://fly.io/docs/reference/configuration/):\n    \u003cdetails\u003e\n    \u003csummary\u003eAlternative: Generating from template\u003c/summary\u003e\n\n    You can generate the `fly.toml` from the [template](templates/fly.toml) provided in this repository.\n\n    1. Install [`envsubst`](https://www.gnu.org/software/gettext/manual/html_node/envsubst-Invocation.html) if you don't have it already:\n\n        ```sh\n        # macOS\n        brew install gettext\n        ```\n\n    2. Copy the [.env.sample](.env.sample) file to `.env`, fill in the values and source them:\n\n        ```sh\n        cp .env.sample .env\n        # vim .env\n        source .env\n        ```\n\n    3. Generate the `fly.toml` from the template:\n\n        ```sh\n        envsubst \u003c templates/fly.toml \u003e fly.toml\n        ```\n\n    4. Proceed to step 3.\n    \u003c/details\u003e\n\n    ```sh\n    # Generate the initial fly.toml\n    # When asked, don't setup Postgres or Redis.\n    flyctl launch\n    ```\n\n    Next, open the `fly.toml` and add the following `env` and `mounts` sections (populating `LITESTREAM_REPLICA_ENDPOINT` and `LITESTREAM_REPLICA_BUCKET`):\n\n    ```toml\n    [env]\n      # linkding's internal port, should be 8080 on fly.\n      LD_SERVER_PORT=\"8080\"\n      # Path to linkding's sqlite database.\n      DB_PATH=\"/etc/linkding/data/db.sqlite3\"\n      # B2 replica path.\n      LITESTREAM_REPLICA_PATH=\"linkding_replica.sqlite3\"\n      # B2 endpoint.\n      LITESTREAM_REPLICA_ENDPOINT=\"\u003cBackblaze B2 endpoint\u003e\"\n      # B2 bucket name.\n      LITESTREAM_REPLICA_BUCKET=\"\u003cBackblaze B2 bucket name\u003e\"\n\n    [mounts]\n      source=\"linkding_data\"\n      destination=\"/etc/linkding/data\"\n    ```\n\n3. Add the Backblaze application key to fly's secret store\n\n    ```sh\n    flyctl secrets set LITESTREAM_ACCESS_KEY_ID=\"\u003ckeyId\u003e\" LITESTREAM_SECRET_ACCESS_KEY=\"\u003capplicationKey\u003e\"\n    ```\n\n4. Create a [persistent volume](https://fly.io/docs/reference/volumes/) to store the `linkding` application data:\n\n    ```sh\n    # List available regions via: flyctl platform regions\n    flyctl volumes create linkding_data --region \u003cregion code\u003e --size 1\n    ```\n\n    \u003e **Note**  \n    \u003e Fly's free tier includes `3GB` of storage across your VMs. Since `linkding` is very light on storage, a `1GB` 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.\n\n5. Add the `linkding` superuser credentials to fly's secret store:\n\n    ```sh\n    flyctl secrets set LD_SUPERUSER_NAME=\"\u003cusername\u003e\" LD_SUPERUSER_PASSWORD=\"\u003cpassword\u003e\"\n    ```\n\n6. Deploy `linkding` to fly:\n\n    ```sh\n    flyctl deploy\n    ```\n\n    \u003e **Note**  \n    \u003e The [Dockerfile](Dockerfile) contains overridable build arguments: `ALPINE_IMAGE_TAG`, `LINKDING_IMAGE_TAG` and `LITESTREAM_VERSION` which can overridden by passing them to `flyctl deploy` like `--build-arg LITESTREAM_VERSION=v0.3.11` etc.\n\n    \nThat'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.\n\nIf you wish, you can [configure a custom domain for your install](https://fly.io/docs/app-guides/custom-domains-with-fly/).\n\n### Verify the Installation\n\n- You should be able to log into your linkding instance.\n- There should be an initial replica of your database in your B2 bucket.\n- Your user data should survive a restart of the VM.\n\n### Verify Backups / Scale Persistent Volume\n\nLitestream continuously backs up your database by persisting its [WAL](https://en.wikipedia.org/wiki/Write-ahead_logging) to the Backblaze B2 bucket, once per second.\n\nThere are two ways to verify these backups:\n\n1. Run the docker image locally or on a second VM. Verify the DB restores correctly.\n2. Swap the fly volume for a new one and verify the DB restores correctly.\n\nWe 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.\n\nStart by making a manual backup of your data:\n\n1. SSH into the VM and copy the DB to a remote. If only you are using your instance, you can also export bookmarks as HTML.\n2. Make a snapshot of the B2 bucket in the B2 admin panel.\n\nNow list all fly volumes and note the id of the `linkding_data` volume. Then, delete the volume:\n\n```sh\nflyctl volumes list\nflyctl volumes delete \u003cid\u003e\n```\n\nThis 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.\n\nWhen the application starts, you should see the successful restore in the logs:\n\n```\n[info] No database found, attempt to restore from a replica.\n[info] Finished restoring the database.\n[info] Starting litestream \u0026 linkding service.\n```\n\n### Troubleshooting\n\n#### Litestream is logging 403 errors\n\nCheck that your B2 secrets and environment variables are correct.\n\n#### Fly ssh does not connect\n\nCheck the output of `flyctl doctor`, every line should be marked as **PASSED**. If `Pinging WireGuard` fails, try `flyctl wireguard reset` and `flyctl agent restart`.\n\n#### Fly does not pull in the latest version of linkding\n\n- Override the [Dockerfile](Dockerfile#L2) build argument `LINKDING_IMAGE_TAG`: `flyctl deploy --build-arg LINKDING_IMAGE_TAG=\u003ctag\u003e`\n- Run `flyctl deploy` with the `--no-cache` option.\n\n#### Create a linkding superuser manually\n\nIf you have never used fly's SSH console before, begin by setting up fly's ssh-agent:\n\n```sh\nflyctl ssh establish\n\n# use agent if possible, otherwise follow on-screen instructions.\nflyctl ssh issue --agent\n```\n\nThen, 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.\n\n```sh\ncd /etc/linkding\npython manage.py createsuperuser --username=\u003cyour_username\u003e --email=\u003cyour_email\u003e\nexit\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffspoettel%2Flinkding-on-fly","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffspoettel%2Flinkding-on-fly","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffspoettel%2Flinkding-on-fly/lists"}