# Cómo ejecutar un nodo Catalyst

¿Alguna vez te has preguntado cómo funcionan los nodos Catalyst de Decentraland? ¿Alguna vez quisiste ejecutar tu propio nodo y te sentiste abrumado sobre por dónde empezar? ¿Estás creando contenido para Decentraland y te resulta difícil hacer todo el ciclo de desarrollo y pruebas en servidores de producción?

Si estás (o has estado) en esa situación, no temas más. Este tutorial te ayudará en el proceso de planificación, a determinar qué necesitas decidir y luego te guiará paso a paso para poner en marcha el servidor. Además, en caso de que algo no salga según lo planeado, hay una sección de resolución de problemas al final con algunos de los problemas más comunes y cómo solucionarlos.

¿Listo? Manos a la obra.

### Requisitos de hardware

Los servidores de la Decentraland Foundation están desplegados en Amazon AWS en `t2.xlarge` instancias. Así que, aunque esos servidores están pensados para uso público, el tuyo puede estar bien con especificaciones mucho más pequeñas, dependiendo del uso previsto.

Un AWS EC2 `t2.xlarge` tiene el siguiente hardware:

* 4 vCPUs.
* 16 Gb RAM

Y para almacenamiento de archivos + almacenamiento de BD, un SSD / HDD con 2 Tb de capacidad debería ser más que suficiente. Al momento de escribir esto, los servidores de la foundation están usando un poco más de 1 Tb para todo el almacenamiento.

### Pre-requisitos de software

Lo siguiente es requerido para ejecutar catalyst-owner:

* Sistema operativo Linux / MacOS
* Docker / docker-compose
* Git
* LiveKit Cluster

### Algunas opciones a considerar antes de empezar

* ¿Quieres que tu nodo esté expuesto públicamente en Internet? Si es así, necesitarás una instancia expuesta a Internet y una URL pública para conectarte a ella.
* ¿El nodo se va a usar para el desarrollo de escenas, wearables, etc.? En ese caso, las especificaciones de hardware pueden ser mucho más pequeñas, ya que probablemente será accedido por una o dos personas, no por cientos de usuarios.
* ¿Quieres sincronizar todos los tipos de entidades? Si lo usas para desarrollar escenas, probablemente quieras omitir la sincronización de profiles, ya que consumen mucho tiempo, ancho de banda y, lo más importante, espacio en disco y no te beneficiarán para tu objetivo.

### LiveKit

Un LiveKit cluster externo es necesario para que el servicio Comms de Catalyst orqueste las comunicaciones entre jugadores. Para ello hay dos opciones: usar una cuenta LiveKit Cloud o ejecutar tu propio LiveKit cluster.

La recomendación es configurar [Livekit Cloud account](https://cloud.livekit.io/) que viene con un nivel gratuito que puede gestionar 100 usuarios, o pagar el servicio según el tráfico. Este enfoque es más sencillo ya que no requiere provisionar infraestructura adicional y el servicio puede gestionar el escalado. De lo contrario, será necesario provisionar un LiveKit cluster. LiveKit hace un muy buen trabajo con su documentación:

* [Despliegue](https://docs.livekit.io/oss/deployment/)
* [Configuración distribuida](https://docs.livekit.io/oss/deployment/distributed/)

*En caso de que quieras profundizar en los detalles técnicos necesarios para soportar comunicaciones basadas en transporte LiveKit, revisa el* [*ADR-70 New Communications Architecture*](https://adr.decentraland.org/adr/ADR-70)*.*

### Guía paso a paso

Lo primero es clonar el [catalyst-owner](https://github.com/decentraland/catalyst-owner) repositorio desde GitHub

```bash
> git clone https://github.com/decentraland/catalyst-owner.git
Cloning into 'catalyst-owner'...
remote: Enumerating objects: 2392, done.
remote: Counting objects: 100% (602/602), done.
remote: Compressing objects: 100% (168/168), done.
remote: Total 2392 (delta 506), reused 481 (delta 430), pack-reused 1790
Receiving objects: 100% (2392/2392), 926.05 KiB | 1.09 MiB/s, done.
Resolving deltas: 100% (1257/1257), done.
> cd catalyst-owner
```

Una vez hecho eso, es momento de configurar las variables de entorno para el nodo y hacer los cambios que correspondan.

```bash
# En la carpeta /catalyst-owner
> cp .env.example .env
> cp .env-advanced.example .env-advanced
```

Ahora, usando tu editor de texto favorito, realiza los cambios necesarios en estos archivos. Por ejemplo, configurar la `EMAIL` variable de entorno con un email válido es obligatorio para que puedas recibir actualizaciones sobre la expiración del certificado de Certbot.

También puede ser necesario configurar tu valor particular para `CATALYST_URL` especialmente si tu servidor va a estar expuesto públicamente en Internet. Para uso en tu máquina local, el valor por defecto de `http://localhost` servirá.

**Comms Service**

Una vez que el cluster LiveKit esté disponible necesitarás establecer las variables específicas de LiveKit para que el servicio Comms funcione, por ejemplo:

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

El `ROOM_PREFIX` la variable es opcional y puede configurarse para identificar las salas LiveKit creadas por el Catalyst. Esto es útil si más de un Catalyst está usando el mismo LiveKit Cluster.

**Content Server**

Hay una variable llamada `CONTENT_SERVER_STORAGE` que define la carpeta local que el content server usará para el almacenamiento. Esto por defecto es `CONTENT_SERVER_STORAGE=./storage`. Puedes cambiar este valor para almacenar archivos en otro lugar, o al menos asegurarte de que la carpeta referenciada existe. Puede que necesites crearla así:

```bash
# En la carpeta /catalyst-owner o donde apunte CONTENT_SERVER_STORAGE
> mkdir storage
```

Hay otra variable interesante `SYNC_IGNORED_ENTITY_TYPES` que permite ignorar ciertos tipos de entidades durante el proceso de sincronización. Si vas a usar el servidor Catalyst para desarrollo, quizás no necesites que todos los tipos de contenido sean sincronizados. Puedes establecer la var de entorno `SYNC_IGNORED_ENTITY_TYPES="profile,store"` para que solo scenes y wearables sean traídos desde los servidores del DAO. Esto ahorrará mucho tiempo, ancho de banda y espacio en disco en tu servidor.

> 💡 Para una lista más exhaustiva de las variables de entorno soportadas, por favor consulta la [Environment variables](#environment-variables) sección más abajo.

#### Lanzar el nodo Catalyst

Una vez que todas las variables de entorno estén configuradas, es hora de iniciar el nodo. Esto debería ser tan fácil como ejecutar el `init.sh` script en la carpeta raíz.

```bash
# En la carpeta /catalyst-owner

> ./init.sh
## Loading env variables... [ OK ]
[ OK ]
## Checking if email is configured... [ OK ]
## Checking if storage is configured... [ OK ]
## Checking if catalyst url is configured... [ OK ]
 ADVERTENCIA: No estás ejecutando la imagen más reciente de los nodos Content y Lambdas de Catalyst.
 ADVERTENCIA: No estás ejecutando la imagen más reciente del nodo Archipelago de Catalyst.
 ADVERTENCIA: No estás ejecutando la imagen más reciente del nodo Explorer BFF de Catalyst.
 - DOCKER_TAG:               45a5154f11b53d55aadfdf7f958e2fce6a964824
 - LIGHTHOUSE_DOCKER_TAG:    latest
 - CATALYST_URL:             http://localhost
 - CONTENT_SERVER_STORAGE:   ./storage
 - EMAIL:                    a@a.com
 - ETH_NETWORK:              mainnet
 - REGENERATE:               0

Iniciando en 5 segundos...
45a5154f11b53d55aadfdf7f958e2fce6a964824: Pulling from decentraland/catalyst-content
Digest: sha256:d6c2981c57cb9367fdb3228d15b07e4d26e62c902944115937de24ecd3ab6aac
Status: Image is up to date for decentraland/catalyst-content:45a5154f11b53d55aadfdf7f958e2fce6a964824
docker.io/decentraland/catalyst-content:45a5154f11b53d55aadfdf7f958e2fce6a964824
45a5154f11b53d55aadfdf7f958e2fce6a964824: Pulling from decentraland/catalyst-lambdas
Digest: sha256:5605812dd29316afc32e561d2a2ce1311f164f07ef3cd99a1cd60727518636e5
Status: Image is up to date for decentraland/catalyst-lambdas:45a5154f11b53d55aadfdf7f958e2fce6a964824
docker.io/decentraland/catalyst-lambdas:45a5154f11b53d55aadfdf7f958e2fce6a964824
latest: Pulling from decentraland/catalyst-lighthouse
Digest: sha256:fedc10b714823909f0a1c17955eed2f22a02e4f784090848d3253ef734e410d4
Status: Image is up to date for decentraland/catalyst-lighthouse:latest
docker.io/decentraland/catalyst-lighthouse:latest
latest: Pulling from decentraland/archipelago-service
Digest: sha256:e2c1d6fa96a5cfbbf6fb37e3840c0724fb5abeef8c366025a28fab3ad33d6480
Status: Image is up to date for quay.io/decentraland/archipelago-service:latest
quay.io/decentraland/archipelago-service:latest
latest: Pulling from decentraland/explorer-bff
Digest: sha256:fa9e305c44972a8613b01f4cd573d6fb84b0fb03ce953a506fbb06053202913c
Status: Image is up to date for quay.io/decentraland/explorer-bff:latest
quay.io/decentraland/explorer-bff:latest
Deteniendo nginx ... hecho
## Usando HTTP porque CATALYST_URL está configurado a http://localhost
## Reemplazando el valor $katalyst_host en el archivo del servidor nginx... [ OK ]
## Reiniciando contenedores...
Creando la red "catalyst-owner_default" con el driver por defecto
Creando catalyst-owner_comms-server_1 ... hecho
Creando node-exporter                   ... hecho
Creando catalyst-owner_lambdas_1      ... hecho
Creando postgres                      ... hecho
Creando catalyst-owner_certbot_1        ... hecho
Creando nats                            ... hecho
Creando postgres-exporter               ... hecho
Creando catalyst-owner_content-server_1 ... hecho
Creando catalyst-owner_archipelago_1    ... hecho
Creando catalyst-owner_explorer-bff_1   ... hecho
Creando nats-exporter                   ... hecho
Creando cadvisor                        ... hecho
Creando nginx                           ... hecho
## El servidor Catalyst está arriba y funcionando en http://localhost
```

Si todo salió bien, ahora tenemos un nodo completo de Decentraland en ejecución. Ahora puedes ir al navegador y escribir la URL. Si usas la configuración por defecto, debería ser [`http://localhost`](http://localhost/).

Podemos revisar los logs del content server con este comando docker:

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

Aunque el servidor ahora está en ejecución, no está 100% listo para operar. Necesita sincronizar el contenido desde los otros [servers of the DAO](https://decentraland.github.io/catalyst-monitor) para poder ofrecer la misma experiencia a los usuarios conectados a él. La sincronización puede tardar mucho tiempo. Con una buena conexión a Internet, 6 horas deberían ser bastante comunes. Así que… es hora de tomar un café, una siesta, dormir bien y volver mañana.

Una forma de saber si la sincronización está completa consiste en verificar los resultados del endpoint de estado del content: <http://localhost/content/status> (usa tu URL aquí).

```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"
}
```

Mientras `synchronizationState` es `Bootstrapping`, el nodo suspenderá temporalmente la aceptación de nuevos deployments. Esta medida asegura que no se desplieguen nuevas entidades hasta que el nodo esté actualizado dentro de la red del DAO. Una vez que el estado cambie a `Syncing`, indica que el nodo se ha puesto al día y ahora está recibiendo continuamente las últimas actualizaciones. Este es el estado saludable en el que el nodo está totalmente operativo y acepta nuevos deployments.

```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"
}
```

Si eres más del tipo cli, puedes grepear los logs de la imagen docker del content server buscando este mensaje: `Starting to sync entities from servers pointer changes`. Una vez que veas ese texto, el content server está totalmente sincronizado y listo para uso completo.

### Environment variables

Lo siguiente es una lista completa de todas las variables de entorno del content server con sus valores por defecto, tal como se registran en los logs del content server durante el arranque:

```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
```

### Usar tu nodo en producción

Si quieres ejecutar tu propio servidor y ayudar a escalar la red, ante todo eso es increíble, la comunidad y la foundation realmente aprecian que lo hagas.

En ese caso, tendrás que pasar por el proceso de solicitar la aprobación al DAO para unirte a la red visitando [this link](https://governance.decentraland.org/submit/catalyst/). También puedes solicitar una subvención en MANA para cubrir los gastos de infraestructura y gestión.

Es importante que las especificaciones de tu hardware estén más alineadas con lo sugerido arriba en los requisitos de hardware, ya que el servidor será usado por cualquier miembro de la comunidad que quiera entrar a Decentraland.

### Especificaciones de la API

Para más detalles sobre las APIs para content, lambdas y comms servers puedes consultar las [API specs](https://decentraland.github.io/catalyst-api-specs).

### Resolución de problemas / FAQ

Algunas cosas pueden salir mal al iniciar tu servidor. Aquí hay algunos de los problemas más comunes encontrados con el tiempo y cómo solucionarlos.

#### El puerto 5432 está siendo usado por postgres local

Si ejecutas el nodo en una máquina usada para desarrollo, o si ya aloja otros servicios, es probable que ya haya un servidor de base de datos postgres ejecutándose en esa máquina. Así que el puerto 5432 ya estará ocupado.

La manera más fácil de arreglar esto es detener el postgres que ya está corriendo localmente y luego reiniciar el contenedor postgres de docker usando `docker start postgres`.

Si tienes conocimientos de docker compose, puedes empezar a trastear con `docker-compose.yml` y las variables de entorno para intentar que funcione en otro puerto. Para mantener las cosas simples aquí, evitaremos ese camino en este tutorial.

#### El puerto 80 está siendo usado por nginx local

Lo mismo puede ocurrir con el puerto 80 (e incluso el 443). Si estás ejecutando nginx en la máquina local, es probable que los puertos 80/443 ya estén ocupados por ese servicio, por lo que el contenedor Docker de Catalyst no podrá usarlos.

De nuevo, el enfoque más sencillo sería detener el servicio nginx local y luego reiniciar el contenedor docker usando `docker start nginx`. O alternativamente, necesitas aprovechar `docker-compose.yml` y `.env` para conseguir que funcione en otro puerto.

### Documentación adicional como referencia

Si quieres entender mejor qué hace un servidor Catalyst, qué servicios incluye, etc., puedes revisar el repo de architecture <https://github.com/decentraland/architecture> que explica las partes en detalle.

Si te gustaría contribuir al código de los servidores Catalyst, asegúrate de revisar la [contributing guide](https://github.com/decentraland/catalyst/blob/main/docs/CONTRIBUTING.md) para aprender sobre nuestro proceso de desarrollo, cómo proponer correcciones de errores y mejoras, y cómo compilar y probar tus cambios.

Y finalmente, si necesitas contactar al equipo, puedes hacerlo vía [Discord](https://discord.com/channels/417796904760639509/948230185457696820) o enviando [GitHub issues](https://github.com/decentraland/catalyst/issues).
