Warum Karakeep?

Cloud-Bookmark-Dienste sind ein Risiko mit Ansage: Pocket, Instapaper & Co. kannst du dir aussuchen — Abo-Erhöhung, Feature-Abbau oder komplette Einstellung, deine gesammelten Links hängen immer an fremder Infrastruktur. Und die Empfehlungs-Engine sortiert dir dazwischen, was sie will.

Karakeep (früher Hoarder) ist die selbst gehostete Antwort: Links und Notizen speichern, Volltextsuche über den kompletten Seiteninhalt, optionales Full-Page-Archiv (Screenshots), Browser-Extension, Mobile-Apps — und optionales KI-Tagging, das jedem gespeicherten Link automatisch passende Schlagwörter verpasst.

In diesem Guide setzen wir Karakeep produktiv auf: extern erreichbar über HTTPS, Single-Sign-On über Keycloak (ein Login für alle deine Dienste) und KI-Tagging über eine günstige OpenAI-kompatible API. Alles im root_cause-Stil — mit den Fallstricken, die dich sonst einen Abend kosten.

Was du brauchst

  • Einen Docker-Host — Karakeep fährt drei Container (App + Volltextsuche + Headless-Chrome), rechne mit etwas RAM
  • Einen Reverse Proxy mit HTTPS (nginx + Let’s Encrypt)
  • Optional, aber empfohlen: eine laufende Keycloak-Instanz für SSO
  • Optional: einen API-Key für eine OpenAI-kompatible LLM-API (oder lokal via Ollama)

Die Architektur

Internet → nginx (Reverse Proxy, HTTPS, Let's Encrypt)
         → app-r2d2:3000  (Container "karakeep")
              ├── karakeep-chrome        (Crawler: Screenshots / Full-Page-Archiv)
              └── karakeep-meilisearch   (Volltextsuche)

SSO:  Karakeep → OIDC → Keycloak (auth.deathstar.lan) → LDAP
KI:   Karakeep → OpenAI-kompatible API (Tagging)

Drei Container, ein Reverse Proxy davor. Der Headless-Chrome ist der RAM-Fresser — wenn du kein Full-Page-Archiv brauchst, läuft es auch schlanker.

Schritt 1: Container-Deployment

Karakeep liefert eine offizielle Compose-Datei. Immer vom aktuellen Release ziehen — Image-Tags von Meilisearch und Chrome ändern sich zwischen Versionen:

mkdir -p karakeep && cd karakeep
wget -O docker-compose.yml \
  https://raw.githubusercontent.com/karakeep-app/karakeep/main/docker/docker-compose.yml

Die minimale .env:

cat > .env <<'EOF'
KARAKEEP_VERSION=release
# externe HTTPS-URL — MUSS stimmen, sonst bricht SSO (siehe unten)
NEXTAUTH_URL=https://bookmarks.deathstar.lan
NEXTAUTH_SECRET=HIER_openssl_rand_-base64_36
MEILI_MASTER_KEY=HIER_anderer_langer_Zufall
EOF

Zwei zufällige Secrets erzeugen:

openssl rand -base64 36    # für NEXTAUTH_SECRET
openssl rand -base64 36    # für MEILI_MASTER_KEY

Starten und prüfen:

docker compose up -d
docker compose ps

Expected Output:

NAME                    STATUS
karakeep                Up (healthy)
karakeep-chrome         Up
karakeep-meilisearch    Up

Karakeep hört jetzt intern auf Port 3000.

Schritt 2: Reverse Proxy + HTTPS

Vor den Container gehört nginx mit einem Let’s-Encrypt-Zertifikat. Der entscheidende Teil ist die :443-Location — und eine Zeile, die dir sonst das SSO zerschießt:

server {
    listen 443 ssl http2;
    server_name bookmarks.deathstar.lan;

    ssl_certificate     /etc/letsencrypt/live/bookmarks.deathstar.lan/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/bookmarks.deathstar.lan/privkey.pem;

    location / {
        proxy_pass http://192.168.66.10:3000$request_uri;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;   # <-- ohne das bricht SSO
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_buffering off;
        client_max_body_size 0;        # große Uploads / Full-Page-Archiv
        proxy_read_timeout 36000s;     # lange Crawls nicht abwürgen
    }
}

Das perfide

Fehlt X-Forwarded-Proto $scheme, meldet sich der Login-Provider (NextAuth) intern als http — und der ganze SSO-Redirect-Flow bricht. Du bekommst Endlos-Redirects oder „Callback URL mismatch", obwohl Keycloak korrekt konfiguriert ist. nginx terminiert das TLS, der Container sieht http — dieser Header ist die einzige Stelle, die ihm sagt, dass der Client per HTTPS kam.

Zertifikat holen und laden:

certbot certonly --webroot -w /var/www/acme -d bookmarks.deathstar.lan \
  --non-interactive --agree-tos --email admin@deathstar.lan --keep-until-expiring
nginx -t && systemctl reload nginx

Ohne SSO bist du hier fertig — Karakeep hat einen eingebauten lokalen Login. Willst du Single-Sign-On, weiter mit Schritt 3.

Schritt 3: Single-Sign-On über Keycloak

Ein Login für alle Dienste. In Keycloak legst du einen confidential Client an. Wichtig ist das Redirect-URI-Muster — Karakeep nutzt die Provider-ID custom:

  • Client-ID: karakeep
  • Access Type: confidential (Standard-Flow, PKCE)
  • Valid Redirect URIs: https://bookmarks.deathstar.lan/*
  • Web Origins: https://bookmarks.deathstar.lan
  • Callback-Pfad (intern): <NEXTAUTH_URL>/api/auth/callback/custom

Client-Secret in Keycloak auslesen, dann in die .env:

cat >> .env <<'EOF'
OAUTH_WELLKNOWN_URL=https://auth.deathstar.lan/realms/rebellion/.well-known/openid-configuration
OAUTH_CLIENT_ID=karakeep
OAUTH_CLIENT_SECRET=<secret aus keycloak>
OAUTH_PROVIDER_NAME=deathstar
OAUTH_SCOPE=openid email profile
DISABLE_PASSWORD_AUTH=false
EOF

DISABLE_PASSWORD_AUTH=false lässt den lokalen Login als Fallback stehen — praktisch, falls Keycloak mal streikt.

Neu einlesen — up -d, nicht restart (nur up -d liest die env_file neu):

docker compose up -d web

Falle: Der erste SSO-Login wird Admin. Der erste Account, der sich per SSO anmeldet, wird zum Karakeep-Administrator. Ein vorher angelegter lokaler Account mit gleicher Mail wird nicht automatisch verknüpft (Account-Linking ist aus Sicherheitsgründen bewusst deaktiviert). Melde dich also zuerst mit dem gewünschten Admin-Account an.

Prüfen, ob der Provider registriert ist:

curl -s https://bookmarks.deathstar.lan/api/auth/providers | jq '.custom.name'
# Erwartet: "deathstar"

Schritt 4: KI-Tagging

Das ist der Teil, der Karakeep von einer simplen Linkliste unterscheidet. Ablauf: Bookmark speichern → Crawler holt den Seitentext → ein Inference-Worker schickt den Text an ein LLM → bekommt Tags zurück → hängt sie ans Bookmark.

Karakeep spricht die OpenAI-kompatible API. Du kannst eine günstige Cloud-API nehmen oder lokal per Ollama fahren. In die .env:

cat >> .env <<'EOF'
OPENAI_BASE_URL=https://api.dein-llm-provider.com/v1
OPENAI_API_KEY=<dein key>
INFERENCE_TEXT_MODEL=<schnelles-günstiges-modell>
INFERENCE_IMAGE_MODEL=<vision-modell>
INFERENCE_LANG=german                 # deutsche Tags
INFERENCE_CONTEXT_LENGTH=8192
INFERENCE_OUTPUT_SCHEMA=json          # siehe Troubleshooting — wichtig!
EOF
docker compose up -d web

Das perfide (Teil 2)

Nicht jede „OpenAI-kompatible" API kann OpenAIs json_schema-Structured-Output. Manche Provider (z. B. DeepSeek) können nur den einfacheren JSON-Mode. Karakeep versucht per Default das strengere json_schema — und du bekommst still kein Tagging, nur im Log:

400 This response_format type is unavailable now

Fix: INFERENCE_OUTPUT_SCHEMA=json in der .env (JSON-Mode statt Structured Output), dann docker compose up -d web.

Schnell testen, was deine API kann:

KEY=<dein-api-key>
curl -s https://api.dein-llm-provider.com/v1/chat/completions \
  -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
  -d '{"model":"<modell>","messages":[{"role":"user","content":"hi"}],
       "response_format":{"type":"json_object"},"max_tokens":5}'
# json_object -> 200 OK  (dann reicht INFERENCE_OUTPUT_SCHEMA=json)
# json_schema  -> 400    (Provider kann kein Structured Output)

Bestehende Bookmarks nachträglich taggen: Settings → Admin Settings → Background Jobs → „Recrawl All Links" (crawlt neu und taggt danach).

Bonus: interne Seiten crawlbar machen

Standardmäßig blockt Karakeep das Crawlen interner Adressen (SSRF-Schutz). Willst du auch Seiten aus deinem eigenen Netz archivieren, im Log erscheint sonst:

Refusing to access disallowed resolved address ... (SSRF)

Fix — nur deine eigenen Domains freigeben:

echo 'CRAWLER_ALLOWED_INTERNAL_HOSTNAMES=.deathstar.lan' >> .env
docker compose up -d web
# dann: Admin Settings → Background Jobs → "Recrawl Failed Links Only"

Schritt 5: Browser & Mobile anbinden

Karakeep lebt davon, dass Speichern reibungslos ist:

  • Browser-Extension (Chrome/Firefox) — ein Klick, Link ist drin
  • Mobile-Apps (iOS/Android) über das Share-Sheet
  • API-Keys für Automation: Settings → API Keys → New API Key — damit kannst du per Skript oder über Tools Bookmarks anlegen und durchsuchen

Wer den Browser-Lesezeichen-Sync obendrauf will: Floccus synchronisiert Browser-Lesezeichen direkt nach Karakeep — dann ist der Browser der Client deines Stacks (siehe unsere Selfhosting-Dienste-Liste).

Verifikation

# 1. Extern erreichbar?
curl -sL -o /dev/null -w "%{http_code} %{url_effective}\n" https://bookmarks.deathstar.lan/
# Erwartet: 200 .../signin

# 2. SSO-Provider registriert?
curl -s https://bookmarks.deathstar.lan/api/auth/providers | jq '.custom.name'
# Erwartet: "deathstar"

# 3. API-Key gültig?
curl -s -o /dev/null -w "%{http_code}\n" -H "Authorization: Bearer $KARAKEEP_API_KEY" \
  "https://bookmarks.deathstar.lan/api/v1/bookmarks?limit=1"
# Erwartet: 200

# 4. Tagging/Crawl im Log?
docker logs karakeep --since 2m 2>&1 | grep -iE "inference|crawl|error"

Lessons Learned

  1. X-Forwarded-Proto $scheme ist Pflicht — ohne den Header meldet sich NextAuth als http und der SSO-Flow bricht
  2. .env-Änderungen brauchen docker compose up -d, nicht restart — nur up -d liest die env_file neu
  3. Erster SSO-Login = Admin — zuerst mit dem gewünschten Admin-Account anmelden, kein Auto-Linking zu lokalen Accounts
  4. Nicht jede OpenAI-kompatible API kann json_schema — bei stummem Tagging-Ausfall: INFERENCE_OUTPUT_SCHEMA=json
  5. Compose immer vom Release ziehen — Meilisearch-/Chrome-Tags ändern sich zwischen Versionen
  6. Headless-Chrome ist der RAM-Fresser — ohne Full-Page-Archiv läuft es deutlich schlanker

Checkliste

  • Compose vom aktuellen Release, .env mit externer NEXTAUTH_URL + zwei Secrets
  • nginx :443 mit X-Forwarded-Proto $scheme
  • Let’s-Encrypt-Zertifikat geholt
  • Keycloak-Client karakeep, Redirect https://.../*, Callback-Pfad /api/auth/callback/custom
  • Erster SSO-Login mit Admin-Account
  • KI-Tagging: INFERENCE_OUTPUT_SCHEMA=json falls Provider kein Structured Output kann
  • Browser-Extension + Mobile-App + API-Key

🛒 Empfohlene Hardware

Karakeep + Meilisearch + Headless-Chrome wollen etwas RAM — ein sparsamer Mini-PC reicht, für Full-Page-Archiv gern mit Reserve:

Kein Host daheim? Karakeep läuft auch auf einem kleinen Cloud-Server:

Hetzner Cloud Server starten


Einige Links auf dieser Seite sind Affiliate-Links. Wenn du über diese Links einkaufst, erhalte ich eine kleine Provision — für dich ändert sich am Preis nichts. So unterstützt du diesen Blog und ermöglichst weitere kostenlose Tutorials. Danke! 🙏


Zuletzt aktualisiert: Juli 2026 | Karakeep v0.32.x — Compose immer vom aktuellen Release ziehen