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
X-Forwarded-Proto $schemeist Pflicht — ohne den Header meldet sich NextAuth alshttpund der SSO-Flow bricht.env-Änderungen brauchendocker compose up -d, nichtrestart— nurup -dliest dieenv_fileneu- Erster SSO-Login = Admin — zuerst mit dem gewünschten Admin-Account anmelden, kein Auto-Linking zu lokalen Accounts
- Nicht jede OpenAI-kompatible API kann
json_schema— bei stummem Tagging-Ausfall:INFERENCE_OUTPUT_SCHEMA=json - Compose immer vom Release ziehen — Meilisearch-/Chrome-Tags ändern sich zwischen Versionen
- Headless-Chrome ist der RAM-Fresser — ohne Full-Page-Archiv läuft es deutlich schlanker
Checkliste
- Compose vom aktuellen Release,
.envmit externerNEXTAUTH_URL+ zwei Secrets - nginx
:443mitX-Forwarded-Proto $scheme - Let’s-Encrypt-Zertifikat geholt
- Keycloak-Client
karakeep, Redirecthttps://.../*, Callback-Pfad/api/auth/callback/custom - Erster SSO-Login mit Admin-Account
- KI-Tagging:
INFERENCE_OUTPUT_SCHEMA=jsonfalls 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:
- 🖥️ Mini-PC N100 Beelink S12 Pro (16 GB/500 GB) — Docker-Host für Karakeep & Co.
- 🧠 32 GB DDR4 SODIMM — wenn Chrome-Archiv + weitere Container parallel laufen
- 💾 Samsung 990 PRO NVMe — schnelle Volumes für Meilisearch-Index
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