资讯动态

自建开源稍后读服务Nagi:Go+Svelte+SQLite构建个人知识库

发布时间:2026/8/9 2:41:32 来源:尧图企业网站定制
1. 项目概述与核心价值最近在折腾个人知识库和自动化工作流发现一个痛点每天接触的信息源太多RSS订阅、邮件列表、社交媒体、技术论坛信息像洪水一样涌来但真正有价值、需要后续跟进或深度阅读的内容却常常淹没在信息流里要么忘了看要么想找的时候找不到。我需要一个能帮我“暂存”和“稍后阅读”的私人助理。市面上这类工具不少但要么功能太重要么数据不归自己管要么就是订阅费用不菲。直到我遇到了yukihirop/nagi一个开源的、自托管的“稍后读”服务它用极简的哲学和强大的技术栈完美地解决了我的问题。yukihirop/nagi本质上是一个个人书签和文章存档管理器。它的核心功能非常聚焦你给它一个网页链接它能帮你把网页内容“抓取”下来不仅仅是保存一个链接而是将文章正文、图片等内容完整地保存到你的服务器上形成一个永久的、可搜索的、离线的个人知识库。想象一下你不再需要担心原链接失效404错误是知识管理的天敌也不用受网络环境限制随时随地都能翻阅你收藏的深度好文。这个项目特别适合开发者、研究者、内容创作者以及任何有信息整理和深度阅读习惯的人。项目采用的技术栈也体现了其“精致而强大”的定位。后端基于 Go 语言开发确保了高性能和低资源占用前端使用 Svelte 框架带来了流畅的交互体验数据存储默认使用 SQLite这意味着部署极其简单单文件搞定无需维护复杂的数据库服务而内容抓取和解析则依赖于强大的readability算法能智能地从纷繁的网页中提取出核心的正文内容。接下来我就结合自己从零部署、深度使用到二次开发的经验把这个项目的里里外外彻底拆解一遍。2. 技术架构与核心组件解析2.1 整体架构设计思路nagi采用了经典且高效的前后端分离架构但它的巧妙之处在于将复杂度隐藏在了背后给用户呈现的是一个极其简单的整体。整个系统可以看作由四个核心层构成用户交互层基于 Svelte 构建的 Web 界面。这一层负责所有用户操作比如添加链接、管理列表、搜索、阅读。Svelte 的编译时框架特性使得最终生成的代码量小、运行效率高这对于一个可能常驻后台打开的个人工具来说体验上的流畅感至关重要。应用逻辑层由 Go 语言编写的后端 API 服务。这是整个系统的大脑它接收前端的请求协调调度其他组件完成任务。Go 语言的并发模型goroutine在这里大放异彩例如当你提交一个链接进行抓取时后端可以异步处理这个耗时任务立即返回响应而不阻塞你的其他操作。同时Go 对 HTTP 协议的原生良好支持和高效的 JSON 处理能力使得 API 设计既简洁又快速。数据处理与存储层核心是 SQLite 数据库。所有元数据如文章标题、原始URL、抓取时间、标签、归档状态等都存储在这里。选择 SQLite 而非 MySQL 或 PostgreSQL是nagi追求极致简化部署的关键决策。它意味着你不需要额外安装和配置数据库服务整个应用的数据就是一个.db文件备份和迁移变得异常简单。对于个人使用场景SQLite 的性能完全绰绰有余。内容获取与处理层这是项目的“魔法”所在。主要由两部分组成1)网络爬虫模块模拟浏览器访问目标链接获取完整的 HTML 内容。2)内容解析引擎集成或类似 Mozilla 的readability库的算法它能智能地剔除导航栏、广告、侧边栏等噪音精准地提取出文章标题和正文主体并尝试保留基本的格式如段落、加粗、列表和图片。注意内容抓取涉及网络请求和资源解析其成功率和效果高度依赖于目标网站的结构以及是否有反爬机制。nagi通常能很好地处理大多数新闻、博客和技术文章网站。2.2 关键依赖与技术选型理由深入看几个关键的技术选型能更好地理解作者的设计哲学Go SQLite轻量级服务器的黄金组合Go 编译后是单个静态二进制文件依赖少部署就是复制一个可执行文件。SQLite 数据库也是一个文件。两者结合使得nagi的整个后端和数据可以轻松放在任何支持运行二进制文件的 Linux 服务器、甚至树莓派上。资源占用极低我的一个运行实例内存常驻在 50MB 以下。这对于希望 24 小时运行在低配 VPS 或 NAS 上的用户来说是决定性优势。Svelte追求极致用户体验的前端选择与 React 或 Vue 相比Svelte 在构建时就将组件编译成高效的原生 JavaScript 代码而非在运行时引入一个庞大的框架库。这带来的直接好处是首屏加载更快页面交互更流畅。对于nagi这种工具型应用快速打开、即时搜索的体验非常重要。Svelte 的语法也更简洁降低了前端部分的认知负担。Readability 内容解析准确性的核心“稍后读”工具的灵魂在于能否干净地提取内容。nagi使用的解析算法经过多年优化能识别文章的主体内容区域。它通过分析 HTML 的标签密度、类名如article,content,post-body、语义结构等特征计算出一个“可读性”分数从而找到并提取正确的部分。这比简单的正则匹配或基于特定模板的抓取要鲁棒得多能适应更广泛的网站。3. 从零开始部署与配置实战3.1 环境准备与二进制部署最简方案假设你有一台运行 Linux 的云服务器如 Ubuntu 22.04或本地开发机。部署nagi最快捷的方式是使用官方发布的预编译二进制文件。首先通过 SSH 连接到你的服务器。我们创建一个专用的用户和目录来运行nagi这有利于权限管理和安全。# 以root或具有sudo权限的用户登录 # 创建系统用户‘nagi’并禁止其登录shell sudo useradd -r -s /bin/false nagi # 创建应用目录 sudo mkdir -p /opt/nagi sudo mkdir -p /opt/nagi/data # 用于存放数据库和抓取的内容 sudo mkdir -p /opt/nagi/logs # 将目录所有权赋予 nagi 用户 sudo chown -R nagi:nagi /opt/nagi接下来下载最新版本的nagi二进制文件。你需要去项目的 GitHub Release 页面查看最新版本号。# 进入临时目录 cd /tmp # 假设最新版本是 v0.8.1架构是 amd64。请根据实际情况替换。 Nagi_VERSIONv0.8.1 wget https://github.com/yukihirop/nagi/releases/download/${Nagi_VERSION}/nagi_${Nagi_VERSION#v}_linux_amd64.tar.gz # 解压 tar -xzf nagi_${Nagi_VERSION#v}_linux_amd64.tar.gz # 通常解压后是一个名为 ‘nagi’ 的二进制文件 sudo mv nagi /usr/local/bin/ sudo chmod x /usr/local/bin/nagi现在我们需要一个配置文件。nagi支持通过环境变量或配置文件如config.yaml进行配置。我们创建一个简单的配置文件。sudo -u nagi bash -c cat /opt/nagi/config.yaml EOF server: host: 0.0.0.0 # 监听所有网络接口 port: 8080 # 服务端口 database: path: /opt/nagi/data/nagi.db # SQLite数据库路径 archive: storage_path: /opt/nagi/data/archive # 文章内容存档的目录 EOF提示将服务绑定到0.0.0.0意味着可以从网络上的其他机器访问。如果你只在本地使用可以改为127.0.0.1以增强安全性。3.2 配置系统服务实现开机自启为了让nagi在后台稳定运行并在系统重启后自动启动我们将其配置为 systemd 服务。创建服务单元文件sudo nano /etc/systemd/system/nagi.service将以下内容粘贴进去注意调整路径与你实际环境一致[Unit] DescriptionNagi - Self-hosted read-it-later service Afternetwork.target [Service] Typesimple Usernagi Groupnagi WorkingDirectory/opt/nagi EnvironmentFile-/opt/nagi/config.env # 可选如果需要环境变量 ExecStart/usr/local/bin/nagi --config /opt/nagi/config.yaml Restarton-failure RestartSec5s StandardOutputappend:/opt/nagi/logs/nagi.out.log StandardErrorappend:/opt/nagi/logs/nagi.err.log # 安全加固 NoNewPrivilegestrue PrivateTmptrue ProtectSystemstrict ReadWritePaths/opt/nagi/data /opt/nagi/logs [Install] WantedBymulti-user.target保存并退出编辑器。然后启动服务并设置开机自启# 重新加载systemd配置 sudo systemctl daemon-reload # 启动nagi服务 sudo systemctl start nagi # 检查服务状态确认运行正常 sudo systemctl status nagi # 启用开机自启 sudo systemctl enable nagi如果状态显示active (running)恭喜你nagi服务端已经部署成功现在你可以通过浏览器访问http://你的服务器IP:8080来使用它了。3.3 反向代理与HTTPS配置生产环境必备直接通过 IP:端口访问不够优雅也不安全。我们通常使用 Nginx 作为反向代理并配置 HTTPS。首先安装 Nginx 和 Certbot用于申请 Let‘s Encrypt 免费SSL证书sudo apt update sudo apt install nginx certbot python3-certbot-nginx -y为nagi创建一个 Nginx 站点配置文件sudo nano /etc/nginx/sites-available/nagi输入以下配置将your-domain.com替换为你自己的域名server { listen 80; server_name your-domain.com; # 你的域名 # 将HTTP请求重定向到HTTPS由Certbot自动配置后生效 location / { return 301 https://$server_name$request_uri; } } server { listen 443 ssl http2; server_name your-domain.com; # SSL证书路径将由Certbot自动填充 ssl_certificate /etc/letsencrypt/live/your-domain.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/your-domain.com/privkey.pem; # SSL优化配置可选但推荐 ssl_protocols TLSv1.2 TLSv1.3; ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512; ssl_prefer_server_ciphers off; # 反向代理到本地的nagi服务 location / { proxy_pass http://127.0.0.1:8080; 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; # 以下两行对于WebSocket或某些API可能很重要 proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection upgrade; } # 静态资源缓存如果nagi有独立的前端资源 # location /static/ { # alias /path/to/static/; # expires 1y; # } }启用该站点并测试 Nginx 配置sudo ln -s /etc/nginx/sites-available/nagi /etc/nginx/sites-enabled/ sudo nginx -t # 测试配置语法 sudo systemctl reload nginx现在使用 Certbot 自动获取并配置 SSL 证书sudo certbot --nginx -d your-domain.com按照 Certbot 的提示操作主要是提供邮箱地址并同意服务条款。完成后Certbot 会自动修改你的 Nginx 配置文件启用 HTTPS 并设置好自动续期。至此你已经拥有了一个通过安全域名访问的、自托管的“稍后读”服务。打开https://your-domain.com即可开始使用。4. 核心功能使用详解与高级技巧4.1 文章添加、抓取与归档流程nagi的界面通常非常简洁。主界面会有一个醒目的输入框用于添加链接。你可以手动粘贴链接但更高效的方式是使用浏览器书签工具。浏览器书签工具Bookmarklet这是提升体验的关键。你可以在nagi的设置页面找到一段 JavaScript 代码将其保存为浏览器的书签。之后在任何你想保存的网页上点击这个书签页面链接就会自动发送到你的nagi服务器并开始抓取。这比复制、切换标签页、粘贴流程快得多。抓取过程解析当你提交一个链接后后端服务会启动一个异步任务HTTP 请求使用 Go 的 HTTP 客户端访问目标 URL并携带合理的 User-Agent 头模拟普通浏览器访问。内容解析将获取到的 HTML 传递给readability解析器。解析器会计算并找出正文区域提取出干净的标题和内容。资源处理对于内容中的图片nagi通常有两种策略a) 保留原始外链。b) 更推荐的方式是将图片下载并存储到本地的storage_path目录下并在内容中将图片链接替换为本地路径。这实现了真正的“离线归档”防止因原图床失效导致文章“破图”。元数据提取与存储将标题、清理后的正文、原始URL、抓取时间戳、可能的作者信息等一并存入 SQLite 数据库。文章内容本身通常以 HTML 或 Markdown 格式存储在数据库的某个字段或关联的文件中。归档与管理抓取成功后文章会出现在“未读”或“所有文章”列表中。你可以阅读点击进入阅读视图享受无干扰的纯净阅读体验。加标签为文章添加一个或多个标签如#golang,#devops,#toread这是后续高效检索的关键。标记已读/未读管理阅读状态。搜索nagi的搜索功能会遍历文章标题、内容和标签帮助你快速定位。删除移除不再需要的文章。4.2 数据备份、迁移与恢复策略你的所有知识积累都在/opt/nagi/data目录下。定期备份这个目录至关重要。简单备份脚本#!/bin/bash # backup_nagi.sh BACKUP_DIR/path/to/your/backup SOURCE_DIR/opt/nagi/data DATE$(date %Y%m%d_%H%M%S) BACKUP_FILE${BACKUP_DIR}/nagi_backup_${DATE}.tar.gz # 创建备份 tar -czf ${BACKUP_FILE} -C ${SOURCE_DIR} . # 可选删除超过30天的旧备份 find ${BACKUP_DIR} -name nagi_backup_*.tar.gz -mtime 30 -delete echo Backup completed: ${BACKUP_FILE}你可以使用cron定时任务如每天凌晨3点自动执行这个脚本。迁移到新服务器在新服务器上按照“3.1”和“3.2”步骤部署nagi服务但先不要启动。将旧服务器上/opt/nagi/data整个目录打包复制到新服务器的相同位置并确保权限正确chown -R nagi:nagi /opt/nagi/data。启动新服务器上的nagi服务。因为数据库路径和存档路径一致所有数据和文章都会完美呈现。4.3 性能调优与安全加固建议随着存档文章越来越多比如超过一万篇一些优化可以保证体验始终流畅。数据库索引优化nagi的数据库表可能已经建立了基础索引。但如果你自定义了复杂的查询例如通过API可以检查articles表的title,created_at和标签关联表上是否有索引。可以使用 SQLite 命令行工具.schema查看或通过EXPLAIN QUERY PLAN分析慢查询。不过对于个人使用量通常无需手动干预。存档文件存储优化如果开启了图片本地化archive目录可能会增长很快。可以考虑定期使用find命令清理抓取失败的临时文件。如果使用云服务器可以将archive目录挂载到单独的大容量云硬盘上。实现一个简单的脚本将超过一定时间如2年的旧文章图片压缩存储。安全加固防火墙确保服务器防火墙如ufw只开放了 80/443 端口关闭了不必要的端口如原始的 8080。服务隔离我们之前已经用独立的nagi系统用户运行服务限制了权限。定期更新关注nagi项目的 GitHub 发布页及时更新到新版本修复可能的安全漏洞。访问控制目前的nagi版本通常没有内置的多用户和密码认证。如果你将其暴露在公网这是一个风险点。解决方案是使用 Nginx 的 HTTP 基础认证或更安全的 OAuth 代理如oauth2-proxy来为整个服务添加一个登录门槛。配置 Nginx 基础认证示例# 安装htpasswd工具 sudo apt install apache2-utils # 创建密码文件用户名设为‘me’ sudo htpasswd -c /etc/nginx/.htpasswd me # 输入并确认密码然后在 Nginx 配置的location /块内添加auth_basic Restricted Access; auth_basic_user_file /etc/nginx/.htpasswd;这样访问你的nagi服务前就需要先输入用户名和密码了。5. 常见问题排查与二次开发入门5.1 部署与运行常见问题速查即使按照步骤操作也可能会遇到一些问题。这里记录几个我踩过的坑和解决方法。问题1服务启动失败日志显示 “permission denied” 或 “read-only database”。原因最可能是/opt/nagi/data目录的权限不对nagi用户没有写入权限。解决sudo chown -R nagi:nagi /opt/nagi/data并确保该目录及其父目录的权限至少是755。问题2可以打开网页但添加链接后一直显示“抓取中”或失败。原因A服务器无法访问外网。nagi需要能访问你提交的网址。排查在服务器上运行curl -I https://example.com测试网络连通性。原因B目标网站有反爬机制如 Cloudflare 5秒盾简单的 HTTP 请求被拦截。解决这是自建抓取工具的普遍难题。可以尝试在nagi的配置中如果支持修改 User-Agent模拟更真实的浏览器。有些高级用法可以通过修改源码为 HTTP 客户端添加延迟、使用代理池等但这比较复杂。对于这类网站手动复制粘贴正文可能是更实际的选择。问题3抓取的文章内容不完整或全是乱码。原因readability解析器对某些特定网站结构识别不佳或网页编码不是 UTF-8。解决检查原网页看是否内容本身就需要复杂交互如大量 JavaScript 渲染才能加载nagi的简单爬虫无法处理此类页面。这是一个开源项目你可以尝试在项目的 Issue 页面搜索该网站看是否有其他人遇到同样问题或已有解决方案。有时需要针对特定网站调整解析规则。问题4Nginx 配置后访问出现 502 Bad Gateway。原因Nginx 无法连接到后端的nagi服务。排查确认nagi服务正在运行sudo systemctl status nagi。确认nagi监听的端口默认8080与 Nginxproxy_pass配置一致。检查防火墙是否允许本地回环127.0.0.1的通信。5.2 基础二次开发与功能扩展思路nagi项目结构清晰代码质量高非常适合作为 Go Svelte 全栈学习的范本也便于进行自定义扩展。1. 修改前端界面Svelte 前端代码通常在web或frontend目录。如果你想修改主题颜色、调整布局或增加一个显示字数的统计信息可以在这里操作。步骤安装 Node.js 和 pnpm/npm进入前端目录运行pnpm install安装依赖然后pnpm run dev启动开发服务器。修改src目录下的 Svelte 组件实时预览效果。最后pnpm run build编译生成静态文件替换掉后端服务默认嵌入的前端资源即可。2. 添加新的API接口Go 假设你想增加一个批量导出所有文章标题和URL为CSV的功能。定位路由Go 后端代码通常使用类似 Gin 或 Echo 的 Web 框架路由定义在main.go或routes/目录下的文件中。添加处理器在handlers/目录下新建一个函数例如HandleExportCSV。在这个函数里编写从数据库查询所有文章的代码使用 Go 的encoding/csv包生成 CSV 数据并设置正确的 HTTP 响应头Content-Type: text/csv和Content-Disposition: attachment。注册路由在路由定义文件中将新的路径如/api/export/csv映射到你刚写的处理器函数。编译部署在项目根目录运行go build -o nagi .重新编译用新的二进制文件替换旧的并重启服务。3. 集成其他服务Webhook 或 API 调用nagi本身可能没有提供与第三方服务如 Notion, Obsidian的集成但你可以通过其 API如果提供或直接操作数据库来实现自动化。思路A使用 nagi 的 API查看项目文档或源码看是否有用于获取文章列表、详情的 API。你可以写一个定时脚本调用这些 API 获取新文章然后通过 Notion 或 Obsidian 的 API 同步过去。思路B直接读取 SQLite 数据库因为数据库是单文件你可以用任何支持 SQLite 的语言Python, Node.js编写一个脚本定期查询articles表处理数据后推送到你想去的任何地方。这种方式更直接但需要注意在服务不运行时操作避免数据损坏。4. 增强内容抓取能力 这是更进阶的修改。你可以修改 Go 后端中负责抓取的模块可能在pkg/fetcher或internal/crawler。增加请求头修改 HTTP 请求添加Referer,Accept-Language等让请求更像真人浏览器。处理 JavaScript 渲染集成一个无头浏览器库如chromedp来抓取依赖 JavaScript 的动态内容。但这会显著增加资源消耗和抓取时间。自定义解析规则针对你常看的、但解析效果不好的特定网站可以编写针对性的解析函数覆盖默认的readability逻辑。进行二次开发前务必先通读项目的README.md、CONTRIBUTING.md文档并熟悉 Go 和 Svelte 的基础知识。从小的修改开始逐步深入你会对这个精致的工具有更深刻的理解也能让它更贴合你的个人工作流。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价