Karakeep — self-hostowany zbieracz zakładek wspierany przez AI
Karakeep zapisuje linki, notatki, obrazy i PDF-y, archiwizuje całe strony i sam nadaje tagi przez model językowy. Pokazujemy, jak go uruchomić i co trzeba ustawić, zanim wystawisz instancję na świat.
Zakładki gniją. Artykuł, który zapisałeś dwa lata temu, dziś prowadzi do domeny na sprzedaż, a dokumentacja narzędzia, które właśnie wdrażasz, została przepisana i nie ma już sekcji, na którą się powoływałeś. Do tego w marcu 2025 Mozilla zamknęła Pocket — narzędzie, które dla wielu ludzi było jedynym miejscem, gdzie trafiały linki „przeczytam później". Kto trzymał tam swoją bibliotekę, dostał plik CSV i pytanie, co dalej.
Karakeep jest odpowiedzią na to pytanie po stronie self-hostingu. To aplikacja, która zapisuje linki, notatki, obrazy i PDF-y, pobiera do nich tytuły i opisy, archiwizuje całe strony na wypadek zniknięcia oryginału, indeksuje treść do wyszukiwania pełnotekstowego i semantycznego, a tagi nadaje sama — modelem językowym. Projekt ma 28 929 gwiazdek i 1504 forki, a przez pierwszy rok życia nazywał się Hoarder.
Ta zmiana nazwy jest ważna praktycznie: stare adresy repozytorium i obrazy kontenerów wciąż krążą po internecie, a w dokumentacji jest osobny przewodnik migracji z Hoardera na Karakeep. Jeśli trafiłeś tu ze starego wpisu na forum, sprawdź, na jaki obraz wskazuje twój compose.
Co Karakeep właściwie przechowuje
Nazwa „bookmark manager" sprzedaje ten projekt zbyt tanio. Zakres jest szerszy:
- Linki, proste notatki tekstowe, obrazy i pliki PDF.
- Automatyczne pobieranie tytułu, opisu i obrazu podglądu dla linku.
- Listy, w tym listy współdzielone — na jednej liście można pracować z innymi osobami.
- Wyszukiwanie pełnotekstowe i semantyczne po całej zapisanej treści.
- Tagowanie i streszczanie przez model językowy, z obsługą modeli lokalnych przez Ollamę.
- OCR — wyciąganie tekstu z obrazów, żeby zrzut ekranu też był wyszukiwalny.
- Zaznaczenia (highlights) zapisywane razem z treścią.
- Archiwizacja całej strony narzędziem
monolith, jako polisa na wypadek link rotu. - Automatyczne pobieranie wideo przez
yt-dlp. - Silnik reguł „jeśli to, to tamto" — auto-tagowanie, ulubione, wrzucanie do list.
- Zasysanie treści z kanałów RSS.
- REST API, webhooki, CLI i serwer MCP.
Do tego dochodzą klienci: wtyczka do Chrome, dodatek do Firefoksa, rozszerzenie Safari, aplikacja na iOS i na Androida, z czytaniem offline na telefonie. Import obsługuje format Netscape HTML (czyli eksport zakładek z Chrome i Firefoksa), nowy format CSV z Pocketa oraz JSON-y z Omnivore. Jest też automatyczna synchronizacja z zakładkami przeglądarki przez floccus. Tłumaczenia interfejsu prowadzone są na Weblate.
Jedna rzecz, o której warto wiedzieć przed importem: dokumentacja mówi wprost, że wszystkie adresy z pliku wejściowego zostaną dodane i nie da się wybrać, które. Jeśli twój eksport z Chrome liczy trzy tysiące pozycji zebranych od 2014 roku, dostaniesz trzy tysiące pozycji, a crawler zacznie je po kolei odwiedzać.
Stan projektu
Repozytorium żyje i to widać po rytmie wydań. Ostatnie wersje: v0.33.2 z 11 sierpnia 2026, v0.33.1 z 1 sierpnia, v0.32.0 z 8 maja, v0.31.0 z 22 lutego, v0.30.0 z 1 stycznia 2026. Ostatni commit w gałęzi main jest z 31 sierpnia 2026 — dziesięć dni przed powstaniem tego wpisu. Projekt startował 6 lutego 2024, więc mamy dwa i pół roku ciągłej pracy.
Uczciwie trzeba dodać drugą liczbę: 723 otwarte zgłoszenia. Przy prawie dwudziestu dziewięciu tysiącach gwiazdek to nie jest sygnał zaniedbania, ale też nie licz na to, że twoje zgłoszenie zostanie obsłużone w tygodniu. Jest Discord i są dyskusje na GitHubie — w praktyce to tam szybciej dostaniesz odpowiedź.
Licencja to AGPL-3.0, a właścicielem praw jest brytyjska spółka Localhost Labs Ltd. Istnieje też płatna wersja hostowana, Karakeep Cloud, i autor pisze otwarcie, że subskrypcje finansują rozwój. To układ, który warto rozumieć: kod jest w całości otwarty na AGPL, a firma zarabia na hostingu, nie na okrojonej wersji społecznościowej.
Repozytorium: karakeep-app/karakeep. Jest też publiczne demo pod try.karakeep.app, zasiane treścią i przełączone w tryb tylko do odczytu.
Architektura
Stos jest przewidywalny i to zaleta. Aplikacja webowa to Next.js na app routerze, baza to SQLite obsługiwana przez Drizzle wraz z migracjami, uwierzytelnianie stoi na NextAuth, komunikacja klient–serwer idzie przez tRPC. Wyszukiwanie pełnotekstowe obsługuje Meilisearch, a crawlowanie — Puppeteer sterujący headless Chrome.
Kolejka zadań też siedzi w SQLite. Workery konsumują z niej trzy rodzaje zadań: crawlowanie (pobranie treści linku przeglądarką bez interfejsu), inferencję (wyliczenie tagów modelem) i indeksowanie (wrzucenie treści do Meilisearch). W praktyce oznacza to, że po dodaniu zakładki widzisz ją od razu, ale tytuł, tagi i możliwość wyszukania pojawiają się z opóźnieniem — gdy odpowiedni worker dojdzie do jej zadania.
Domyślnie każdy typ workera działa w jednej instancji: CRAWLER_NUM_WORKERS, INFERENCE_NUM_WORKERS, SEARCH_NUM_WORKERS, EMBEDDING_NUM_WORKERS, RULE_ENGINE_NUM_WORKERS i WEBHOOK_NUM_WORKERS mają wartość 1. Przy imporcie trzech tysięcy zakładek to jest właśnie to miejsce, które chcesz podkręcić — i jednocześnie miejsce, w którym łatwo zadławić własny serwer trzema równoległymi instancjami Chrome.
Zasoby binarne (zrzuty ekranu, archiwa, obrazy) trafiają domyślnie na lokalny system plików do katalogu DATA_DIR, ale można je przełączyć na magazyn zgodny z S3. Przełączenie odbywa się przez samo ustawienie ASSET_STORE_S3_ENDPOINT — obecność tej zmiennej włącza tryb S3. Dokumentacja ostrzega, i słusznie, że zmiana backendu po zapisaniu danych wymaga ręcznej migracji istniejących zasobów. Tę decyzję podejmij przed wdrożeniem, nie po pół roku.
Uruchomienie
Instalacja to Docker Compose. Plik docker-compose.yml z repozytorium podnosi trzy usługi: web, chrome i meilisearch, a wolumeny i połączenia między nimi są już w nim opisane. Minimalny plik .env obok compose'a:
KARAKEEP_VERSION=0.33.2
NEXTAUTH_SECRET=wygenerowany_losowy_ciag
MEILI_MASTER_KEY=inny_losowy_ciag
NEXTAUTH_URL=https://zakladki.example.comSekrety generuj poleceniem, nie z głowy:
openssl rand -base64 36Dla MEILI_MASTER_KEY autorzy sugerują dodatkowo odsianie znaków specjalnych: openssl rand -base64 36 | tr -dc 'A-Za-z0-9'.
Teraz rzecz, którą warto zrobić inaczej niż w domyślnym pliku. Compose ma wpisane ${KARAKEEP_VERSION:-release}, a dokumentacja instalacji podaje KARAKEEP_VERSION=release jako wariant startowy. To ciągnie najnowszą stabilną wersję — czyli przy każdym docker compose up --pull always -d dostajesz to, co akurat jest najnowsze, bez kontroli nad momentem aktualizacji. Przypnij konkretną wersję. Dokumentacja sama to zaleca, tylko jej przykład (KARAKEEP_VERSION=0.10.0) został przy wersji z dawnych czasów, więc nie kopiuj numeru — sprawdź aktualny tag w wydaniach.
Przy przypiętej wersji aktualizacja to podbicie numeru w .env i docker compose up -d. Przy release trzeba zmusić Dockera do pobrania obrazu flagą --pull always, bo tag się nie zmienił.
Osobna uwaga dla osób migrujących ze starszych instalacji: jeśli twój compose wciąż używa dawnego obrazu Chrome na Alpine, w dokumentacji jest przewodnik migracji obrazu przeglądarki. Meilisearch również ma własną procedurę przy zmianie wersji, opisaną na stronie rozwiązywania problemów.
Zanim wystawisz to na świat
To najważniejsza sekcja tego wpisu i najłatwiejsza do przeoczenia, bo składa się z dwóch niewinnych osobno wartości domyślnych, które razem tworzą problem.
Pierwsza: DISABLE_SIGNUPS ma domyślnie false, czyli rejestracja nowych kont jest otwarta. Druga, z sekcji FAQ dokumentacji: pierwszy użytkownik, który się zarejestruje, jest automatycznie awansowany na administratora.
Złóż to razem. Jeśli podniesiesz instancję, skierujesz na nią domenę i pójdziesz zrobić kawę, zanim założysz konto — administratorem twojej instancji zostanie ta osoba, która wejdzie pierwsza. Kolejność jest więc jednoznaczna: najpierw uruchom aplikację lokalnie albo za zaporą, zarejestruj swoje konto, a dopiero potem wystawiaj ją na zewnątrz z DISABLE_SIGNUPS=true. Konta dla resztu zespołu administrator zakłada z panelu, przyciskiem „Create User" — wyłączona rejestracja tego nie blokuje.
Jeśli macie już dostawcę tożsamości, sensowniejsza jest ścieżka OAuth. Karakeep obsługuje wyłącznie dostawców zgodnych z OIDC, konfiguracja idzie przez OAUTH_WELLKNOWN_URL, OAUTH_CLIENT_ID i OAUTH_CLIENT_SECRET, a adres przekierowania po stronie dostawcy ustawia się na <adres>/api/auth/callback/custom. Logowanie hasłem można wtedy wyłączyć przez DISABLE_PASSWORD_AUTH=true, a przez OAUTH_AUTO_REDIRECT=true pominąć ekran wyboru metody.
Jednej flagi z tej grupy nie włączaj bez namysłu: OAUTH_ALLOW_DANGEROUS_EMAIL_ACCOUNT_LINKING automatycznie łączy istniejące konto w bazie z kontem OAuth o tym samym adresie e-mail. Dokumentacja mówi „włącz tylko, jeśli ufasz dostawcy" i to nie jest kurtuazja — przy dostawcy, który nie weryfikuje adresów, jest to droga do przejęcia konta.
Warto też wiedzieć, jak wygląda odzyskiwanie dostępu administratora, bo to opisuje model zaufania całej instalacji. Gdy administrator zgubi hasło, procedura z FAQ to: zatrzymać Karakeep, otworzyć plik db.db w katalogu danych klientem sqlite3 i podmienić hash hasła zapytaniem UPDATE. Innymi słowy — kto ma dostęp do wolumenu z danymi, ten ma instancję. Wolumen szyfruj i traktuj jak sekret, a nie jak zwykły katalog na dysku.
Crawler, czyli przeglądarka na twoim łączu
Dokumentacja ma osobną stronę „Security Considerations" i jest w niej rzadko spotykana szczerość. Crawler to prawdziwa przeglądarka, która pobiera treść zakładek, a każdy użytkownik z dostępem do aplikacji może zlecić jej pobranie dowolnego adresu i zobaczyć wynik. Autorzy wymieniają trzy sposoby nadużycia tego wprost:
Niezaufany użytkownik może zlecić pobranie stron, z którymi nie chcesz, by kojarzono twoje adresy IP. Crawlowanie strony kontrolowanej przez użytkownika ujawnia twoje IP źródłowe i lokalizację, nawet jeśli usługa stoi za Cloudflare. A żądania wychodzą z twojej własnej sieci, więc można je wykorzystać do odpytywania wewnętrznych endpointów, które nie są wystawione do internetu.
Karakeep ma na to podstawową ochronę: domyślnie blokuje żądania inicjowane przez workery, jeśli nazwa hosta rozwiązuje się na adres prywatny, loopback, link-local albo z zakresu CGNAT używanego przez Tailscale. Wyjątki dodaje się przez CRAWLER_ALLOWED_INTERNAL_HOSTNAMES, z obsługą wieloznaczników w postaci kropki na początku (.internal.example.com). Wartość . otwiera wszystko — jeśli ją gdzieś zobaczysz w cudzym compose, to jest właśnie wyłączona ochrona.
A teraz szczegół, który łatwo przegapić, choć jest w dokumentacji zapisany czarno na białym. Zalecanym sposobem ograniczenia ryzyka jest przepuszczenie ruchu crawlera przez proxy poza siecią wewnętrzną (CRAWLER_HTTP_PROXY, CRAWLER_HTTPS_PROXY). Ale: walidacja adresów wewnętrznych jest pomijana, gdy dla danego URL skonfigurowano proxy, ponieważ lokalny resolver DNS nie musi być tym samym, którego użyje proxy. Zalecane zabezpieczenie wyłącza więc wbudowane. To nie jest błąd — to konsekwencja tego, że przy proxy Karakeep przestaje wiedzieć, gdzie żądanie faktycznie trafi. Ale znaczy, że proxy musi mieć własną politykę sieciową, a nie być samo w środku twojej sieci. Jeśli postawisz je obok Karakeepa, zamienisz jedną ochronę na żadną.
Dostępne są też limity, które domyślnie nie działają, bo nie mają wartości: CRAWLER_DOMAIN_RATE_LIMIT_WINDOW_MS i CRAWLER_DOMAIN_RATE_LIMIT_MAX_REQUESTS. Przy zasysaniu RSS-ów z jednej domeny warto je ustawić, choćby z uprzejmości wobec cudzego serwera.
Tagowanie AI i wybór dostawcy
Tagowanie jest opcjonalne, ale to ono odróżnia Karakeepa od zwykłego katalogu linków. Obsługiwane są dostawcy zgodni z API OpenAI oraz Ollama, co w praktyce daje długą listę: OpenAI, Ollama (dwa warianty endpointu), Gemini przez warstwę zgodności, OpenRouter, Perplexity, Azure AI Foundry i Cloudflare Workers AI.
Dla lokalnej inferencji autorzy zalecają endpoint zgodny z OpenAI, nie natywne API Ollamy:
OPENAI_API_KEY=ollama
OPENAI_BASE_URL=http://ollama.mojasiec.pl:11434/v1
INFERENCE_TEXT_MODEL=gemma3
INFERENCE_IMAGE_MODEL=llava
EMBEDDING_TEXT_MODEL=embeddinggemma
EMBEDDING_DIMENSIONS=768
EMBEDDING_CONTEXT_LENGTH=2048Adres Ollamy musi być osiągalny z wnętrza kontenera Karakeepa, więc localhost nie zadziała. Przy natywnym API trzeba pamiętać o odwrotnej zależności: jeśli ustawiony jest OPENAI_API_KEY, ma on pierwszeństwo nad OLLAMA_BASE_URL. A gdy model nie obsługuje wyjścia strukturalnego, potrzebne jest INFERENCE_OUTPUT_SCHEMA=plain.
W przypadku Azure jest osobna pułapka nazewnicza, na którą dokumentacja słusznie zwraca uwagę ostrzeżeniem: nazwa modelu to nazwa wdrożenia (deployment name), którą podałeś przy publikacji, a nie nazwa modelu bazowego. Wpisanie tam gpt-4o-mini zamiast nazwy własnego wdrożenia skończy się błędami, których treść niczego nie podpowie.
Teraz dwie rzeczy, których nie znajdziesz w jednym miejscu. Pierwsza: domyślny model tekstowy w kodzie (packages/shared/config.ts) to gpt-5.6-luna, a domyślny model do obrazów gpt-4o-mini. Strona o dostawcach AI podaje w zakomentowanym przykładzie gpt-4.1-mini — ten komentarz jest po prostu nieaktualny w stosunku do kodu. Skoro używasz innego dostawcy niż OpenAI, ustaw INFERENCE_TEXT_MODEL jawnie, bo domyślna wartość niemal pewnie nie istnieje w jego katalogu, a zadania inferencji będą się cicho wywalać.
Druga: INFERENCE_LANG ma domyślnie wartość english. To zmienna decydująca o języku generowanych tagów. Jeśli zbierasz polskie treści i nie tkniesz tego ustawienia, dostaniesz polskie artykuły opisane angielskimi tagami, obok których z czasem pojawią się polskie tagi dodane ręcznie — i skończysz z dwoma równoległymi systemami nazw na tę samą rzecz. Ustaw INFERENCE_LANG=polish na samym początku, przed pierwszym importem, bo przetagowanie kilku tysięcy pozycji po fakcie to koszt inferencji zapłacony dwa razy.
O kosztach dokumentacja pisze konkretnie: przy tagowaniu tekstu wystarczy mniej niż dolar na ponad sześć tysięcy zakładek, a przy obrazach — mniej niż dolar na ponad tysiąc sztuk, przy czym obrazy przetwarzane są w trybie niskiej rozdzielczości o stałym koszcie tokenowym niezależnym od rozmiaru wejścia. To rzędy wielkości, nie oferta, ale wystarczają, żeby ocenić, czy warto.
Osiągnięcie wyszukiwania semantycznego wymaga jeszcze modelu embeddingów i jawnego włączenia indeksowania:
EMBEDDING_TEXT_MODEL=text-embedding-3-small
EMBEDDING_DIMENSIONS=1536
EMBEDDING_ENABLE_AUTO_INDEXING=trueTu obowiązuje zasada, którą lepiej poznać z dokumentacji niż z własnego incydentu: embeddingi z różnych modeli nie są ze sobą kompatybilne. Zmiana modelu albo liczby wymiarów wymusza przeliczenie embeddingów dla wszystkich zakładek. Dodatkowo, jeśli używasz EMBEDDING_TEXT_MODEL_DIMENSION_OVERRIDE, jego wartość musi się zgadzać z EMBEDDING_DIMENSIONS — inaczej aplikacja się nie wystartuje. Embeddingi mogą przy tym korzystać z innego dostawcy niż inferencja, przez EMBEDDING_OPENAI_API_KEY i EMBEDDING_OPENAI_BASE_URL.
Wyszukiwanie
Karakeep ma własny język zapytań i jest to jedna z lepiej dopracowanych części projektu. Spacja oznacza domyślne AND, są też jawne and i or, negacja przez - albo !, oraz nawiasy do grupowania — z zastrzeżeniem, że grup nie da się zanegować.
Kwalifikatory, których używa się najczęściej: is:fav, is:archived, is:tagged, is:inlist, is:link, is:text, is:media, url:, title:, #tag (albo tag:), list:, after:, before:, feed:, source: i age:. Nazwy ze spacjami podaje się w cudzysłowach, na przykład #"w toku".
# pozycje z zepsutymi linkami — audyt link rotu
is:broken
# co przyszło z RSS-ów, a czego nie dodałem ręcznie
source:rss -source:web
# świeże, nieotagowane, do przejrzenia
age:<1d -is:tagged
# zarchiwizowane i jednocześnie na liście albo z tagiem
is:archived and (list:czytanie or #praca)Dwa z tych kwalifikatorów zasługują na osobne słowo. is:broken zwraca pozycje, przy których crawl się nie udał albo serwer odpowiedział kodem innym niż 2xx — czyli pozwala regularnie robić przegląd tego, co właśnie umarło w twojej bibliotece. A source: rozróżnia pochodzenie zapisu: api, web, cli, mobile, extension, singlefile, rss, import. Przy włączonym zasysaniu RSS-ów to jedyny sensowny sposób oddzielenia rzeczy, które sam wybrałeś, od strumienia, który wpadł automatycznie.
Archiwizacja, czyli co jest domyślnie wyłączone
Tu trzeba zajrzeć w wartości domyślne, bo obietnica z README i zachowanie po instalacji to nie to samo. Domyślnie włączone są: pobieranie obrazu podglądu (CRAWLER_DOWNLOAD_BANNER_IMAGE) i zapisywanie zrzutu ekranu (CRAWLER_STORE_SCREENSHOT). Domyślnie wyłączone są natomiast: archiwizacja całej strony (CRAWLER_FULL_PAGE_ARCHIVE), zrzut całej strony (CRAWLER_FULL_PAGE_SCREENSHOT), zapis PDF (CRAWLER_STORE_PDF) i pobieranie wideo (CRAWLER_VIDEO_DOWNLOAD).
Czyli funkcja, dla której wiele osób sięga po Karakeepa — pełne archiwum strony chroniące przed link rotem — nie działa, dopóki jej nie włączysz. A gdy ją włączysz, natkniesz się na drugą rzecz: CRAWLER_MONOLITH_TIMEOUT_SEC ma domyślnie 5 sekund, przy czym własny limit narzędzia monolith to 120 sekund. Dokumentacja podaje obie liczby obok siebie i dodaje, żeby zwiększyć wartość, jeśli zakładki z wolnych serwerów często nie dają się zarchiwizować. Pięć sekund na zebranie całej strony wraz z zasobami to bardzo ciasno — jeśli archiwa wychodzą puste, zacznij od tego parametru, nie od szukania błędu w monolicie.
Do tego dwa limity rozmiaru: MAX_ASSET_SIZE_MB wynosi 50, a CRAWLER_VIDEO_DOWNLOAD_MAX_SIZE również 50 MB. Godzinna prelekcja z konferencji się w tym nie zmieści.
Jest jeszcze jedno ustawienie warte świadomej decyzji: CRAWLER_ENABLE_AUTOCONSENT, domyślnie włączone, automatycznie odklikuje zgody w obsługiwanych okienkach cookie — po wykryciu platformy zarządzania zgodami crawler czeka do 3 sekund na zakończenie opt-outu, a potem pobiera treść. Praktycznie: bez tego połowa archiwów byłaby zrzutem banera zamiast artykułu. Formalnie: twój serwer podejmuje decyzje o zgodach w twoim imieniu na cudzych stronach. Warto o tym wiedzieć, zanim ktoś zapyta.
Integracje, CLI i MCP
CLI instaluje się z npm (npm install -g @karakeep/cli) albo uruchamia z obrazu Dockera. Obsługuje zakładki, listy i tagi oraz masowy import i eksport. Konfigurację można trzymać w $XDG_CONFIG_HOME/karakeep/config.json, a przy braku tej zmiennej w ~/.config/karakeep/config.json.
I tu czai się pułapka, której nikt nie spodziewa się po narzędziu z hasłem „self-hosting first": jeśli nie podasz adresu serwera, CLI domyślnie łączy się z https://cloud.karakeep.app. Zapomniany --server-addr nie oznacza więc błędu ani lokalnego połączenia — oznacza próbę rozmowy z chmurą producenta. Ustaw KARAKEEP_SERVER_ADDR w środowisku albo serverAddr w pliku konfiguracyjnym i sprawdź to od razu poleceniem karakeep whoami. Przy okazji: klucz API leży w tym pliku jawnym tekstem, więc należą mu się uprawnienia 600, a nie domyślne.
Import z pliku z listą adresów, jeden na linię, robi się pętlą po CLI:
while IFS= read -r url; do
karakeep bookmarks add --link "$url"
done < linki.txtSerwer MCP pozwala modelom rozmawiać z twoimi zakładkami — jest publikowany na npm jako @karakeep/mcp oraz jako obraz kontenera. Zakres narzędzi jest szeroki: wyszukiwanie zakładek, czytanie treści, tworzenie i aktualizacja, obsługa list i tagów, dopinanie i odpinanie tagów. Dokumentacja precyzuje przy tym dwa zachowania, które łatwo źle założyć: usunięcie listy nie usuwa list potomnych (zostają ze wskazaniem na nieistniejącego rodzica), a usunięcie tagu nie usuwa zakładek, które go miały.
Konfiguracja klienta to standardowy blok z kluczem API i adresem serwera — i znów, tu adres podajesz jawnie, więc wpisz swój, nie chmurowy z przykładu:
{
"mcpServers": {
"karakeep": {
"command": "npx",
"args": ["@karakeep/mcp"],
"env": {
"KARAKEEP_API_ADDR": "https://zakladki.example.com",
"KARAKEEP_API_KEY": "twoj_token"
}
}
}
}Po stronie automatyzacji są jeszcze webhooki (limit czasu 5 sekund, trzy ponowienia domyślnie), silnik reguł do auto-tagowania i rozdzielania treści po listach oraz pełne REST API — to samo, z którego korzystają oficjalne aplikacje.
Monitoring stoi na OpenTelemetry: śledzenie (OTEL_TRACING_ENABLED) i strukturalne logi zdarzeń (EVENT_LOGS_ENABLED) są domyślnie wyłączone, a autorzy uprzedzają, że logi zdarzeń bywają gadatliwe. Jest też endpoint metryk dla Prometheusa pod /api/metrics, chroniony tokenem PROMETHEUS_AUTH_TOKEN — z zastrzeżeniem, o które warto się nie potknąć: gdy tokenu nie ustawisz, przy każdym starcie generowany jest nowy losowy. Bez jawnej wartości scrapowanie przestanie działać po pierwszym restarcie kontenera. Zwróć też uwagę, że LOG_LEVEL ma domyślnie debug — na produkcji to zwykle nie jest to, czego chcesz w wolumenie z logami.
O czym pomyśleć, zanim zaczniesz archiwizować cudze strony
Karakeep w trybie pełnej archiwizacji tworzy kompletne kopie stron osób trzecich i trzyma je na twoim serwerze. Do użytku własnego jest to zwykłe zachowanie kopii materiału, do którego miałeś legalny dostęp. Sytuacja zmienia się, gdy instancja jest firmowa i korzysta z niej zespół, a listy są współdzielone albo publicznie linkowane — wtedy nie mówimy już o kopii na własne potrzeby, ale o udostępnianiu cudzych treści dalej. To warto ustalić z kimś, kto odpowiada u was za takie rzeczy, zanim biblioteka podrośnie do kilkudziesięciu tysięcy pozycji.
Druga kwestia to dane osobowe. Archiwum całej strony bierze wszystko: profile, komentarze, imiona, nazwiska, zdjęcia. Jeśli instancja stoi w organizacji, te archiwa są zbiorem danych, dla którego trzeba mieć podstawę przetwarzania i politykę retencji. Silnik reguł nadaje się do wymuszania tej retencji — archiwizowanie automatyczne warto zawęzić do domen, o których wiesz, po co je trzymasz, zamiast zapisywać wszystko, co przeleci przez RSS.
Trzecia to regulaminy serwisów, które crawlujesz. Kontener przeglądarki dostarczany z projektem uruchamia Chrome z flagą --disable-blink-features=AutomationControlled, która ukrywa część sygnałów automatyzacji — bez niej wiele stron nie odda treści przeglądarce bez interfejsu. Przy prywatnym archiwum kilkuset artykułów nikt się tym nie przejmie; przy systematycznym zbieraniu z jednego serwisu na skalę warto sprawdzić, co mówi jego regulamin, i ustawić wspomniane limity na domenę.
I na koniec licencja. AGPL-3.0 to nie MIT: jeśli zmodyfikujesz Karakeepa i udostępnisz go po sieci, obowiązek udostępnienia źródeł tej modyfikacji obejmuje także użytkowników korzystających z niego przez przeglądarkę. Dla zwykłego wdrożenia bez zmian w kodzie nie ma to znaczenia. Dla firmy, która chce dorobić własny moduł i sprzedać go jako część swojej usługi — ma znaczenie zasadnicze.
Pułapki w jednym miejscu
- Pierwsza rejestracja daje administratora, a rejestracja jest domyślnie otwarta. Zarejestruj się przed wystawieniem instancji, potem
DISABLE_SIGNUPS=true. INFERENCE_LANGtoenglish. Ustawpolishprzed pierwszym importem, inaczej przetagowanie zapłacisz drugi raz.- Walidacja adresów wewnętrznych jest pomijana przy skonfigurowanym proxy. Proxy musi mieć własną politykę sieciową i stać poza twoją siecią.
- CLI bez
--server-addrceluje wcloud.karakeep.app. UstawKARAKEEP_SERVER_ADDRi sprawdź przezwhoami. - Pełna archiwizacja strony jest wyłączona domyślnie, a po włączeniu ma 5-sekundowy limit czasu przy własnym limicie monolitu równym 120 s.
- Domyślny
INFERENCE_TEXT_MODELtogpt-5.6-luna— przy innym dostawcy ustaw model jawnie, bo zadania będą cicho padać. Zakomentowany przykład w dokumentacji dostawców AI jest nieaktualny wobec kodu. - Zmiana modelu embeddingów wymusza przeliczenie wszystkich zakładek, a niezgodność
EMBEDDING_DIMENSIONSz nadpisaniem wymiarów blokuje start aplikacji. - Zmiana magazynu zasobów z lokalnego na S3 po fakcie wymaga ręcznej migracji. Zdecyduj przed wdrożeniem.
PROMETHEUS_AUTH_TOKENbez jawnej wartości jest losowany przy każdym starcie — scrapowanie umrze po pierwszym restarcie.- Import nie pozwala wybrać pozycji — wszystkie adresy z pliku wejdą do systemu i pójdą do crawlera.
- Reset hasła administratora to
UPDATEw pliku SQLite. Kto ma wolumen z danymi, ma instancję.
Podsumowanie
Karakeep jest projektem, który robi jedną rzecz szeroko i robi ją dobrze: zbiera to, co znalazłeś, i pilnuje, żeby dało się to potem znaleźć ponownie — nawet gdy oryginał zniknie. W kategorii self-hostowanych zbieraczy zakładek jest dziś najbardziej kompletną propozycją, a po zamknięciu Pocketa ma też najklarowniejszą ścieżkę migracji.
- Realna ochrona przed link rotem — archiwizacja monolitem, zrzuty ekranu, PDF-y i wideo, plus
is:brokendo audytu tego, co już umarło. - Tagowanie bez ręcznej pracy, z możliwością trzymania całej inferencji lokalnie na Ollamie — bez wysyłania biblioteki do zewnętrznego dostawcy.
- Dojrzały język zapytań z kwalifikatorami po typie, źródle, wieku i stanie, zamiast jednego pola „szukaj".
- Kompletny zestaw klientów — trzy przeglądarki, iOS, Android z czytaniem offline, CLI, REST API, webhooki i serwer MCP.
- Przewidywalny stos do utrzymania — Next.js, SQLite, Meilisearch i kontener z Chrome, bez egzotycznych zależności.
- Uczciwa dokumentacja, która sama opisuje słabe punkty crawlera i nie udaje, że problemu nie ma.
Karakeep jest wydany na licencji AGPL-3.0, a właścicielem praw jest Localhost Labs Ltd. Kod jest w całości otwarty — model biznesowy opiera się na hostowanej usłudze Karakeep Cloud, nie na okrojeniu wersji self-hostowanej, i to dobra wiadomość dla każdego, kto stawia ją u siebie. Warunek AGPL uruchamia się dopiero wtedy, gdy zmodyfikowaną wersję udostępniasz innym po sieci: wtedy udostępniasz też źródła swoich zmian. Do wdrożenia „jak jest" nie ma to żadnych konsekwencji.