探索 Misskey 的无服务部署

发布于 / 所有文章 / 0 条评论

本文将介绍如何利用 Supabase、Cloudflare R2 和 Railway 等平台搭建一个完全 Serverless 的 Misskey 实例。

三年前,我曾写过一篇文章,介绍如何自行搭建去中心化社交平台 Misskey。

搭建属于自己的去中心化社交平台 Misskey

Misskey 是一个支持 ActivityPub 协议的去中心化社交平台。本文将介绍如何手动搭建属于自己的 Misskey 实例,并以 AWS S3 为例为其配置对象存储以及对象存储 ...
https://eri.cx/build-your-own-decentralized-social-platform-misskey/

不过,当时遇到了一些问题。例如,那时 Mastodon 不支持 WebP 格式的媒体,导致我的实例媒体在其他 Mastodon 实例上无法加载。而更大的问题其实是每个准备自己建立 Fediverse 实例的人都会遇到的问题——孤独。实例刚建立时,你和 Fediverse 的其他实例尚未联合,你的时间线只有你自己的内容。你需要通过中继才能看到其他实例的用户活动,而且,由于缺少商业平台的推荐机制,你的时间线一开始会非常普通,主题混杂且平均。只有在你建立起自己的圈子后,这一现象才会有所改变。因此,我三年前的实例最终关闭了。但几周前,我还能在草莓县(https://m.cmx.im/)看到我以前发布的内容。这正是 Fediverse 的魅力所在,一个人的存在痕迹不会因实例的消失而消失。

三年后,我计划重新启动我的 Misskey 实例。与之前不同的是,我部署服务的方式发生了很大改变。三年前,我几乎是在自己的服务器上手动构建一切:PostgreSQL + Redis + Node + Misskey + Nginx + AutoBackup。所有服务都是手动部署,除了 AWS S3 外,没有使用任何托管服务,也没有使用任何容器。三年过去了,人变懒了。现在我的服务全部是托管服务或容器化服务。这次我的 Misskey 实例将使用 Supabase 提供的 PostgreSQL 数据库,Cloudflare 提供的 R2 对象存储,而 Node + Redis + Misskey 将使用 Docker 打包并运行在 Railway 的 Serverless Container 下。

首先介绍一下 Supabase。市面上有很多 Serverless PostgreSQL 服务,而我选择它的主要原因是它是唯一一家在文档中明确记录其数据库可以使用 PGroonga 扩展的服务商。如果你经常使用 Twitter 或 Telegram 等服务,应该知道这些平台的中文搜索有多难用。Misskey 也存在同样的问题,因为在默认情况下 PostgreSQL 提供的搜索功能无法提供中文、日文等全文语义搜索,需要搭配其他方式实现。而 Misskey 2025 将加入对 PGroonga 的全文搜索支持。但据我调查,市面上各种 Serverless PostgreSQL 服务都不支持 PGroonga,目前我只找到 Supabase 支持,这也是我第一次接触 Supabase 的产品。Supabase 将自己定义为 Firebase 的开源替代品,主要提供 PaaS(Platform as a Service),并且他们的系统在其 GitHub(https://github.com/supabase/supabase)上开源。你可以随时在自己的基础设施上搭建一个你自己的 Supabase 平台。他们的产品包括带有 RLS(Row Level Security)的 PostgreSQL 数据库,在此基础上实现 Auth、Storage、Edge Function、Realtime 等服务。还有一些配套服务,例如自动提供与数据库结构相符的 REST API 来暴露数据库结构,便于开发者直接构建上层应用。免费版 Supabase 提供两个 Nano 级实例,每个实例包含 0.25 vCPU + 500MB RAM + 500MB Disk,以及试用级别的 Auth、Storage、Edge Function、Realtime 等服务。我使用的是 Pro 计划,并建立了一个 Small 级实例,底层是 AWS t4g.small 实例,使用的是 AWS 的 Graviton2 ARM 处理器。实例规格为 2 vCPU + 2GB RAM + 8GB gp3 Disk。CPU 不是独享的,而是 AWS 祖传的 Baseline + Credit 组合。不过这款处理器的性能不错,我开了一台同规模的 AWS 实例,在 Burst 状态下使用 Sysbench 跑分,单核 2800,多核 5600 的成绩相当不错。最后,Supabase 默认提供的数据库直接连接地址是 IPv6 Only 的,如果要开通 IPv4,每月需要额外支付 4 美元的附加费。最终每月支出为 Pro 计划(25 美元/月)+ Small 实例(15 美元/月)+ IPv4 附加费(4 美元/月)- Pro 计划附带的 Credit(10 美元/月)= 34 美元/月。最终我得到的是一个 2H2G 实例,其上有 Serverless PostgreSQL 数据库,8GB 容量且带有七天每日备份,100GB 的 S3 存储,一个 OAuth 平台,以及 Edge Function、Realtime 和其他 Supabase 功能,以上所有服务共享 250GB 的出站流量。如果我选择使用 AWS Lightsail Managed Databases,单节点实例每月 30 美元的配置是 1 vCPU + 2GB RAM + 80GB Disk + 100GB Transfer,所以 Supabase 的价格还是很有竞争力的。

接下来介绍一下 Cloudflare 提供的 R2 对象存储。我日常生活中经常使用的是 AWS S3。市面上大部分对象存储服务都按存储量 + API 调用 + 流量计费。因此,三年前我为 Misskey 实例配置 AWS S3 时,特意使用 Nginx 为 S3 做了反向代理,并使用 ACL 限制只有我的服务器可以访问 S3,还在 Nginx 中配置了长达一年的缓存。这一切都是为了防止我某天收到天价流量费账单。而 Cloudflare 提供的 R2 服务,不仅存储费用比 AWS 低得多,而且不计算流量费,这下再也不用担心破产了。虽然市面上也有 Wasabi 等存储提供商不计算流量费,但我还是更信任大厂。

最后介绍一下 Railway。对于开发者来说,这家服务商应该很熟悉,也是市面上比较知名的提供免费额度的 Serverless Container 服务商。他们的所有产品都围绕 Docker 构建,也支持复杂服务编排,并基于使用量按积分计费。我一直用他们家托管一些小型实验性项目,不过根据我的使用经验,它完全可以胜任托管生产程序。

接下来开始搭建我的 Misskey 实例:

我使用的 Misskey 实例是修改版,源码位于 https://github.com/Eric-2369/misskey。主要修改是将数据库设定部分改为使用环境变量设定,方便部署到 Railway 上。同时内置了 Redis,毕竟 Redis 是轻量级内存数据库,且 Misskey 不依赖 Redis 的持久化,直接放在 Misskey 镜像中影响不大,也省得我再建立 Redis 实例。我使用 GitHub Actions 构建镜像并推送到了 Docker Hub(https://hub.docker.com/r/eric2369/debian12-misskey)上。

在 Supabase 中建立一个 Project,然后使用 Supabase 提供的默认用户(postgres)以及你设定的密码登录默认数据库(postgres)。你可以使用 postgresql-client 或任何你喜欢的客户端。登录后,为 Misskey 单独创建一个数据库,再创建一个 Misskey 用户,并将该用户设置为 Misskey 数据库的 Owner:

CREATE ROLE misskey_user WITH LOGIN PASSWORD '<your_password>';

GRANT misskey_user TO postgres;

CREATE DATABASE misskey_db;

ALTER DATABASE misskey_db OWNER TO misskey_user;

REVOKE misskey_user FROM postgres;

记得将 <your_password> 替换为你的密码。

在将 Misskey 连接到数据库之前,有两点需要注意。首先,免费版 Supabase 的 Direct Connect URL 仅支持 IPv6,而 Railway 应该不支持连接 IPv6(我没有测试,但 Railway 的 IPv6 网络用于 Private Network,所以应该不支持)。因此,你可能需要将数据库地址更换为 Supabase 提供的 Supavisor Pooler 地址,并相应地更改用户名。这些在 Supabase 的文档中都有说明,我就不赘述了。其次,Supabase 数据库使用的 SSL 证书是自签名的。你需要在 Supabase 的 Database 设置页面下载 CA 证书,传给你的 Misskey 实例。Misskey 使用 typeorm 包连接数据库,你可以参考 typeorm 的设置方法修改 Misskey 的配置文件 yml。如果你使用我的镜像,将证书进行 Base64 编码后,通过 DATABASE_SSL_CA_BASE64 环境变量配置即可。我的镜像的所有环境变量示例位于 https://github.com/Eric-2369/misskey/blob/master/.env.example

接下来,在 Railway 下新建一个 Project,然后在 Project 下新建一个 Service,类型为 Dockerimage,填入我提前发布到 Docker Hub 的镜像,并配置相关环境变量,即可部署该服务。此时在 Railway 的 Deploy Log 中,你可以看到 Misskey 大概需要一分钟进行数据库迁移。在等待 Misskey 建立数据库的过程中,可以进入该 Service 的 Setting 中为服务配置域名。这一步遵从 Railway 的引导即可,注意 Misskey 实例运行在 3000 端口。

等到 Misskey 日志显示 listened on 3000 后,就可以访问你绑定的域名进行初始化设置了。此时 Misskey 搭建完成。

之后有一个可选项,即开启当前 Misskey 实例的 PGroonga 全文搜索。该功能将在 Misskey 2025 发布。截至我编写本文时,Misskey 的 Release 版本还是 2024.11,2025 版本仍处于 Beta 版本。但你可以先启用该插件并建立 Index,等到 Misskey 发布 2025 版本后,修改 yml 配置文件即可启用该功能。

同样使用 postgresql-client 连接到数据库,注意这次连接的是 misskey_db 数据库,然后执行以下命令:

CREATE EXTENSION pgroonga;

CREATE INDEX idx_note_text_with_pgroonga ON note USING pgroonga (text);

等到 Misskey 2025 发布后,将 Misskey 配置 yml 文件中的 fulltextSearch.provider 选项从默认的 sqlLike 更改为 sqlPgroonga 即可。

接下来为 Misskey 配置对象存储,这对于无服务部署 Misskey 是必须的,因为 Railway 的容器在重新部署后,里面存储的文件会消失。登录 Cloudflare 并进入 R2 界面,创建一个新的存储桶。随后在 R2 页面新建一个 API Token,记录下该 Token 的 Access Key 和 Access Secret。Cloudflare 默认为每个 Bucket 都提供一个 r2.dev 域名,你可以直接使用它,但该域名存在速率限制,所以 Cloudflare 推荐绑定自己的域名。你可以在 Bucket 的 Setting 中设置自定义域名。完成上述步骤后,进入 Misskey 的控制面板,找到对象存储一项,填入所需信息,具体内容可一参考我上一篇文章,注意 region 需要填写 us-east-1,Base URL 填写你为 Bucket 绑定的自定义域名,Endpoint 填写 Cloudflare 给你的 S3 端点,保存生效即可。此时你可以上传一个文件,看看是否出现在存储桶中,以及在 Misskey 中是否可以正常加载。

至此,你的 Misskey 实例就建立完成了,完全 Serverless。接下来你可以对实例进行一些美化,然后与其他实例联合,或者加入中继。我使用的中继是以下两个:

https://relay.nya.one/
https://mastodon-relay.moew.science/

另外,推荐为你的实例启用 Cloudflare Proxy。除了 Misskey API 外,其他所有静态资源都可以被 Cloudflare 缓存,这可以节省你的开支。要注意,开启 Cloudflare Proxy 的话,需要将 Cloudflare SSL 模式设置为 full,而不是 flex 或 full (restrict)。

转载原创文章请注明,转载自: Eric's Blog » 探索 Misskey 的无服务部署

Not Comment Found