> For the complete documentation index, see [llms.txt](https://docs.decentraland.org/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.decentraland.org/contributor/contributor-zh/jiao-cheng/how-to-run-a-catalyst.md).

# 如何运行 Catalyst 节点

有没有曾经好奇过 Decentraland Catalyst 节点是如何工作的？有没有想过自己运行一个节点，却不知道从哪里开始而感到不知所措？你是否正在为 Decentraland 构建内容，并发现要在生产服务器上完成完整的开发和测试流程很困难？

如果你有这种经历，别再担心了。本教程将帮助你完成规划过程，弄清楚需要做哪些决定，然后一步一步指导你启动服务器。另外，如果某些事情没有按计划进行，文末还有一个故障排查部分，列出了一些最常见的问题以及如何修复它们。

准备好了吗？动手开始吧。

### 硬件要求

Decentraland 基金会的服务器部署在 Amazon AWS 上， `t2.xlarge` 实例上。因此，虽然这些服务器是面向公开使用的，但你自己的服务器可能只需要更小的配置，具体取决于预期用途。

一个 AWS EC2 `t2.xlarge` 具有以下硬件：

* 4 个 vCPU。
* 16 GB 内存

至于文件存储 + 数据库存储，一个容量为 2 TB 的 SSD / HDD 应该绰绰有余。截至本文撰写时，基金会服务器的全部存储总共只用了略多于 1 TB。

### 软件前置条件

运行 catalyst-owner 需要以下内容：

* Linux / MacOS 操作系统
* Docker / docker-compose
* Git
* LiveKit 集群

### 在开始之前需要考虑的一些选项

* 你希望你的节点在互联网上公开可访问吗？如果是，你需要一个可被互联网访问的实例，以及一个可连接到它的公共 URL。
* 这个节点会用于场景、可穿戴设备等内容的开发吗？在这种情况下，硬件配置可以小得多，因为访问它的可能只有一两个人，而不是成百上千的用户。
* 你想同步所有实体类型吗？如果你打算用它来开发场景，也许你不需要同步所有内容类型，尤其是 profiles，因为它们会消耗大量时间、带宽，最重要的是磁盘空间，而且对你的目标也不会有帮助。

### LiveKit

Catalyst 的 Comms 服务需要一个外部 LiveKit 集群来编排玩家之间的通信。对此有两个选择：使用 LiveKit Cloud 账户，或者运行你自己的 LiveKit 集群。

建议设置 [LiveKit Cloud 账户](https://cloud.livekit.io/) 它提供免费套餐，可管理 100 名用户，或者根据流量付费。这个方案更简单，因为它不需要额外准备基础设施，而且服务本身可以管理扩缩容。否则就需要部署一个 LiveKit 集群。LiveKit 在文档方面做得非常好：

* [部署](https://docs.livekit.io/oss/deployment/)
* [分布式部署](https://docs.livekit.io/oss/deployment/distributed/)

*如果你想深入了解支撑基于 LiveKit 传输的通信所需的技术细节，请查看* [*ADR-70 新通信架构*](https://adr.decentraland.org/adr/ADR-70)*.*

### 分步指南

首先要做的是克隆 [catalyst-owner](https://github.com/decentraland/catalyst-owner) GitHub 仓库

```bash
> git clone https://github.com/decentraland/catalyst-owner.git
正在克隆到 'catalyst-owner'...
remote: 正在枚举对象：2392，完成。
remote: 正在计数对象：100% (602/602)，完成。
remote: 正在压缩对象：100% (168/168)，完成。
remote: 总计 2392（增量 506），重用 481（增量 430），包重用 1790
正在接收对象：100% (2392/2392)，926.05 KiB | 1.09 MiB/s，完成。
正在解析增量：100% (1257/1257)，完成。
> cd catalyst-owner
```

完成后，就该为节点配置环境变量，并根据需要进行一些更改。

```bash
# 在 /catalyst-owner 文件夹中
> cp .env.example .env
> cp .env-advanced.example .env-advanced
```

现在使用你最喜欢的文本编辑器，在这些文件中做任何需要的修改。比如，设置 `EMAIL` 环境变量并填写有效邮箱是必需的，这样你才能收到 Certbot 证书到期的更新提醒。

另外，为 `CATALYST_URL` 设置你自己的值也可能是必需的，尤其是当你的服务器要公开暴露在互联网上时。在本地机器上使用时，默认值 `http://localhost` 就可以。

**Comms 服务**

一旦 LiveKit 集群可用，你就需要设置 Comms 服务所需的特定 LiveKit 变量，例如：

```
LIVEKIT_HOST=wss://livekit-1.mydomain.org
LIVEKIT_API_KEY=API-JjHuvM
LIVEKIT_API_SECRET=J7YSHmNzkNCEfT2
ROOM_PREFIX=my-prefix
```

该 `ROOM_PREFIX` 变量是可选的，可配置为标识 Catalyst 创建的 LiveKit 房间。如果有多个 Catalyst 使用同一个 LiveKit 集群，这会很有用。

**内容服务器**

有一个名为 `CONTENT_SERVER_STORAGE` 的变量，它定义了内容服务器用于存储的本地文件夹。默认值为 `CONTENT_SERVER_STORAGE=./storage`。你可以修改这个值，将文件存储到其他位置，或者至少确保引用的文件夹存在。你可能需要像这样创建它：

```bash
# 在 /catalyst-owner 文件夹中，或者在 CONTENT_SERVER_STORAGE 指向的任何位置
> mkdir storage
```

还有另一个很有意思的变量 `SYNC_IGNORED_ENTITY_TYPES` 它允许在同步过程中忽略某些实体类型。如果你打算把 Catalyst 服务器用于开发，也许你不需要同步所有内容类型。你可以设置环境变量 `SYNC_IGNORED_ENTITY_TYPES="profile,store"` 这样就只会从 DAO 服务器拉取场景和可穿戴设备。这将为你的服务器节省大量时间、带宽和磁盘存储。

> 💡 如需更完整的受支持环境变量列表，请查看下面的 [环境变量](#environment-variables) 部分。

#### 启动 Catalyst 节点

一旦所有环境变量都设置好，就可以启动节点了。最简单的方法就是在根目录运行 `init.sh` 脚本。

```bash
# 在 /catalyst-owner 文件夹中

> ./init.sh
## 正在加载环境变量... [ OK ]
[ OK ]
## 正在检查是否配置了邮箱... [ OK ]
## 正在检查是否配置了存储... [ OK ]
## 正在检查是否配置了 catalyst url... [ OK ]
 警告：你运行的不是 Catalyst 内容节点和 Catalyst Lambda 节点的最新镜像。
 警告：你运行的不是 Catalyst Archipelago 节点的最新镜像。
 警告：你运行的不是 Catalyst Explorer BFF 节点的最新镜像。
 - DOCKER_TAG:               45a5154f11b53d55aadfdf7f958e2fce6a964824
 - LIGHTHOUSE_DOCKER_TAG:    latest
 - CATALYST_URL:             http://localhost
 - CONTENT_SERVER_STORAGE:   ./storage
 - EMAIL:                    a@a.com
 - ETH_NETWORK:              mainnet
 - REGENERATE:               0

5 秒后启动...
45a5154f11b53d55aadfdf7f958e2fce6a964824：正在从 decentraland/catalyst-content 拉取
摘要：sha256:d6c2981c57cb9367fdb3228d15b07e4d26e62c902944115937de24ecd3ab6aac
状态：镜像已是最新，适用于 decentraland/catalyst-content:45a5154f11b53d55aadfdf7f958e2fce6a964824
docker.io/decentraland/catalyst-content:45a5154f11b53d55aadfdf7f958e2fce6a964824
45a5154f11b53d55aadfdf7f958e2fce6a964824：正在从 decentraland/catalyst-lambdas 拉取
摘要：sha256:5605812dd29316afc32e561d2a2ce1311f164f07ef3cd99a1cd60727518636e5
状态：镜像已是最新，适用于 decentraland/catalyst-lambdas:45a5154f11b53d55aadfdf7f958e2fce6a964824
docker.io/decentraland/catalyst-lambdas:45a5154f11b53d55aadfdf7f958e2fce6a964824
latest：正在从 decentraland/catalyst-lighthouse 拉取
摘要：sha256:fedc10b714823909f0a1c17955eed2f22a02e4f784090848d3253ef734e410d4
状态：镜像已是最新，适用于 decentraland/catalyst-lighthouse:latest
docker.io/decentraland/catalyst-lighthouse:latest
latest：正在从 decentraland/archipelago-service 拉取
摘要：sha256:e2c1d6fa96a5cfbbf6fb37e3840c0724fb5abeef8c366025a28fab3ad33d6480
状态：镜像已是最新，适用于 quay.io/decentraland/archipelago-service:latest
quay.io/decentraland/archipelago-service:latest
latest：正在从 decentraland/explorer-bff 拉取
摘要：sha256:fa9e305c44972a8613b01f4cd573d6fb84b0fb03ce953a506fbb06053202913c
状态：镜像已是最新，适用于 quay.io/decentraland/explorer-bff:latest
quay.io/decentraland/explorer-bff:latest
停止 nginx ... 完成
## 使用 HTTP，因为 CATALYST_URL 设置为 http://localhost
## 正在替换 nginx 服务器文件中的 $katalyst_host 值... [ OK ]
## 正在重启容器...
使用默认驱动程序创建网络 "catalyst-owner_default"
正在创建 catalyst-owner_comms-server_1 ... 完成
正在创建 node-exporter                   ... 完成
正在创建 catalyst-owner_lambdas_1      ... 完成
正在创建 postgres                      ... 完成
正在创建 catalyst-owner_certbot_1        ... 完成
正在创建 nats                            ... 完成
正在创建 postgres-exporter               ... 完成
正在创建 catalyst-owner_content-server_1 ... 完成
正在创建 catalyst-owner_archipelago_1    ... 完成
正在创建 catalyst-owner_explorer-bff_1   ... 完成
正在创建 nats-exporter                   ... 完成
正在创建 cadvisor                        ... 完成
正在创建 nginx                           ... 完成
## Catalyst 服务器已在 http://localhost 上启动并运行
```

如果一切顺利，我们现在已经有了一个完整运行的 Decentraland 节点。你现在可以打开浏览器并输入该 URL。如果使用默认值，它应该是 [`http://localhost`](http://localhost/).

我们可以使用这个 docker 命令查看内容服务器日志：

```bash
> docker logs catalyst-owner_content-server_1
```

虽然服务器现在已经在运行，但它还没有 100% 准备好投入使用。它需要从其他 [DAO 服务器](https://decentraland.github.io/catalyst-monitor) 同步内容，这样它才能为连接到它的用户提供相同的体验。同步可能需要很长时间。在网络状况良好的情况下，6 小时通常都算很常见。所以……是时候喝杯咖啡、小睡一下、好好睡一觉，然后明天再回来看看了。

判断同步是否完成的一种方法，是检查内容状态端点的结果： <http://localhost/content/status> （请在这里使用你的 URL）。

```json
{
  "synchronizationStatus": {
    "lastSyncWithDAO": 1658153514917,
    "synchronizationState": "Bootstrapping"
  },
  "snapshot": {
    "entities": {
      "profile": 1271331,
      "scene": 23477,
      "wearable": 17351,
      "store": 890
    },
    "lastUpdatedTime": 1658153414530
  },
  "version": "v3",
  "commitHash": "9a2e0d5d05d02646df2e1e5d00436d3166a07aa1",
  "catalystVersion": "4.8.6",
  "ethNetwork": "mainnet"
}
```

当 `synchronizationState` 是 `Bootstrapping`时，节点会暂时暂停接受新的部署。此措施可确保在节点于 DAO 网络中更新到最新状态之前，不会部署任何新实体。一旦状态变为 `Syncing`，这表示节点已经成功追上并正在持续接收最新更新。这是节点完全正常工作并接受新部署时的健康状态。

```json
{
  "synchronizationStatus": {
    "lastSyncWithDAO": 1658153872301,
    "synchronizationState": "Syncing"
  },
  "snapshot": {
    "entities": {
      "profile": 1271317,
      "scene": 23477,
      "store": 890,
      "wearable": 17350
    },
    "lastUpdatedTime": 1658152050030
  },
  "version": "v3",
  "commitHash": "9a2e0d5d05d02646df2e1e5d00436d3166a07aa1",
  "catalystVersion": "4.8.6",
  "ethNetwork": "mainnet"
}
```

如果你更喜欢命令行风格，你可以在内容服务器 docker 镜像日志中搜索这条消息： `开始从服务器指针变更同步实体`。一旦你看到这段文字，内容服务器就已完全同步并可正常使用。

### 环境变量

以下是内容服务器所有环境变量及其默认值的完整列表，这些值是在启动期间记录于内容服务器日志中的：

```jsx
STORAGE_ROOT_FOLDER: "/app/storage/content_server/"
DENYLIST_FILE_NAME: "denylist.txt"
DENYLIST_URLS: "https://config.decentraland.org/denylist"
SYNC_IGNORED_ENTITY_TYPES: ""
FOLDER_MIGRATION_MAX_CONCURRENCY: 1000
SERVER_PORT: 6969
LOG_REQUESTS: false
UPDATE_FROM_DAO_INTERVAL: 1800000
SYNC_WITH_SERVERS_INTERVAL: 45000
CHECK_SYNC_RANGE: 1200000
DECENTRALAND_ADDRESS: "0x1337e0507eb4ab47e08a179573ed4533d9e22a7b"
DEPLOYMENTS_DEFAULT_RATE_LIMIT_TTL: 60
DEPLOYMENTS_DEFAULT_RATE_LIMIT_MAX: 300
ETH_NETWORK: "mainnet"
LOG_LEVEL: "debug"
FETCH_REQUEST_TIMEOUT: "2m"
USE_COMPRESSION_MIDDLEWARE: false
BOOTSTRAP_FROM_SCRATCH: false
REQUEST_TTL_BACKWARDS: 1200000
LAND_MANAGER_SUBGRAPH_URL: "https://api.thegraph.com/subgraphs/name/decentraland/land-manager"
COLLECTIONS_L1_SUBGRAPH_URL: "https://api.thegraph.com/subgraphs/name/decentraland/collections-ethereum-mainnet"
COLLECTIONS_L2_SUBGRAPH_URL: "https://api.thegraph.com/subgraphs/name/decentraland/collections-matic-mainnet"
THIRD_PARTY_REGISTRY_L2_SUBGRAPH_URL: "https://api.thegraph.com/subgraphs/name/decentraland/tpr-matic-mainnet"
BLOCKS_L1_SUBGRAPH_URL: "https://api.thegraph.com/subgraphs/name/decentraland/blocks-ethereum-mainnet"
BLOCKS_L2_SUBGRAPH_URL: "https://api.thegraph.com/subgraphs/name/decentraland/blocks-matic-mainnet"
PSQL_DATABASE: "content"
PSQL_HOST: "postgres"
PSQL_SCHEMA: "public"
PSQL_PORT: "5432"
GARBAGE_COLLECTION: true
GARBAGE_COLLECTION_INTERVAL: 21600000
PG_IDLE_TIMEOUT: 30000
PG_QUERY_TIMEOUT: 60000
PG_STREAM_QUERY_TIMEOUT: 600000
SNAPSHOT_FREQUENCY_IN_MILLISECONDS: 21600000
CUSTOM_DAO: undefined
DISABLE_SYNCHRONIZATION: false
SYNC_STREAM_TIMEOUT: "10m"
CONTENT_SERVER_ADDRESS: "http://localhost/content/"
REPOSITORY_QUEUE_MAX_CONCURRENCY: 50
REPOSITORY_QUEUE_MAX_QUEUED: 300
REPOSITORY_QUEUE_TIMEOUT: "1m"
ENTITIES_CACHE_SIZE: 150000
DEPLOYMENT_RATE_LIMIT_MAX: {}
DEPLOYMENT_RATE_LIMIT_TTL: {}
VALIDATE_API: false
RETRY_FAILED_DEPLOYMENTS_DELAY_TIME: 900000
```

### 将你的节点用于生产

如果你想运行自己的服务器并帮助扩展网络，首先这非常棒，社区和基金会真的很感谢你这样做。

在这种情况下，你需要通过访问 [这个链接](https://governance.decentraland.org/submit/catalyst/)来申请 DAO 的批准以加入网络。你也可以申请一笔 MANA 资助，以覆盖基础设施和管理费用。

重要的是，你的硬件配置应更接近上文硬件要求中建议的规格，因为该服务器将被社区中的任何成员用来进入 Decentraland。

### API 规范

想了解内容、lambdas 和 comms 服务器 API 的更多细节，可以查看 [API 规范](https://decentraland.github.io/catalyst-api-specs).

### 故障排查/常见问题

启动服务器时可能会出一些问题。下面列出了一些历史上最常见的问题以及如何修复它们。

#### 端口 5432 被本地 postgres 占用

如果你在一台用于开发的机器上运行节点，或者它已经在托管其他服务，那么那台机器上很可能已经有一个 postgres 数据库服务器在运行了。因此端口 5432 可能已经被占用。

最简单的解决方法是停止已经在本地运行的 postgres，然后使用以下命令重启 postgres docker 容器： `docker start postgres`.

如果你了解 docker compose，可以尝试调整 `docker-compose.yml` 以及环境变量，看看能否让它运行在其他端口。为了保持这里的讲解尽量简单，我们在本教程中不会走这条路。

#### 端口 80 被本地 nginx 占用

端口 80（甚至 443）也可能出现同样的问题。如果你在本地机器上运行 nginx，那么端口 80/443 很可能已经被该服务占用，因此 Catalyst Docker 容器将无法使用它们。

同样，最简单的方法是停止本地 nginx 服务，然后使用以下命令重启 docker 容器： `docker start nginx`。或者，你需要借助 `docker-compose.yml` 和 `.env` 来让它运行在其他端口。

### 供参考的其他文档

如果你想更好地了解 Catalyst 服务器的作用、它包含哪些服务等，可以查看架构仓库 <https://github.com/decentraland/architecture，里面对各个部分有详细说明。>

如果你想为 Catalyst 服务器代码做贡献，请务必查看 [贡献指南](https://github.com/decentraland/catalyst/blob/main/docs/CONTRIBUTING.md) ，了解我们的开发流程、如何提交 bug 修复和改进，以及如何构建和测试你的更改。

最后，如果你需要联系团队，可以通过以下方式： [Discord](https://discord.com/channels/417796904760639509/948230185457696820) 或者提交 [GitHub 问题](https://github.com/decentraland/catalyst/issues).


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.decentraland.org/contributor/contributor-zh/jiao-cheng/how-to-run-a-catalyst.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
