订阅以接收新文章的通知:

欢迎光临 Wildebeest:Cloudflare 上的 Fediverse

2023/02/08

26 分钟(阅读时间)
Welcome to Wildebeest: the Fediverse on Cloudflare

最近,Fediverse 一直是一个热门话题,成千上万甚至上十万新用户在 Mastodon 等平台上创建帐户,或完全转移到“另一端”,或试用和了解这一全新的社交网络。

今天我们要介绍的是 Wildebeest。这是一个易于部署的开源服务器,与 ActivityPub 和 Mastodon 兼容,完全构建在 Cloudflare 的 Supercloud 之上。若想在 Fediverse 中运行自己的服务器,现在您可以完全通过 Cloudflare 实现。

构建在 Cloudflare 上的 Fediverse。

若想加入 Mastodon 联盟网络,现在您有两个选择:或加入现有的服务器(服务器也称社区,每个社区都有自己的基础设施和规则),或运行自己的自托管服务器。

想运行自己的服务器有以下几种原因:

  • 您想创建一个新的社区,并通过共同的主题和使用规来吸引其他用户。
  • 您不希望必须信任第三方服务器并遵守他们的策略,您希望您的服务器在您自己的域中为您的个人帐户服务。
  • 您希望完全控制自己的数据、个人信息和内容,并了解实例的运行情况。

非营利组织 Mastodon gGmbH 使用 Ruby、Node.js、PostgreSQL 和 Redis 来帮助实现服务器。不过,运行官方服务器可能存在挑战。您需要在某个地方拥有或租赁一台服务器或虚拟专用服务器 (VPS);您必须安装和配置软件,设置数据库和面向公众的 web 服务器,配置和保护您的网络免遭攻击或滥用。然后,您必须维护所有这些设备,并不断更新。您需要处理大量的脚本和技术工作才能启动和运行;非技术爱好者绝对不想这么麻烦。

Wildebeest 的宗旨:让您可以在 Cloudflare 上快速部署与 Mastodon 兼容的自有服务器,并在几分钟内连接到 Fediverse;无需担心维护、滥用或攻击问题;Cloudflare 会自动为您处理这些工作。

Wildebeest 不是一项托管服务。它是您的实例、数据和代码,以您的 Cloudflare 帐户在我们的云中运行。而且它是一项开源服务,这意味着它会不断发展,将拥有更多功能,任何人都可以扩展并改进。

目前我们支持:

  • ActivityPubWebFingerNodeInfoWebPushMastodon 兼容的 API。Wildebeest 可以连接其他 Fediverse 服务器或接收来自其他 Fediverse 服务器的连接。
  • 与最常用的 Mastodon web(例如 Pinafore)、桌面和移动客户端兼容。我们还提供一个简单的只读 web 界面来浏览时间线和用户档案。
  • 可以发布、编辑、推广或删除帖子、sorry 帖、嘟文。我们支持文本、图像,马上还将支持视频。
  • 任何人都可以关注您;您也可以关注任何人。
  • 可以搜索内容。
  • 可以在您的实例下注册一个或多个帐户。可使用电子邮件,或与 Cloudflare Access 兼容的任何 IdP(例如 GitHub 或 Google)进行身份验证。
  • 可以编辑您的档案信息、头像和标头图像。

我们的网络是如何打造的

这些实现完全以我们的产品API 为基础。构建 Wildebeest 是另一个绝佳机会,可以展示我们功能强大、用途广泛的技术栈,证明任何人都可以使用 Cloudflare 来构建涉及多个系统和复杂要求的大型应用程序。

Wildebeest 架构的鸟瞰图如下:

现在我们来了解其细节和技术。

Cloudflare 页面

本质上而言,Wildebeest 是一个使用 Pages Functions 运行代码的 Cloudflare Pages 项目。Cloudflare Pages 为构建和部署应用程序、支持您的捆绑资产提供了很好的基础,Functions 则让您能够完全访问 Workers 生态系统,您可在其中运行任何代码。

Functions 有一个基于文件的内置路由器/functions 目录结构,按 Wildebeest 的持续部署版本上传,它定义了您的应用程序路由以及哪些文件和代码负责处理每个 HTTP 端点请求。这种路由技术与 Next.js 等框架使用的技术相似。

例如,Mastodon 的 /api/v1/timelines/public API 端点由 /functions/api/v1/timelines/public.ts 使用 onRequest 方法处理。

export onRequest = async ({ request, env }) => {
	const { searchParams } = new URL(request.url)
	const domain = new URL(request.url).hostname
...
	return handleRequest(domain, env.DATABASE, {})
}

export async function handleRequest(
    …
): Promise<Response> {
    …
}

端点单元测试也变得更加简单,只需从测试框架中调用 handleRequest() 函数即可。请参阅我们的一个 Jest 测试——mastodon.spec.ts

import * as v1_instance from 'wildebeest/functions/api/v1/instance'

describe('Mastodon APIs', () => {
	describe('instance', () => {
		test('return the instance infos v1', async () => {
			const res = await v1_instance.handleRequest(domain, env)
			assert.equal(res.status, 200)
			assertCORS(res)

			const data = await res.json<Data>()
			assert.equal(data.rules.length, 0)
			assert(data.version.includes('Wildebeest'))
		})
       })
})

与其他普通 Worker 一样,Functions 也允许设置绑定,以便与其他 Cloudflare 产品和功能交互,例如 KVR2D1Durable Objects,等等。可交互的产品和功能还在不断增加。

我们使用 Functions 来实现官方 Mastodon API 规范的大部分内容,使 Wildebeest 与其他服务器和客户端应用程序的现有生态系统兼容,同时在同一项目代码库中运行我们自己的只读 web 前端。

Wildebeest 的 web 前端使用 Qwik。Qwik 是一个旨在加快速度的多用途 web 框架,使用 JSX JavaScript 语法扩展等现代概念,支持服务器端渲染 (SSR) 和静态网站生成 (SSG)。

Qwik 提供一个开箱即用的 Cloudflare Pages Adaptor,所以我们可以直接使用(查看我们的框架指南,进一步了解如何在 Cloudflare 页面上部署 Qwik 网站)。样式设计方面,我们使用 Qwik 原生支持的 Tailwind CSS 框架。

可通过 /frontend 目录查找我们的前端网站代码和静态资产。应用程序由 /functions/[[path]].js 动态路由处理,它基本上能捕捉所有非 API 请求,然后调用 Qwik 自己的内部路由器 Qwik City,由其负责后面的所有工作。

Pages 和 Functions 路由功能强大,用途广泛,使得在同一项目下同时运行后端 API 和服务器端渲染的动态客户端(实际上是一个全栈应用程序)成为可能。

现在我们来深入了解服务器如何与我们架构中的其他组件交互。

D1

Wildebeest 使用 D1。D1 是 Cloudflare 为 Workers 平台构建的第一个 SQL 数据库,以 SQLite 为基础,现在向所有人开放 α 测试,用于存储和查询数据。我们的模式如下:

随着功能不断增多,未来模式可能会发生改变。但没关系,D1 支持迁移,当您需要更新数据库模式时,不会丢失数据。使用每个新版 Wildebeest 时,如果需要改变数据库模式,我们可以创建一个新的迁移文件。

-- Migration number: 0001 	 2023-01-16T13:09:04.033Z

CREATE UNIQUE INDEX unique_actor_following ON actor_following (actor_id, target_actor_id);

D1 支持构建强大的客户端 API,帮助开发者操作和查询 Worker 脚本的数据。在我们的例子中就是 Pages Functions。

下面举一个简化的例子,说明当您在 Fediverse 上开始关注某人时,我们如何与 D1 交互。

export async function addFollowing(db, actor, target, targetAcct): Promise<UUID> {
	const query = `INSERT OR IGNORE INTO actor_following (id, actor_id, target_actor_id, state, target_actor_acct) VALUES (?, ?, ?, ?, ?)`
	const out = await db
		.prepare(query)
		.bind(id, actor.id.toString(), target.id.toString(), STATE_PENDING, targetAcct)
		.run()
	return id
}

Cloudflare 的文化倡导内部测试,在自己的产品基础上构建,这意味着我们有时会比用户先发现产品的不足。使用 D1 确实给我们带来了一些挑战,D1 以 SQLite 为基础,用于存储我们的数据。下面来看两个例子。

ActivityPub 使用 UUID 来识别对象,并在 URI 中广泛引用。这些对象需要存储在数据库中。PostgreSQL 等其他数据库则提供内置函数来产生唯一标识符。SQLite 和 D1 目前没有这个功能,但已列入我们的计划。

别担心,Workers 运行时支持 Web Crypto,所以我们使用 crypto.randomUUID() 来获取唯一标识符。请参阅 /backend/src/activitypub/actors/inbox.ts

export async function addObjectInInbox(db, actor, obj) {
	const id = crypto.randomUUID()
	const out = await db
		.prepare('INSERT INTO inbox_objects(id, actor_id, object_id) VALUES(?, ?, ?)')
		.bind(id, actor.id.toString(), obj.id.toString())
		.run()
}

问题就解决了。

另一个例子是,我们需要存储具有亚秒级分辨率的日期。同样,PostgreSQL 等数据库也有该功能。

psql> select now();
2023-02-01 11:45:17.425563+00

但 SQLite 的不足之处在于:

sqlite> select datetime();
2023-02-01 11:44:02

我们通过一个小型 hack 程序,使用 strftime() 解决了这个问题:

sqlite> select strftime('%Y-%m-%d %H:%M:%f', 'NOW');
2023-02-01 11:49:35.624

请参阅我们的初始 SQL 模式,查找 cdate 默认值。

Images

Mastodon 的内容有大量富媒体。我们不需要重造轮子,重建图像管道;Cloudflare Images 提供 API,从我们的全球 CDN 上传、转换和提供优化的图像,完全符合 Wildebeest 的要求。

发布内容图像、档案头像或标头等,都是使用图像 API。请参阅 /backend/src/media/image.ts,了解我们如何与 Images 配合使用。

async function upload(file: File, config: Config): Promise<UploadResult> {
	const formData = new FormData()
	const url = `https://api.cloudflare.com/client/v4/accounts/${config.accountId}/images/v1`

	formData.set('file', file)

	const res = await fetch(url, {
		method: 'POST',
		body: formData,
		headers: {
			authorization: 'Bearer ' + config.apiToken,
		},
	})

      const data = await res.json()
	return data.result
}

如有兴趣在下一个项目中考虑使用 Images,请参阅此教程:如何在您的网站上集成 Cloudflare Images

也可从仪表板访问 Cloudflare Images。可以用它来快速浏览或管理您的目录。

队列

ActivityPub 协议是为聊天设计的。根据社交图谱的大小,可能会有很多来回传递的 HTTP 流量。我们不能在每次有人发帖时,都让客户端等待数百条 Fediverse 消息的传送,造成拥堵。

我们需要寻找一种方法,既支持异步工作,又启动后台作业,将数据处理从主应用程序中分离出来,以保持客户端的敏捷性。官方的 Mastodon 服务器有一个类似策略,使用 Sidekiq 负责后台处理。

幸运的是,我们也不需要担心这些复杂的问题。Cloudflare Queues 让开发人员能够安心无虞地发送和接收消息,为 Workers 请求分担一些工作,从而有效提供异步批量作业的能力。

简而言之,您有一个队列主题标识符——本质上是一个自动扩展的缓冲列表;然后您有一个或多个生产者生产结构化的消息(在我们的例子中就是 JSON 对象),并把它们放入队列(模式由您定义);最后您有一个或多个消费者订阅该队列,接收消息并按自己的速度处理消息。

请参阅 Queues 工作原理页面,了解更多信息。

在我们的案例中,每当任何传入的 API 调用需要时间长、成本高的操作时,主应用程序就会产生队列作业。例如,有人发布帖子、sorry 帖或嘟文时,我们需要将其传送到粉丝的收件箱,可能会引发许多对远程服务器的请求。这时,我们为此排列作业,将 API 释放出来确保继续响应:

export async function deliverFollowers(
	db: D1Database,
	from: Actor,
	activity: Activity,
	queue: Queue
) {
	const followers = await getFollowers(db, from)

	const messages = followers.map((id) => {
		const body = {
			activity: JSON.parse(JSON.stringify(activity)),
			actorId: from.id.toString(),
			toActorId: id,
		}
		return { body }
	})

	await queue.sendBatch(messages)
}

同样,远程服务器向我们的实例收件箱传送消息时,我们也不希望停止主 API。Wildebeest 在收件箱接收消息时,创建异步作业的方法如下:

export async function handleRequest(
	domain: string,
	db: D1Database,
	id: string,
	activity: Activity,
	queue: Queue,
): Promise<Response> {
	const handle = parseHandle(id)

	const actorId = actorURL(domain, handle.localPart)
const actor = await actors.getPersonById(db, actorId)

      // creates job
	await queue.send({
		type: MessageType.Inbox,
		actorId: actor.id.toString(),
		activity,
	})

	// frees the API
	return new Response('', { status: 200 })
}

最后一环是我们的队列消费者,它们在一个独立的 Worker 中运行,独立于 Pages 项目。消费者监听新的消息,并按自己的节奏依次处理,将其他人从拥堵中解救出来。繁忙时,队列会增加缓冲区。尽管如此,一切仍在运行,作业最终会全部分派,将主要的 API 释放出来处理关键的事情:尽可能快速响应远程服务器和客户端。

export default {
	async queue(batch, env, ctx) {
		for (const message of batch.messages) {
			…

			switch (message.body.type) {
				case MessageType.Inbox: {
					await handleInboxMessage(...)
					break
				}
				case MessageType.Deliver: {
					await handleDeliverMessage(...)
					break
				}
			}
		}
	},
}

如果您想亲自体验 Queues,可以试试这个简单的例子:使用 Queues 在 R2 中存储数据

缓存和 Durable Objects

缓存重复性操作也可以提高需要数据处理的复杂应用程序的性能。著名的 Netscape 开发者 Phil Karlton 曾说:“计算机科学只有两件难事:缓存失效和命名。”

Cloudflare 显然非常了解缓存,毕竟缓存是我们全球 CDN 的一个核心功能。我们还向客户提供 Workers KV——一个低延迟的全球键值数据存储,任何人都可以用它在我们的数据中心缓存数据对象,构建快速的网站和应用程序。

但 KV 实现了最终一致的性能。虽然这对许多应用程序和用例来说还不错,但对其他应用程序和用例来说却不太理想。

ActivityPub 协议高度事务性,无法实现最终一致性。例如:生成完整的时间线成本高昂,所以我们会缓存该操作。然而,发布帖子时,我们需要在缓存失效后再回复客户端。否则,新的帖子就不会出现在时间线上,客户端可能会因为没有看到它而出错,导致发帖失败。这其实就是我们最流行的客户端上发生过的情况。

我们需要更加聪明。团队讨论了几个选项。幸运的是,我们的 API 目录有很多选择。例如 Durable Objects

Durable Objects 是提供事务性存储 API 的单实例 Workers。需要中央协调性、强一致性和状态持久性时,Durable Objects 便是理想之选。处理多个 WebSocket 连接的状态、协调和路由聊天室消息,甚至运行多人游戏(例如 Doom)等用例中均可使用 Durable Objects。

现在您已经有所了解。是的,我们在 Durable Objects 的基础上,为 Wildebeest 实现了键值缓存子系统。通过利用 DO 的原生事务性存储 API,我们可以有力地保证,当我们创建或更改一个键后,下次读取时将总是会返回最新的版本。

这个想法非常简单有效,我们只用了几行代码,就使用两种原语(HTTP PUT 和 GET)实现了键值缓存。

export class WildebeestCache {
	async fetch(request: Request) {
		if (request.method === 'GET') {
			const { pathname } = new URL(request.url)
			const key = pathname.slice(1)
			const value = await this.storage.get(key)
			return new Response(JSON.stringify(value))
		}

		if (request.method === 'PUT') {
			const { key, value } = await request.json()
			await this.storage.put(key, value)
			return new Response('', { status: 201 })
		}
	}
}

强一致性就是这样。现在我们来看看用户注册和身份验证。

Zero Trust Access

官方的 Mastodon 服务器处理用户注册(通常使用电子邮件注册)之后,您才能选择您的本地用户名,开始使用该服务。如果我们从头开始构建,处理用户注册和身份验证可能非常耗时,令人生畏。

此外,人们不希望为想要使用的每一项新服务创建新的凭证,而是希望有更方便的授权和身份验证方法,就像 OAuth 那样,可以使用他们现有的 Apple、Google 或 GitHub 帐户。

我们希望利用 Cloudflare 的内置功能进行简化。显然,我们有一款产品可以为 Cloudflare 保护的任何应用程序处理用户引导、身份验证和访问策略;它就是 Zero Trust。因此,我们把 Wildebeest 部署在它后面。

Zero Trust Access 可以使用电子邮件进行一次性 PIN (OTP) 身份验证,或使用多种标识提供程序(例如 Google、Facebook、GitHub、LinkedIn)进行单点登录 (SSO),包括任何支持 SAML 2.0 的常规标识提供程序

开始在客户端上使用 Wildebeest 时,根本不需要注册。您可以直接登录,然后将重定向到 Access 页面,并根据您自己(您的实例的所有者)配置的策略来处理身份验证。

该策略定义了谁可以通过身份验证,以及如何验证。

通过身份验证后,Access 将把您重定向到 Wildebeest。第一次这样登录时,如果我们没有该用户的信息,我们会检测出来,并要求提供用户名和显示名称。这些问题只会问一次,并直接用于创建您的公开 Mastodon 档案。

在技术上,Wildebeest 实现了 OAuth 2 规范。Zero Trust 保护 /oauth/authorize 端点,并在用户通过身份验证后,在请求标头中出具一个有效的 JWT 令牌。然后 Wildebeest 读取并验证 JWT,并在 URL 重定向中返回一个授权码。

客户端获得授权码后,就可以使用 /oauth/token 端点来获取 API 访问令牌。随后的 API 调用会在授权标头中注入一个持有者令牌。

Authorization: Bearer access_token

部署和持续集成

我们不想为 Mastodon 运行托管服务,因为这会在一定程度上削弱联盟和数据所有权的概念。此外,我们必须承认 ActivityPub 和 Mastodon 是快速发展的新兴技术,将以难以预测的方式迅速演进。

因此,我们认为,现在帮助构建生态系统的最好方式是提供一个开源软件包,任何人都可以在我们的云上使用、定制、改进和部署。Cloudflare 显然会继续改进 Wildebeest,并支持社区,但我们希望 Fediverse 维护者可以完全控制和拥有其实例和数据。

但问题是,当 Wildebeest 需要配置这么多 Cloudflare 功能时,我们如何分发 Wildebeest 软件包并轻松部署到某人的帐户中,以及如何支持长期更新软件?

最终解决方案是将 GitHub 与 GitHub ActionsDeploy with WorkersTerraform 巧妙搭配。

用 Deploy with Workers 按钮是一个特制链接,可以自动生成工作流程页面,询问用户一些问题,Cloudflare 负责授权 GitHub 部署到 Workers,自动分叉 Wildebeest 存储库并克隆到用户的帐户中,然后使用 GitHub Actions 工作流程来配置和部署该项目。

GitHub Actions 工作流程 是一个 YAML 文件,其中说明了每一步操作。Wildebeest 工作流程(简化版)如下:

name: Deploy
on:
  push:
    branches:
      - main
  repository_dispatch:
jobs:
  deploy:
    runs-on: ubuntu-latest
    timeout-minutes: 60
    steps:
      - name: Ensure CF_DEPLOY_DOMAIN and CF_ZONE_ID are defined
        ...
      - name: Create D1 database
        uses: cloudflare/[email protected]
        with:
          command: d1 create wildebeest-${{ env.OWNER_LOWER }}
        ...
      - name: retrieve Zero Trust organization
        ...
      - name: retrieve Terraform state KV namespace
        ...
      - name: download VAPID keys
        ...
      - name: Publish DO
      - name: Configure
        run: terraform plan && terraform apply -auto-approve
      - name: Create Queue
        ...
      - name: Publish consumer
        ...
      - name: Publish
        uses: cloudflare/[email protected]
        with:
          command: pages publish --project-name=wildebeest-${{ env.OWNER_LOWER }} .

更新 Wildebeest

每当主分支发生变更,都会自动运行该工作流程,因此,更新 Wildebeest 就像将上游官方存储库与分叉同步一样简单。您甚至不需要使用 git 命令;GitHub 在用户界面中提供了同步按钮,点击该按钮即可,非常简单方便。

还有呢?更新是增量式的,不涉及销毁。将 GitHub Actions 工作流程重新部署 Wildebeest 时,我们只对您的配置做必要的修改,没有任何其他操作。您绝不会丢失数据;我们也不需要删除您现有的配置。我们的操作方法如下:

我们使用 Terraform,这是一种声明式配置语言和工具,可与我们的 API 交互,并可查询和配置您的 Cloudflare 功能。关键在于,每当我们应用一个新的配置时,我们会在一个 Cloudflare KV 键中为 Wildebeest 保留一份 Terraform 状态的副本。当触发新的部署时,我们可从 KV 副本中获取该状态,计算差值,只进行必要的修改。

也不会有数据丢失问题。如前文所述,D1 支持迁移。如果我们需要给表格增加一个新的列或需要新增一个表格,我们不需要销毁、重建数据库,我们只需要将必要的 SQL 应用于这一变更。

防护、优化和可观察性,轻而易举

一旦启动并运行 Wildebeest,您必须保护它免受不良流量和恶意行为者的影响。Cloudflare 在开箱后只需点击几下即可为您提供 DDoSWAF机器人管理保护。

同样,您将通过我们的产品获得即时的网络和内容交付优化,以及有关您的 Wildebeest 实例的性能和使用情况分析

ActivityPub、WebFinger、NodeInfo 和 Mastodon API

尽管是 Mastodon 普及了 Fediverse 的概念,但其使用的底层技术许多早已有之。这是一个珍贵的时刻,所有技术最终“齐聚一堂”,共同创建一个工作平台,回答互联网用户的实际用例问题。我们来快速浏览一下 Wildebeest 必须实现的协议:

ActivityPub

ActivityPub 是一个去中心化的社交网络协议,至少从 2018 年起就以 W3C 建议书的形式出现了。它定义了用于创建和操作内容的客户端 API,以及用于内容交换和通知的服务器到服务器 API,也称为联盟。ActivityPub 的词汇表使用 ActivityStreams,这是一个更老的 W3C 协议。

许多操作和活动的概念都是在 ActivityPub 规范中定义的。例如:Actors(档案)、消息或 Objects(嘟文)、收件箱(您通过收件箱接收关注对象的嘟文)和发件箱(您通过发件箱向关注对象发送嘟文)。

我们实现了 ActivityPub 的文件夹如下:

import type { APObject } from 'wildebeest/backend/src/activitypub/objects'
import type { Actor } from 'wildebeest/backend/src/activitypub/actors'

export async function addObjectInInbox(db, actor, obj) {
	const id = crypto.randomUUID()
	const out = await db
		.prepare('INSERT INTO inbox_objects(id, actor_id, object_id) VALUES(?, ?, ?)')
		.bind(id, actor.id.toString(), obj.id.toString())
		.run()
}

WebFinger

WebFinger 是一个简单的 HTTP 协议,用于发现任何实体(例如配置文件、服务器或特定功能)的相关信息。它将 URI 解析为资源对象。

Mastodon 使用 WebFinger 查询来发现远程用户的信息。例如,假设您想与 @[email protected] 互动,您的本地服务器会请求 https://example.com/.well-known/webfinger?resource=acct:[email protected](使用 acct 方案)并得到类似这样的结果:

{
    "subject": "acct:[email protected]",
    "aliases": [
        "https://example.com/ap/users/user"
    ],
    "links": [
        {
            "rel": "self",
            "type": "application/activity+json",
            "href": "https://example.com/ap/users/user"
        }
    ]
}

现在我们已经知道如何使用 https://example.com/ap/users/user endpoint 端点与 @[email protected] 互动。

我们的 WebFinger 响应如下:

export async function handleRequest(request, db): Promise<Response> {
	…
	const jsonLink = /* … link to actor */

	const res: WebFingerResponse = {
		subject: `acct:...`,
		aliases: [jsonLink],
		links: [
			{
				rel: 'self',
				type: 'application/activity+json',
				href: jsonLink,
			},
		],
	}
	return new Response(JSON.stringify(res), { headers })
}

Mastodon API

最后,设置服务器信息、档案信息、生成时间线、通知和搜索等,都是 Mastodon 特定的 API。Mastodon 开源项目定义了一个 REST API 目录,您可以在他们的网站上查找所有文档。

可以在此处(REST 端点)和此处(后端原语)查看我们的 Mastodon API 实现。下面举一个由 Wildebeest 实现的 Mastodon 服务器信息 /api/v2/instance 示例。

export async function handleRequest(domain, db, env) {

	const res: InstanceConfigV2 = {
		domain,
		title: env.INSTANCE_TITLE,
		version: getVersion(),
		source_url: 'https://github.com/cloudflare/wildebeest',
		description: env.INSTANCE_DESCR,
		thumbnail: {
			url: DEFAULT_THUMBNAIL,
		},
		languages: ['en'],
		registrations: {
			enabled: false,
		},
		contact: {
			email: env.ADMIN_EMAIL,
		},
		rules: [],
	}

	return new Response(JSON.stringify(res), { headers })
}

Wildebeest 还为客户端通知实现了 WebPush,为服务器令牌实现了 NodeInfo

其他与 Mastodon 兼容的服务器必须实现所有这些协议;Wildebeest 便是其中之一。社区非常积极地讨论未来的增强功能;我们将不断提高我们的兼容性,并增加对更多功能的支持,确保 Wildebeest 在 Fediverse 服务器和客户端生态系统的形成过程中发挥积极作用。

立即开始使用

技术方面我们已经讨论了很多,下面我们来了解 Fediverse。我们尽可能详细说明部署服务器的所有步骤。要开始使用 Wildebeest,请前往公共 GitHub 存储库,并查阅我们的入门教程

Wildebeest 的大多数依赖项提供优惠的免费计划,允许您为个人或业余项目(与关键业务无关)试用它们,但您需要订阅一个 Images 计划(最低级的计划应该足以满足大多数需求),并视服务器负载情况订阅 Workers Unbound(同样,最便宜的计划应该足以满足大多数用例)。

我们倡导内部测试,因此,Cloudflare 今天也正式加入了 Fediverse。您可以开始关注我们的 Mastodon 帐户,并使用您最喜爱的 Mastodon 应用程序获取 Cloudflare 的定期更新,与通过其他社交平台获取更新的体验毫无二致。这些帐户完全在 Wildebeest 的服务器上运行。

Wildebeest 与大多数客户端应用程序兼容;我们已确认可与官方的 Mastodon AndroidiOS 应用程序、PinaforeMastodontooot 兼容,并还在研究与 Ivory 等其他应用程序的兼容性。如果您最喜爱的应用程序不能兼容,请在此提交问题,我们将尽力提供支持。

结语

Wildebeest 完全构建在我们的 Supercloud 栈上。这是我们创建的最完整、最复杂的项目之一,使用了 Cloudflare 的各种产品和功能。

希望这篇报道能激励您不仅尝试部署 Wildebeest,加入 Fediverse,并在 Cloudflare 上构建您的下一个应用程序,无论应用程序要求有多高。

Wildebeest 目前还只是一个非常简单可行、与 Mastodon 兼容的服务器,但我们会不断改进,推出更多功能,支持更多应用程序;毕竟,我们的官方帐户也在使用它。Wildebeest 是一种开源服务器,非常欢迎您通过拉动请求或反馈献计献策。

同时,我们在我们的 Developers Discord Server 上开设了Wildebeest 室,并始终关注 GitHub 存储库问题选项卡。欢迎与我们交流,我们渴望了解您是如何使用 Wildebeest 的,也乐意回答您的问题。

PS:为方便阅读并节省空间,本博客中的代码片段经过了简化(例如,删除了 TypeScript 类型和错误处理代码)。请参阅 GitHub 存储库的链接,查看完整版本。

我们保护整个企业网络,帮助客户高效构建互联网规模的应用程序,加速任何网站或互联网应用程序抵御 DDoS 攻击,防止黑客入侵,并能协助您实现 Zero Trust 的过程

从任何设备访问 1.1.1.1,以开始使用我们的免费应用程序,帮助您更快、更安全地访问互联网。要进一步了解我们帮助构建更美好互联网的使命,请从这里开始。如果您正在寻找新的职业方向,请查看我们的空缺职位
Cloudflare Pages (CN)D1 (CN)Cloudflare Workers (CN)Cloudflare Zero Trust (CN)简体中文

在 X 上关注

Celso Martinho|@celso
Sven Sauleau|@svensauleau
Cloudflare|@cloudflare

相关帖子

2022年11月17日 14:00

我们的构建过程:Cloudflare Radar 2.0 背后的技术

在上个月的 Cloudflare Birthday Week 期间,Radar 2.0 已作为完整的产品改进发布。这篇博客文章介绍了其技术上的构建过程。希望这篇文章能激励开发人员使用 Cloudflare 产品构建复杂的 Web 应用程序...

2021年12月19日 13:59

在 Cloudflare 上构建您的下一个视频应用程序

过去,构建视频应用程序十分困难。在录制、编码和播放视频背后有许多复杂的技术。幸运的是,Cloudflare Stream 分担走了所有困难的部分,现在您可以轻松构建自定义视频和流媒体应用程序。让我们看一下,我们可以如何结合 Cloudflare Stream、Access、Pages 和 Workers,使用极少的代码创建一个高性能的视频应用程序。...