Karakeep(原 Hoarder)自托管故障排查完全指南:数据库、AI 打标、抓取与 Meilisearch 升级
【免费下载链接】hoarderA self-hostable bookmark-everything app (links, notes and images) with AI-based automatic tagging and full text search项目地址: https://gitcode.com/GitHub_Trending/ho/hoarder
Karakeep 是一款可自托管的"收藏一切"应用(书签、笔记与图片),支持基于 AI 的自动打标与全文搜索。本指南以 v0.32.0 官方 Troubleshooting 文档为骨架,结合仓库源码与 Docker 编排配置,系统梳理自托管部署中最常见的五类故障——SQLite 数据库未初始化、Chrome 容器日志噪音、OpenAI/Ollama AI 打标失效、抓取失败以及 Meilisearch 版本迁移——并给出可复现的定位方法与修复步骤。读完本文,你将能够根据容器日志与 docker-compose.yml 中的环境变量逐项排查,并安全完成 Meilisearch 索引重建。
故障排查的通用方法论:先看日志,再查配置
原文档在每一节都强调同一件事:先检查容器日志。这一原则在源码层面有直接对应——例如推理 worker 在onError回调中会记录失败信息(见 inferenceWorker.ts),爬虫在连接浏览器失败时会输出Failed to connect to the browser instance, will retry in 5 secs(见 browser.ts)。因此,所有排查都应从以下命令开始:
# 查看 web 容器日志(数据库、推理、抓取等核心逻辑都在 web 容器中) docker compose logs -f web # 查看 Meilisearch 容器日志(索引与版本兼容问题) docker compose logs -f meilisearch # 查看 Chrome 容器日志(抓取相关) docker compose logs -f chrome此外,Karakeep 的日志级别由LOG_LEVEL环境变量控制,默认值为debug(见 config.ts),这意味着默认部署下日志信息已经足够详细,可直接用于定位绝大多数问题。
SqliteError: no such table: user
错误含义与产生原理
这个错误通常意味着数据库没有完成初始化。Karakeep 使用 SQLite 作为主数据库(通过 Drizzle ORM 管理 schema),首次启动时应用会自动执行数据库迁移、创建user等核心表。如果应用启动时发现已有数据库文件但内容不完整(或根本没有数据库文件),就会出现no such table: user。
两种常见原因与修复
原文档给出了两类典型触发场景:
DATA_DIR 被清空(Wiped DATA_DIR):
DATA_DIR指向的目录被清空,或者底层存储目录发生了变更。如果是有意清空数据,只需重启容器,让应用重新初始化数据库即可:docker compose restart webDATA_DIR 未配置(Missing DATA_DIR):如果你没有使用默认的 docker-compose.yml,而是自定义了编排文件,却忘了设置
DATA_DIR环境变量,就会导致数据库被初始化到服务实际读取目录之外的其他位置,从而出现"表不存在"。
源码级补充:DATA_DIR 的默认值与其派生路径
从 config.ts 可以看到,DATA_DIR的 schema 定义为z.string().default("")——即默认是空字符串,这解释了为什么自定义编排时漏配该变量会出问题。更重要的是,DATA_DIR还会派生其他关键路径:assetsDir默认为path.join(val.DATA_DIR, "assets")(见 config.ts),即附件目录默认挂在数据目录之下。
而在默认编排中,官方明确写死了DATA_DIR: /data并注释DON'T CHANGE THIS(见 docker-compose.yml),同时通过卷映射data:/data(docker-compose.yml)把 Docker 卷持久化到宿主机。官方注释还指出:如果你希望把数据挂载到自定义目录,应该修改卷映射(volume mapping)而不是 DATA_DIR 的值,例如:
volumes: - /path/to/your/directory:/data也就是说:容器内的/data是固定约定,宿主机侧的持久化位置由卷映射决定;擅自改动DATA_DIR值反而容易造成数据库与附件目录分裂、读写错位。
Chrome Failed to Read DnsConfig
如果你在 Chrome 容器日志中看到Failed to Read DnsConfig,这是一个良性错误,可以安全忽略。它与你在 Karakeep 中遇到的任何实际问题都无关。该错误源于 Chromium 在读取宿主 DNS 配置时的一种已知行为,属于噪音日志。
AI Tagging not working(OpenAI 场景)
Karakeep 的 AI 打标、摘要等功能由独立的推理 worker 执行。当使用 OpenAI 时打标不生效,先看web容器日志,通常问题出在以下几点:
OPENAI_API_KEY变量名拼写错误:这会导致日志出现类似skipping inference as it's not configured(跳过推理,因为它未配置)的提示。源码中,推理功能是否配置取决于!!val.OPENAI_API_KEY || !!val.OLLAMA_BASE_URL(见 config.ts)——只要这两个变量都为空,系统就认为推理未配置并跳过,而不会明确报错,因此拼写错误极易被忽视。配置后忘记执行
docker compose up:修改.env或环境变量后,必须重建/重启容器使配置生效:docker compose up -d注意:仅仅是
docker compose restart不一定会重新加载所有环境变量,稳妥做法是up -d让编排重新解析配置。OpenAI 账户余额不足:OpenAI 要求账户预先充值,否则会返回类似
insufficient funds的错误。
源码级补充:推理相关的关键环境变量
从 config.ts 可以整理出 OpenAI 场景下与推理直接相关的变量及其默认值:
| 环境变量 | 默认值 | 说明 |
|---|---|---|
OPENAI_API_KEY | 无(可选) | OpenAI API 密钥,推理配置的判定依据之一 |
OPENAI_BASE_URL | 无(可选) | 自定义 OpenAI 兼容端点 |
OPENAI_PROXY_URL | 无(可选) | 代理 URL |
INFERENCE_TEXT_MODEL | gpt-5.6-luna | 文本推理模型(打标/摘要) |
INFERENCE_IMAGE_MODEL | gpt-4o-mini | 图片推理模型 |
INFERENCE_ENABLE_AUTO_TAGGING | true | 是否启用自动打标 |
INFERENCE_ENABLE_AUTO_SUMMARIZATION | false | 是否启用自动摘要 |
另外,若你设置了自定义OPENAI_BASE_URL但未显式设置INFERENCE_USE_MAX_COMPLETION_TOKENS,源码会默认将其置为false(见 config.ts),这是因为默认的 gpt 5.6 系列模型需要该开关为true——这条逻辑同样适用于 Ollama 场景,值得留意。
AI Tagging not working(Ollama 场景)
使用 Ollama 本地模型时打标失效,同样先从日志入手。原文档列出的常见原因:
OLLAMA_BASE_URL变量名拼写错误:同样会导致skipping inference as it's not configured日志。该变量在 config.ts 中定义为z.string().url().optional()——注意它是URL 类型校验,如果你填写的值不是一个合法 URL(例如漏了协议头http://),配置解析本身就会失败。配置后忘记执行
docker compose up:同上,修改后需重建容器。没有修改
INFERENCE_TEXT_MODEL:这是 Ollama 场景最典型的坑。INFERENCE_TEXT_MODEL的默认值是gpt-5.6-luna(见 config.ts),如果不改,Karakeep 会拿着 GPT 模型名去请求 Ollama,而 Ollama 中并不存在该模型,自然无法工作。使用 Ollama 时应显式指定为已拉取的模型,例如:INFERENCE_TEXT_MODEL: llama3.1Ollama 服务对 Karakeep 容器不可达,具体又分两种情况:
- Ollama 服务器与 Karakeep 容器不在同一个 Docker 网络(network)中;
- 把
OLLAMA_BASE_URL配成了localhost。在 Docker 中,localhost指向的是容器自身而非 Docker 宿主机。要访问宿主机服务,需要按你的 Docker 平台选择正确的主机地址(Linux 可用host.docker.internal或宿主机网关 IP,macOS/Windows 桌面版通常直接支持host.docker.internal),或让 Ollama 与 Karakeep 加入同一自定义网络并使用服务名。
源码级补充:推理 worker 的实际执行路径
Ollama/OpenAI 的推理任务最终由OpenAiWorker消费队列执行:runOpenAI会读取serverConfig.inference中的模型与端点配置(见 inferenceWorker.ts),任务完成后通过attemptMarkStatus把书签的taggingStatus/summarizationStatus更新为success或failure(inferenceWorker.ts)。因此,当你在管理界面看到书签的 tagging 状态一直处于 pending/failure 时,直接去 web 容器日志里查推理 worker 输出的具体错误(如模型不存在、连接超时、余额不足),是最快的定位路径。
Crawling not working(抓取失效)
抓取功能依赖独立的 Chrome 容器(karakeep-app/karakeep-chrome)通过 CDP 协议提供浏览器能力。爬虫 worker 在启动时会读取BROWSER_WEB_URL并调用chromium.connectOverCDP连接该地址,同时解析其主机名对应的 IP 后再发起连接(见 browser.ts);连接失败时每 5 秒重试一次并记录错误。
原文档指出的最常见原因是:你改了 Chrome 容器的名字(service 名称),却没有同步修改BROWSER_WEB_URL环境变量。默认编排中,web 容器通过服务名chrome访问浏览器:BROWSER_WEB_URL: http://chrome:9222(见 docker-compose.yml)。一旦你把 Chrome 服务的名字改成my-chrome之类的自定义名称,而BROWSER_WEB_URL仍指向http://chrome:9222,Docker 内部 DNS 将无法解析该主机名,抓取随即失败。
修复方法:保持两者一致。改容器名时同步更新:
environment: BROWSER_WEB_URL: http://my-chrome:9222 # 与新的 service 名保持一致若你完全没有独立的 Chrome 容器(例如browserless模式),爬虫会记录Running in browserless mode并返回undefined(browser.ts),这种情况下请确认你的部署方式确实不需要浏览器容器。
Upgrading Meilisearch:数据库版本迁移与索引重建
为什么 Meilisearch 版本不能随意升级
Meilisearch 是 Karakeep 用于书签搜索的全文检索引擎。当前仓库锁定的版本是v1.41.0(见 docker-compose.yml),官方建议没有充分理由不要升级。Meilisearch 的数据文件格式与引擎版本强绑定,升级后你会看到类似这样的错误:
Your database version (x.x.x) is incompatible with your current engine version (x.x.x). To migrate data between Meilisearch versions, please follow our guide on ...官方推荐的变通修复步骤
好消息是这个问题可以快速绕过——因为书签数据本身存在 SQLite 主数据库中,Meilisearch 里的索引只是可重建的派生数据。步骤如下:
停止 Meilisearch 容器:
docker compose stop meilisearch删除或重命名数据目录:进入 Meilisearch 卷挂载到
/meili_data的位置,删除或重命名其中的data.ms文件夹。使用默认编排时,该目录位于名为meilisearch的 Docker 卷中(见 docker-compose.yml):# 重命名比删除更稳妥,可在确认一切正常后再清理 docker compose run --rm -v meilisearch:/meili_data alpine mv /meili_data/data.ms /meili_data/data.ms.bak重新启动 Meilisearch:
docker compose up -d meilisearch在管理界面触发全量重建索引:以管理员身份登录 Karakeep,进入
Admin Settings > Background Jobs(管理设置 > 后台任务),点击Reindex All Bookmarks(重建所有书签索引)。等待重建完成:索引重建完成后,搜索功能恢复正常。
源码级补充:Reindex All Bookmarks 到底做了什么
Reindex All Bookmarks对应 tRPC 路由admin.reindexAllBookmarks(见 admin.ts)。其内部逻辑分为两步:
- 若未指定
modifiedWithinSeconds过滤条件,先调用搜索客户端执行clearIndex()清空现有索引(admin.ts); - 从 SQLite 中查出全部(或指定时间窗口内修改的)书签 ID,逐个以低优先级(
QueuePriority.Low)投递triggerSearchReindex任务(admin.ts),由搜索 worker 异步完成重建。
对应的测试用例也验证了这条链路:reindexAllBookmarks会调用triggerSearchReindex且优先级为低(见 admin.test.ts)。因此你可以放心:清空索引后,只要等待后台任务跑完,搜索即可恢复,无需手动恢复任何数据——书签数据从未丢失,丢失的只是可重建的搜索索引。
另外,如果你只想重建部分书签(例如最近 7 天修改过的),也可以利用该接口支持的modifiedWithinSeconds参数做定向重建,避免全量扫描。
排查速查表
| 症状 | 优先查看的日志 | 最常见根因 | 一键修复 |
|---|---|---|---|
SqliteError: no such table: user | web | DATA_DIR 缺失或被清空 | 配置DATA_DIR: /data或重启容器 |
Chrome Failed to Read DnsConfig | chrome | 良性噪音 | 忽略 |
| AI 打标不生效(OpenAI) | web | OPENAI_API_KEY拼写错误 / 未up/ 余额不足 | 修正变量名、docker compose up -d、充值 |
| AI 打标不生效(Ollama) | web | OLLAMA_BASE_URL拼错、INFERENCE_TEXT_MODEL未改、网络不可达 | 修正配置并指定本地模型名 |
| 抓取失效 | web + chrome | 容器改名后BROWSER_WEB_URL未同步 | 让两者保持一致 |
| Meilisearch 版本不兼容 | meilisearch | 升级了非 1.41.0 引擎 | 删除data.ms并重建索引 |
延伸阅读
- 完整的环境变量说明见 环境变量文档 与解析实现 config.ts;
- 不同 AI 提供商的配置方式见 AI 提供商配置;
- 默认部署编排与卷定义见 docker-compose.yml;
- 更多部署方式(Docker、K8s、Unraid 等)见 安装文档;
- 数据库迁移脚本与 schema 定义位于 packages/db,如需彻底重建数据库可参考 数据库文档。
【免费下载链接】hoarderA self-hostable bookmark-everything app (links, notes and images) with AI-based automatic tagging and full text search项目地址: https://gitcode.com/GitHub_Trending/ho/hoarder
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考