前言

网站上的优秀文章随时都会消失,因此我一直都有使用稍后读服务收藏文章的习惯。虽然「稍后读」服务名义上是用来「稍后」阅读的,但我更多拿来当收藏夹使用。

既然是收藏夹,那么抓取功能很重要,除了文章内容外,还要能够把原始的图片存储下来。这方面做的比较好的是印象笔记的剪藏插件,虽然我之前续费印象笔记到了 2027 年,但这两年印象笔记越做越差劲,所以我已经开始转战 obsidian,既然不再使用印象笔记,那么它的剪藏插件最好也敬而远之了。

后面我有尝试搭建 Wallabag,但它的抓取功能不是很好,好些网站都无法抓取。除此之外,我也知道有一些付费的软件,比如 Pocket、Cubox、Readwise 等等,他们评价都很不错。但作为折腾党,还是更喜欢自部署相关的开源服务,把数据都掌握在自己的手里。

再之后我就发现了 Omnivore 稍后读服务,它的抓取功能相当不错,并且开源。但不足的是,它依赖过重,自部署较为麻烦,网上虽然有看到一些自部署的文章,但都不是官方的途径,担心不稳定,因此我也都没有尝试。

去年 Omnivore 宣布它不再提供服务,同时社区方面表示会加快实现依赖项的解耦,进而让用户更加轻松的实现自部署。在获得这个消息之后,我一直有关注相关的进展。直到最近,它的自部署文档 Self Hosting GUIDE 已经相当完善,我决定开始进行自部署的尝试。

目前已经部署使用了两天,就收藏方面还未发现什么 bug,比较流畅。部署过程中,踩了一些小坑,做个小结。

部署

基于文档 Self Hosting GUIDE,Omnivore 的部署非常简单。

  1. 克隆仓库 git@github.com:omnivore-app/omnivore.git
  2. 进入目录 self-hosting/docker-compose
  3. 将目录下的 .env.example 重命名为 .env
  4. 修改 .env 文件中 BASE URLSERVER_BASE_URL 等几个环境变量,这里需要特别说明下。
    1. 假设最终要通过 nginx 或是 caddy 对 Omnivore 进行反代,而反代的域名是 omnivore.app,同时使用 https 协议。
    2. 那么 BASE URLSERVER_BASE_URLHIGHLIGHTS_BASE_URLCLIENT_URL 这个环境变量全都改为 https://omnivore.app
    3. IMAGEPROXY_URL 环境变量则需要改为 https://omnivore.app/images。若像其他变量那样直接设为域名会有问题,详见 issue
  5. 执行 docker compose up 启动服务,观察是否有错误。若无错误后,可 ctrl+c 终止,并使用命令 docker compose up -d 后台执行。
  6. 若无问题,可以配置 nginx 或是 caddy 进行反代了,仓库中有提供 nginx 示例配置,我使用的是 caddy,在附录部分也提供一个配置供参考。
  7. 反代配置好后,通过自己的域名以及默认的用户邮箱 demo@omnivore.app,密码 demo_password 访问了。如果需要新建用户,直接在登录页面使用自己的邮箱新建用户即可。
  8. 至此,自建其实已经结束了,在文档后续还有一些可选配置,比如一些邮箱服务器的搭建等,对于个人使用来说,可不需要。

支持自部署参数的浏览器插件还在审核中,对于 Chrome 系浏览器来说,可以先开启「开发者模式」本地加载插件,插件在仓库的 pkg/extension-v3/extension 目录下。

加载后,对插件进行设置,其中 API Key 在 Omnivore WEB 端进行申请,而 API URLOMNIVORE URL 均设置为 https://omnivore.app(假设反代的域名是 https://omnivore.app)。

浏览器插件设置

最新版本的 IOS 客户端也支持了自部署参数的设置,按下图设置,之后保存登录即可。

IOS客户端设置

附录

caddy 反代配置,假设域名是 omnivore.app

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
omnivore.app {
		handle /api/client/auth {
			encode zstd gzip
			reverse_proxy 127.0.0.1:3000 {
				lb_policy ip_hash
			}
		}

		handle /api/save {
			encode zstd gzip
			reverse_proxy 127.0.0.1:3000 {
				lb_policy ip_hash
			}
		}

		handle /api* {
			encode zstd gzip
			reverse_proxy 127.0.0.1:4000 {
				lb_policy ip_hash
			}
		}

		handle /mail* {
			encode zstd gzip
			reverse_proxy localhost:4398/mail
		}

		handle /bucket* {
			reverse_proxy 127.0.0.1:1010 {
				lb_policy ip_hash
			}
		}

		handle_path /images/* {
			reverse_proxy 127.0.0.1:7070 {
				lb_policy ip_hash
			}
		}

		handle /* {
			encode zstd gzip
			reverse_proxy 127.0.0.1:3000 {
				lb_policy ip_hash
			}
		}
	}
}