DEV Community

Cover image for linkding: Self-Host Your Bookmarks
serverkueche.de
serverkueche.de

Posted on Originally published at serverkueche.de

linkding: Self-Host Your Bookmarks

Browser bookmarks are tied to one device, chaotically organized and gone the moment the profile breaks. linkding collects your links centrally on your own server: via the browser, an extension, the API – searchable, tagged and cross-device.

What are we building?

A lean, self-hosted bookmark manager with linkding (v1.45.0) behind Traefik. By the end you save links in one click, tag them, find them again via full-text search – and linkding fetches title and description from the linked page automatically. linkding is deliberately minimalist and extremely frugal (SQLite, barely any RAM).

Prerequisites

Step by step

Step 1: Project and Compose file

linkding stores everything (database, settings) in a data folder. Create the project:

mkdir -p /opt/linkding/data && cd /opt/linkding
Enter fullscreen mode Exit fullscreen mode

The compose.yaml – replace YOUR_DOMAIN. linkding creates the admin account on first start from the environment variables:

services:
  linkding:
    image: sissbruecker/linkding:1.45.0
    restart: unless-stopped
    volumes:
      - ./data:/etc/linkding/data
    environment:
      LD_SUPERUSER_NAME: cook
      LD_SUPERUSER_PASSWORD: YOUR_STRONG_PASSWORD
      LD_CSRF_TRUSTED_ORIGINS: https://YOUR_DOMAIN
    networks: [proxy]
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.linkding.rule=Host(`YOUR_DOMAIN`)"
      - "traefik.http.routers.linkding.entrypoints=websecure"
      - "traefik.http.routers.linkding.tls.certresolver=le"
      - "traefik.http.services.linkding.loadbalancer.server.port=9090"

networks:
  proxy:
    external: true
Enter fullscreen mode Exit fullscreen mode

⚠️ Don't forget LD_CSRF_TRUSTED_ORIGINS

Like many Django applications behind a reverse proxy, linkding needs LD_CSRF_TRUSTED_ORIGINS set to your full HTTPS domain – otherwise the login form fails with a CSRF error. The login page loads, but submitting it is rejected.

Step 2: Start and log in

docker compose up -d
Enter fullscreen mode Exit fullscreen mode

The image ships a health check; Traefik only routes once linkding is healthy (about 30 seconds). Then open https://YOUR_DOMAIN/:

The linkding login page under your own HTTPS domain

Log in with the account set in the Compose file.

Step 3: Save your first bookmark

Click Add bookmark at the top and paste a URL. The clever part: linkding fetches the page and fills in title and description automatically – you only add tags (separated by spaces, without #):

The form for creating a bookmark with automatically filled title and description

Optionally you can mark a bookmark as unread ("Mark as unread") – handy as a read-later list.

Step 4: Search and filter the collection

The overview shows your bookmarks chronologically, with a clickable tag cloud on the right. The search finds links by words or #tags:

The linkding overview with several bookmarks, tags and a search box

Clicking a tag filters instantly; multiple tags combine the filters. That keeps even a large collection tidy – without any folder hierarchy.

Step 5: Save quickly from the browser

For everyday use you don't want to open the web interface every time. linkding offers two convenient ways:

  • Browser extension: there's an official linkding extension for Firefox and Chrome. In its settings you enter https://YOUR_DOMAIN and an API token (found in linkding under Settings → Integrations → REST API). After that you save the current page with one click.
  • Bookmarklet: alternatively linkding offers a bookmarklet under Settings – a bookmark in your browser bar that sends the current page straight to linkding. Works without an extension, on mobile too.

💡 Import existing bookmarks

Switching from a browser or another service? Export your bookmarks there as an HTML file (the standard format of all browsers) and import them under Settings → Import. All your links move over at once – including the folder structure, which linkding turns into tags.

When things go wrong

Login fails with a CSRF error. LD_CSRF_TRUSTED_ORIGINS: https://YOUR_DOMAIN is missing or wrong (must be given with https:// and no path). Add it and docker compose up -d (see the warning in step 1).

The page doesn't load (Traefik 404) even though the container is running. The health check isn't healthy yet – Traefik deliberately doesn't route then. Wait about 30 seconds after start; check the status with docker inspect -f '{{.State.Health.Status}}' linkding-linkding-1.

Title/description aren't fetched automatically. The target page blocks automated access or responds too slowly. You can then simply enter title and description by hand – the fields are in the same form.

The admin account wasn't created. LD_SUPERUSER_NAME/LD_SUPERUSER_PASSWORD only take effect on the first start with an empty database. If the data database already exists, a later change does nothing. Create the account afterwards: docker compose exec linkding python manage.py createsuperuser.

The extension won't connect. Almost always the API token or the URL. Regenerate the token under Settings → Integrations and enter exactly https://YOUR_DOMAIN as the server.

Maintenance & backups

  • Updates. Occasionally bump the image tag (sissbruecker/linkding:1.45.0) to the current version and docker compose up -d; the database migrates automatically at start. The rest runs through your normal update process.
  • The backup is tiny. The entire state lives in the data folder (SQLite database). Add it to your Restic backup – then all bookmarks, tags and settings are safe. Additionally an occasional HTML export (Settings → Export) makes a browser-readable, service-independent backup.
  • Near-zero effort. linkding is a "set it up and forget it" service. The only recurring activity is saving new links – and you'll do that via the extension or bookmarklet in a second from now on.

This post first appeared on serverkueche.de.

Top comments (0)