Mastodon 和 Gitea 的静态替代品
就像我当时决定换掉 Wordpress 一样,我觉得我已经受够了运行 Mastodon 和 Gitea。
跟上 Gitea 设置选项的频繁改变一直很烦人,而使用 Mastodon 时,由于系统库版本不匹配(通常是 protobuf)造成的依赖软件包出错十分常见。尽管后者不是 Mastodon 本身的错,但需要额外安装两个软件包管理器(分别用于 Ruby 和 Node.js)来运行一个程序对我来说是很荒谬的。
我于 2018 年开始在服务器上运行两者:先开始的是作为 Twitter 替代品的 Mastadon,而 Gitea 则是我后来对微软收购 Github 的回应。回头想想,相对于我的需求,这有点大材小用:我的 git 服务器和微型博客的主要用例都是单用户中心的只写任务。这意味着这些内容应以只读形式提供给我网站的访问者,而静态网页正是完美的替代品。
从 Mastadon 开始说起,我现在使用 twtxt 格式存储和发布我的微型博客。这一格式已经存在了一段时间,但最近在波浪号社区(tildeverse,一系列提供可公共访问的类 Unix 系统的网站)中开始重新流行。尽管现在有一整个旨在为该格式添加更多功能的社区支持的生态系统(其中包含各种语法扩展和软件),但我发现最基本的的时间戳加制表键加文字的语法已足够满足我的需求。这种即写即忘的形式确实很容易上瘾,尤其是与自己写的命令行客户端搭配使用时(我的版本被恰当地命名为 twixter)。
至于 Gitea,虽然我认为是 Github 的优秀替代品,但它更适合于多用户协作,而不是作为个人项目的闲置场。我决定直接自己管理 git 仓库(参阅《Pro Git》的 4.4 和 4.5 章),然后使用 stagit 生成相应的 HTML 文件。这些由 stagit 生成的页面已经替代 Gitea 作为新生的 川陀全息档案馆。
在解决了我在线存在的只写任务需求后,我将继续探索剩下的两个难题:只读(内容消费)和交互(通讯方式)类操作。目前,订阅源和电子邮件是我最好的答案,但是它们仍然不足以涵盖我所有的需求。
给提供不需登录的匿名评论点赞! 我也刚刚从折腾评论系统的苦海中解脱:我先后换用过 WordPress、Disqus、和 Isso,但是我最后决定直接用一个 mailto 表单,自己手动添加、管理评论。
由于是邮件所以还是需要一封一封地看,不过剩余的部分是自动的。具体的做法是:我用的邮件阅读器有个功能可以将邮件内容 pipe 到外界命令中,所以我写了一个脚本将评论内容提取成 TOML 格式并写入到我博客的本地 git 仓库里,最终显示则靠 Hugo 的模板功能。这样我在浏览收件箱时看到评论邮件就可以一键采纳。然而在设置好这些后还没有收到过评论
关于名字确实是这样哈哈,这是我所保留下来的为数不多的几项评论功能之一。
外太空九号博客
最近,我在想办法将我的微型博客整合到当前网站里,所以我开始重新考虑 IndieWeb 所提倡的一些构想:与希望一切都通过服务器 API 和 JSON 响应来动态完成的 ActivityPub(Mastodon、Pleroma 等用于互联的协议)不同,IndieWeb 社区推荐的不少标准都支持从有正确标记的静态 HTML 文件中直接生成机器可读的网站源。IndieWeb 隐含地依赖的一大核心要素是 URI(统一资源标志符)的稳定性,或者从更高的角度来说,站点所有者对域名的控制。由于最近关于.ORG 域名的 闹剧,我逐渐意识到,一个域名昂贵到无法维护(或可能随时被扣押)的未来可能并不是遥不可及的。这会严重破坏整个 IndieWeb 赖以建立的前提,更不用说更常见的链接失效了。幸运的是,我觉得 IPFS(星际文件系统)有潜力能够解决这两个问题。
IPFS 速成班
好的,好的,我知道和一些类似的项目,例如 Dat 协议,pingfs,甚至 Scruttlebutt,比起来,IPFS 的名称听起来非常不靠谱(相信我,我开始时也和你一样怀疑),而不少加密货币类创业公司将 IPFS 与各种首字母缩写词混杂在其营销资料中的事实更降低了它的可信度,但 IPFS 看起来的确是类似项目中最成熟且易于使用的。以下我对解释 IPFS 所做的尝试,其信息大部分来自 官方文档 和这一 讲座。如果你对进一步的实现细节感兴趣,这一 来自 IPFS Camp 2019 的专题讨论 是一个很好的起始点。
简单地说,一条网页链接只是指向某服务器上文件路径的一种花哨说法。就像一般的文件路径一样,服务器下线后,即使坐在同一房间的某人可能缓存了网页内容,该链接也无法被访问。在 IPFS 中,文件(或数据块)通过与其内容相应的加密哈希值作为地址,并以分布式的方式存储在所有用户群中。这意味着我们不需要中心化的设施来访问文件、可以简单地验证文件完整性、可以使用 P2P 共享来加快访问速度、以及以这种方式存储的文件内容是无法改变的。
无法更改文件内容相比我们所得到的好处来说似乎是一个相当昂贵的代价,但是就像计算机科学中的任何其他问题一样,这可以通过添加抽象层来解决。解决这一问题的 IPNS(星际域名系统)利用公钥加密来创建可以指向不同文件的不可变地址。IPNS 地址基本上就是某个公钥的哈希值。一次 IPNS 查找包括取回公钥本身、搜索具有相应的私钥签名的指针文件(一个包含 IPFS 地址的文件)、辨认最新的指针文件、以及重定向到正确的地址几个步骤。要利用 IPNS,用户首先要创建一个公私钥对,然后将公钥、想分享的文件和带有签名的指针文件上传到 IPFS 上。当需要更新时,用户只需要签署并上传新的指针文件就可以了。
IPFS 的不少方面都可以在过去的项目中看到踪影,例如 BitTorrent(P2P 共享)、Plan 9 下的 Fossil 和 Venti(一次写入的数据块和路径重定向)、和 git(哈希树/有向无环图)。但是,IPFS 的杀手级功能在于其与现有架构集成的便捷程度。专用的 HTTP 网关允许从浏览器(而不是 IPFS 客户端)中直接访问 IPFS 或 IPNS 地址,而且 IPFS 还具有与 FUSE(用户空间文件系统)的兼容性,这意味着我们甚至可以将整个 IPFS 挂载为一个只读分区:这一兼容性也让我们能够托管静态网站,但是我必须承认,访问全球(甚至星际)规模的 P2P 共享盘是个明显更酷的用法。
在 IPFS 上架设静态网站
官方指南 已经很好地概述了使用方法。以下是简要概括:
- 运行
ipfs init
和ipfs daemon
初始化并启动 IPFS 守护进程。 - 生成网站文件并运行
ipfs add -r <网站文件路径>
将其内容发送到 IPFS。输出的最后几行会有路径根目录的哈希值。 - 如果要使用 IPNS,请运行
ipfs name publish <网站根目录哈希>
以将 IPNS 链接定向到刚刚上传的文件夹上。IPNS 公钥的哈希值可以通过ipfs key list -l
获得。 - 在更新或重建网站文件时重复以上两个步骤。由于 IPFS 寻址过程固有的数据去重功能,该过程的实际开销并不大。对静态站点这一用例来说非常合适:越大的文件(例如照片)更新频率就越低。
完成此操作后,我们就可以从任何专用 HTTP 网关使用 <网关地址>/ipfs/<网站根目录哈希>
或 <网关地址>/ipns/<ipns-地址>
来访问刚才上传的网站了:我们可以使用由 IPFS 守护进程启动的本地网关(通常位于 127.0.0.1:8080
),也可以使用 公共网关(由于 IPFS 文件取回需要在运行网关的服务器上进行,因此使用公共网关有遭受来自服务器所有者的中间人攻击的额外风险)。如果想要架设多个网站,则可以使用 ipns key gen
来生成更多 IPNS 密钥对,并在执行 ipfs name publish
时通过 --key
选项指定发布地址。
在 IPFS支持 IPNS 密钥的导入/导出 之前(这有助于我们备份密钥并从多台设备发布内容),DNSLink 可用于更方便地访问站点,但代价是需要拥有域名并信任 DNS 服务提供者。要想通过 /ipns/<域名>
从 HTTP 网关访问站点,只需为域名加入以下 TXT 记录:
dnslink=/ipfs/<网站根目录哈希>
或
dnslink=/ipns/<ipns-地址>
例如本站就可以通过 /ipns/shimmy1996.com(该链接使用 ipfs.io 架设的公共网关)来访问。虽然算不上是一个完全没有缺点的办法,但对我来说这是个合理的妥协。我发现 IPFS 通常比 IPNS 快,所以在 DNSLink 里用 IPFS 地址应该更加合适。为了避免每次手动复制粘贴,我在博客构建脚本中添加了以下内容以自动将网站上传到 IPFS 并更新 DNS 记录(使用 DigitalOcean 的 API):
echo "上传网站至 IPFS..."
hash=$(/usr/bin/ipfs add -Qr "<网站根目录>")
echo "更新 DNSLink 记录..."
token="<digitalocean-api-令牌>"
curl -X PUT \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $token" \
-d "{\"data\":\"dnslink=/ipfs/$hash\"}" \
"https://api.digitalocean.com/v2/domains/<域名>/records/<记录-id>"
DigitalOcean 上 DNS 记录的记录 ID 也可以通过 其 API 取回,不过你可能需要在请求中增加 ?page=2
或更后面的页码才能找到你想要更新的记录。
对了,还需要注意的是,正如同使用任何脱机 HTML 文件时一样,我们需要在生成的网页中使用相对链接。在 Hugo 中,这可以通过在 config.toml
中加入
relativeURLs = true
来实现。
当然,作为一个 P2P 网络,IPFS 无法取回已经不存在于任何节点上的文件。默认情况下,IPFS 客户端会 固定 从本地计算机共享的任何内容:固定内容不会被删除,这确保 IPFS 上至少有一个可用的副本。我们可以取消固定网站的过时版本,或者,如果需要,在多台设备上查找并固定网站地址以防万一。
繁星若尘
回到 IndieWeb 的问题上:越来越黑的域名系统和链接失效使基于 HTTP 的 URI 的稳定性难以保证。但是,如果我们使用 IPFS 或 IPNS 地址作为 URI 呢?简直完美!我们通过由数学而非 FBI 警告所控制的地址获得了(理论上可以永久持续下去的)对静态网页的稳定分布式访问。消除拥有服务器的需要还降低了拥有个人网站的门槛。HTTP 协议已经存在了 29 年,而 IPFS 仅存在了 5 年。我不知道 IPFS 在接下来的 24 年中是否还会继续存在,但是如果是的话,我希望我们会看到一个或许更加混乱,但更加健壮、充满活力、多彩的在线世界。
不是有个很俗套的说法是“一个人直到被遗忘之前都不会真正死去”吗?这句话直到我第一次经历家里比较熟识的长辈去世的时候我都觉得有点矫情,但是在那之后我的看法改变了。坟墓、清明节的习俗、回忆录、甚至传记也许一开始都是我们为了能让逝者在记忆里留存久一些而做的努力吧。
用动物叫声来作为微型博文的代称似乎已经成了惯例:例如推特的推文(tweet)、Mastodon 的嘟文(toot)、还有 honk(鹅叫)。我将自己的微型博文称作 hoot(猫头鹰的叫声),本想音译成“呼文”,但是翻看维基时我想到了“鸮文”这个名称。虽然现在的读音已经不同,但是“鸮”中表声的“号”和 hoot 的发音恰好类似,简直完美!
偶然发现维基上居然有 蔬菜題材作品 这个页面