> ## Documentation Index
> Fetch the complete documentation index at: https://docs.ss14.art/llms.txt
> Use this file to discover all available pages before exploring further.

# Настройка SS14.Watchdog

<Info>
  Прежде чем нырять с головой, вам стоит *как минимум* пройти через хостинг обычного сервера и научиться им управлять.

  Также может быть полезно ознакомиться с [настройкой среды разработчика](../general-development/setup/setting-up-a-development-environment), так как вам понадобится хотя бы `dotnet` для компиляции Watchdog и Python для запуска некоторых скриптов сборки сервера.

  Также стоит ознакомиться с разделом о пользовательских кодовых базах, особенно если вы собираетесь использовать их с кастомной кодовой базой.
</Info>

{/*
Спасибо, я ненавижу это.
*/}

[`SS14.Watchdog`](https://github.com/space-wizards-federation/SS14.Watchdog/) (кодовое имя Ian) — это наша обёртка для хостинга серверов, похожая на TGS для BYOND (но на данный момент гораздо проще). Он обрабатывает автообновления, мониторинг, автоматические перезапуски и администрирование. Мы рекомендуем использовать его для полноценных развёртываний.

## Процесс настройки

### 1. Проверка предварительных требований

Вам необходимо иметь:

* .NET 10 SDK
* ASP .NET Core 10 Runtime

Всё это можно найти на [странице загрузки .NET 10](https://dotnet.microsoft.com/en-us/download/dotnet/10.0).

В Linux используйте ваш любимый пакетный менеджер (apt, dnf, pacman, brew и т.д.) в соответствии с [инструкциями Microsoft](https://learn.microsoft.com/en-us/dotnet/core/install/linux).

### 2. Сборка

Следующий набор команд должен собрать Watchdog в Linux-системе. Вам, конечно, придётся адаптировать его под вашу реальную систему.

```
# Скачайте репозиторий SS14.Watchdog и все подмодули и т.д.
git clone --recursive https://github.com/space-wizards-federation/SS14.Watchdog

# Перейдите в директорию SS14.Watchdog.
cd SS14.Watchdog

# Соберите Watchdog.
# Результат будет помещён в: SS14.Watchdog/bin/Release/net10.0/linux-x64/publish
dotnet publish -c Release -r linux-x64 --no-self-contained
```

Содержимое `SS14.Watchdog/bin/Release/net10.0/linux-x64/publish` затем можно скопировать в другое место. Здесь вы продолжите работу.

### 3. Запуск

Предполагая, что вы следовали описанной выше структуре, вам просто нужно открыть терминал в папке, куда вы скопировали файлы, и запустить исполняемый файл `SS14.Watchdog`.

## Конфигурация Watchdog

Конфигурационный файл Watchdog — `appsettings.yml`

Конфигурация watchdog разделена на два основных раздела:

* Глобальные элементы, общие для всех экземпляров (серверов).
* Элементы для каждого экземпляра.

### Serilog, AllowedHosts

Обычно их не нужно менять, и они слишком сложны для описания здесь.

### BaseUrl

Представляет внешний URL Watchdog.
Он автоматически передаётся экземплярам, чтобы они могли связываться с Watchdog.
Также используется в режимах обновления, требующих подключения клиентов к Watchdog для получения ресурсов.

```yml theme={null}
# Обычно то, что нужно, если только не используется для клиентских ZIP-архивов.
BaseUrl: "http://localhost:5000/"
```

### Urls

Контролирует, на каких интерфейсах работает Watchdog, что может быть важно в некоторых случаях.
В частности, это может использоваться для открытия доступа к Watchdog извне localhost без обратного прокси, например:

```yml theme={null}
Urls: "http://*:5000"
```

Смотрите соответствующую документацию для более подробной информации: [docs.microsoft.com](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/host/web-host?view=aspnetcore-9.0#server-urls)

Не забудьте соответствующим образом изменить BaseUrl!

### Уведомления

Теперь вы можете настроить Discord webhook для уведомлений, чтобы получать сообщения при сбое сервера; интеграция настолько же проста, как добавление следующего в вашу конфигурацию.

```yml theme={null}
Notification:
  DiscordWebhook: "https://discord.com/api/webhooks/..."
```

### Экземпляры (Instances)

Каждый экземпляр — это отдельный игровой сервер, поэтому термины «экземпляр» и «сервер» можно использовать как взаимозаменяемые.

```yml theme={null}
Servers:
  Instances:
    example:
      # Это предполагаемое «человеческое» имя экземпляра.
      # На практике иногда используется в логировании.
      # Оно не влияет, например, на game.hostname.
      Name: "Example"

      # Это API-токен для внешнего доступа.
      # (В отличие от API-токена, используемого внутри между Watchdog и игровым сервером.
      #  Он генерируется случайным образом.)
      ApiToken: "you should choose a better token"

      # Несколько обманчиво — это порт игрового сервера на localhost.
      # Он НЕ будет автоматически синхронизироваться с реальным портом в конфиге.
      ApiPort: 1212

      # Тип обновления и дополнительные параметры управляют тем, откуда берётся серверное ПО.
      # Этот пример предназначен для официальных серверных сборок.
      UpdateType: "Manifest"
      Updates:
        ManifestUrl: "https://wizards.cdn.spacestation14.com/fork/wizards/manifest"

      # Ожидается, что сервер будет периодически отправлять ping Watchdog.
      # (Упомянутый выше BaseUrl передаётся серверу для этого.)
      # Это подтверждает, что сервер не упал, например.
      # Если он упал, сервер принудительно перезапускается.
      # Однако запуск может быть довольно долгим процессом на некоторых системах.
      TimeoutSeconds: 60
      # Если включено, при зависании сохраняются данные о состоянии сервера для анализа.
      # DumpOnTimeout: true
      # TimeoutDumpType управляет тем, как это настраивается, но я не уверен в деталях.

      # Программа для запуска сервера может быть задана здесь.
      # Обратите внимание, что реально это не нужно менять, если только вы:
      # A. Не пытаетесь выполнить более продвинутую диагностику (например, прикрепить отладчик)
      # B. Не делаете что-то очень непохожее на запуск сервера Space Station 14
      # RunCommand: "./wrapper.sh"

      # Переменные окружения можно задать здесь.
      # См., например, Performance Tweaks в Server Operator's Handbook.
      # EnvironmentVariables:
      #   ROBUST_NUMERICS_AVX: "true"
```

### Папка экземпляра сервера

Watchdog автоматически создаст структуру папок для каждого экземпляра сервера. Она находится в `instances/<instanceId>`, например `instances/wizards_den` / `instances/wizards_den_two`, относительно текущей рабочей директории при выполнении watchdog. В примере конфигурации выше это было бы `instances/example`

Каждая папка экземпляра содержит следующие файлы и папки:

* `binaries/`: Используется для хранения клиентских бинарных файлов при использовании типа обновления «Local», см. ниже.
* `bin/`: Содержит собственно извлечённые серверные бинарные файлы.
* `data/`: Хранит данные сервера, такие как предпочтения игроков.
* `config.toml`: Это конфигурационный файл, который будет загружать сервер (watchdog переопределяет расположение по умолчанию, `server_config.toml` рядом с .exe, чтобы он не удалялся при сбросе сервера). Возможно, вам придётся создать этот файл вручную в первый раз.
* `data.json`: Содержит информацию watchdog. Если вы изменили тип обновления и получаете ошибки, удалите этот файл.

<Info>
  Обратите внимание, что хотя watchdog обрабатывает обновления сервера, вам всё равно может потребоваться настроить config.toml в соответствии с руководством оператора сервера.
</Info>

## Управление Watchdog

Есть две ключевые ситуации, когда требуется управление watchdog.

Во-первых, watchdog будет обновляться только тогда, когда ему либо явно сообщат проверить наличие обновлений, либо когда он будет перезапущен.

Во-вторых, вы можете просто принудительно перезапустить сервер.

В-третьих, вы можете захотеть завершить сервер после окончания раунда. Например, для обслуживания.

Эти задачи можно выполнить с помощью следующих команд:

`curl -v -X POST -u myInstance:ApiToken http://localhost:5000/instances/myInstance/restart`

`curl -v -X POST -u myInstance:ApiToken http://localhost:5000/instances/myInstance/update`

`curl -v -X POST -u myInstance:ApiToken http://localhost:5000/instances/myInstance/stop`

## Типы обновлений

### Манифестное обновление (Manifest)

<Info>
  Сервер всё равно не будет автоматически уведомлён об обновлениях, поэтому смотрите инструкции выше.
</Info>

Тип Manifest — это метод, который используют все серверы Wizard's Den, и мы рекомендуем его. Manifest требуется для возможности записи [реплеев](../server-hosting/server-replay-recording).

```yml theme={null}
Servers:
  Instances:
    example:
      # (Это пример, НЕ копируйте его вслепую. Иначе вы можете получить незавершённую конфигурацию.)
      UpdateType: "Manifest"
      Updates:
        ManifestUrl: "https://wizards.cdn.spacestation14.com/fork/wizards/manifest"
```

### Git-обновления

<Danger title="Здесь водятся драконы!">
  Метод обновления на основе Git не поддерживается. Хотя это самый простой способ начать работу, мы не сможем вам помочь, если он сломается. Вы в основном предоставлены сами себе.
</Danger>

<Warning>
  Использование Git-обновлений предполагаемым образом может находиться в различных состояниях «сломанности» из-за различных способов, которыми репозиторий может прийти в состояние, которое лучше всего описать как, ну, *сломанное*.
  Это не должно касаться вас, если вы просто доставляете предварительно скомпилированные обновления на сервер с помощью Git, но это тоже неудобно и не является предполагаемым способом работы.
</Warning>

SS14.Watchdog может компилировать и обновлять сервер, когда коммиты отправляются в ветку Git-репозитория, содержащего исходный код вашего форка.

<Info>
  Для этого на сервере должны быть необходимые части среды разработчика.
  Кроме того, вам всё равно нужно написать Git hook или что-то подобное, чтобы гарантировать, что Watchdog уведомляется об обновлениях, или иным образом заставить его периодически проверять наличие обновлений.
</Info>

```yml theme={null}
Servers:
  Instances:
    example:
      # (Это пример, НЕ копируйте его вслепую. Иначе вы можете получить незавершённую конфигурацию.)
      UpdateType: "Git"
      Updates:
        # BaseUrl: URL Git-репозитория для отслеживания.
        # Он отличается от общеwatchdog'ового BaseUrl.
        BaseUrl: "https://github.com/moonheart08/outer-rim-14/"
        # Branch: Ветка для отслеживания.
        Branch: "master"
        # Hybrid ACZ: При включении игровой сервер сам размещает клиентский zip, а не watchdog.
        # С момента внедрения дельта-обновлений это теперь лучший способ обработки.
        HybridACZ: true
```

### Jenkins-обновления

Это древний метод, но он всё ещё должен работать.

```yml theme={null}
Servers:
  Instances:
    example:
      # (Это пример, НЕ копируйте его вслепую. Иначе вы можете получить незавершённую конфигурацию.)
      UpdateType: "Jenkins"
      Updates:
        BaseUrl: "http://localhost:9938"
        JobName: "Star"
```

### Провайдер обновлений «Dummy»

Провайдер обновлений «Dummy» будет имитировать обновление при каждом запросе, а в остальном просто предполагает, что сервер уже извлечён в `bin/`.

Поскольку Watchdog не проверяет автоматически наличие обновлений периодически, имитация обновлений не должна мешать.

Чтобы настроить это, используйте следующую конфигурацию обновления в вашем `appsettings.yml` в записи для вашего экземпляра сервера:

```yml theme={null}
Servers:
  Instances:
    example:
      # (Это пример, НЕ копируйте его вслепую. Иначе вы можете получить незавершённую конфигурацию.)
      UpdateType: "Dummy"
```

### Пользовательские автообновления

Не поддерживается, но должно быть относительно тривиально отредактировать код `SS14.Watchdog`, чтобы добавить поддержку любого необходимого вам механизма обновления. Смотрите `UpdateProvider.cs`.

## Типы обновлений (сделай сам)

### Провайдер обновлений «Dummy», версия DIY

Прежде чем пытаться это сделать, убедитесь, что вы знакомы с использованием провайдера обновлений «Dummy» в целом.

Настроить всё для поддержки обновлений относительно просто. Следующие инструкции предназначены для Unix-подобных систем, но идея должна быть понятна в любом случае.

Начните с настройки следующим образом:

```yml theme={null}
Servers:
  Instances:
    example:
      # (Это пример, НЕ копируйте его вслепую. Иначе вы можете получить незавершённую конфигурацию.)
      UpdateType: "Dummy"
      RunCommand: "./currentServer"
```

Основная идея этого механизма — использование символических ссылок для переключения между используемыми директориями.

Для этого нужны три скрипта: `switchTo`, `switchTo1` и `switchTo2`:

`switchTo`:

```
#!/bin/sh
rm currentServer switch inactiveBin ; mkdir -p $1
ln -s $1/Robust.Server currentServer ; ln -s $2 switch ; ln -s $3 inactiveBin
echo Switching to $1
curl -v -X POST -u myInstance:ApiToken http://localhost:5000/instances/myInstance/update
```

`switchTo1`:

```
#!/bin/sh
./switchTo bin1 switchTo2 bin2
```

`switchTo2`:

```
#!/bin/sh
./switchTo bin2 switchTo1 bin1
```

После того как эти скрипты сделаны исполняемыми (`chmod +x switchTo*`) и один из них запущен, выполнение `./switch` после этого будет переключать между двумя директориями.

Таким образом, рабочий процесс заключается в удалении всего из `inactiveBin`, затем извлечении нового сервера туда, а затем запуске `./switch` для подтверждения.

Перед очисткой и извлечением новой сборки сервера в `inactiveBin` убедитесь, что сервер действительно перезапустился после предыдущего обновления и больше не использует эту директорию.

### DIY-манифест сервера

Это быстрый скрипт, полезный для настройки DIY-сервера для типа обновления Manifest, описанного в разделе о манифесте.

Он предполагает, что у вас есть произвольный статический HTTP-сервер, и вам нужен только скрипт для вывода JSON с обновлённой датой (чтобы вы могли просто передать два файла на статический HTTP-сервер и инициировать обновление).

```python theme={null}
import json, datetime
nowish = datetime.datetime.now().isoformat()
print(json.dumps({"builds":{nowish: {"time": nowish, "client": {"url": "", "sha256": ""}, "server": {"linux-x64": {"url": "http://localhost:9283/SS14.Server_linux-x64.zip", "sha256": ""}}}}}))
```

## Systemd-сервис

Чтобы watchdog работал в фоне и автоматически запускался при загрузке сервера, вы можете создать сервисный файл. Он будет выглядеть примерно так.

Разумеется, настройте его под актуальную директорию вашего watchdog.

Если ваш дистрибутив не использует systemd в качестве инита, вам придётся преобразовать это в соответствующий init.

<Info>
  Из-за того, как работают сервисы, вы не сможете использовать консоль сервера SS14 напрямую из терминала, если это необходимо. Убедитесь, что вы предоставили себе разрешения на сервере, чтобы использовать команды `sudo` или `>` для выполнения команд на сервере.
</Info>

`/etc/systemd/system/SS14.Watchdog.service`

```toml theme={null}
[Unit]
Description=SS14 Watchdog
After=network.target

[Service]
ExecStart=/path/to/SS14.Watchdog
WorkingDirectory=/path/to
Restart=on-failure
# Это предотвращает отправку systemd сигнала SIGTERM watchdog'у и его завершение, если один из серверов умирает от OOM.
OOMPolicy=continue
# Это используется для git-метода, чтобы он не падал мгновенно.
Environment="DOTNET_CLI_HOME=/tmp"

[Install]
WantedBy=default.target
```

Теперь перезагрузите демон systemd и включите сервис обычным образом.

```
# Перезагрузите демон systemd (требуется при создании нового сервисного файла)
systemctl daemon-reload

# Запустите сервис Watchdog в фоне
systemctl start SS14.Watchdog

# Включите сервис Watchdog, чтобы он запускался при старте системы.
systemctl enable SS14.Watchdog
```

Если вы ещё не знаете, как использовать systemctl, [сейчас самое время узнать](https://www.digitalocean.com/community/tutorials/how-to-use-systemctl-to-manage-systemd-services-and-units).

Для просмотра логов используйте [journalctl](https://www.digitalocean.com/community/tutorials/how-to-use-journalctl-to-view-and-manipulate-systemd-logs).

## Персистентность серверов

Изменение конфигурации watchdog или его обновление требует перезапуска, и по умолчанию это означает перезапуск всех игровых серверов, работающих под watchdog. Начиная с коммита [`6194ed4`](https://github.com/space-wizards-federation/SS14.Watchdog/commit/6194ed481a6007949b7449dcf7140a1387e2ec2f), watchdog поддерживает *персистентность серверов*. Это позволяет перезапускать его независимо, не затрагивая сами игровые серверы.

Чтобы настроить это, добавьте следующее в ваш `appsettings.yml`:

```yml theme={null}
Process:
  PersistServers: true
```

С этой настройкой watchdog не будет завершать игровые серверы при собственном завершении и при перезапуске попытается найти предыдущий процесс игрового сервера, чтобы продолжить наблюдение за ним.

### Systemd

При размещении watchdog в качестве сервиса Systemd вышеописанного недостаточно. С настройками Systemd по умолчанию перезапуск watchdog приведёт к тому, что Systemd также убьёт процессы игровых серверов. Этого можно избежать, установив следующее в определении сервиса:

```ini theme={null}
[Service]
KillMode=process
```

Это заставит Systemd останавливать только основной процесс watchdog, не затрагивая процессы игровых серверов ниже. Это, конечно, означает, что попытка выполнить `systemctl stop ss14-watchdog` не остановит игровые серверы, даже если они неправильно работают/зависли.

## Общие неполадки

### Сервер постоянно перезапускается каждые 30 секунд

Это означает, что сервер неправильно взаимодействует с watchdog, и watchdog вынужден предположить, что сервер завис или что-то в этом роде. Это происходит, если `BaseUrl` в конфигурации watchdog установлен неверно или иным образом недоступен для игрового сервера.

### `System.IO.FileNotFoundException: Could not load file or assembly 'Mono.Posix.NETStandard, Version=1.0.0.0, Culture=neutral` (...)

Текущая рабочая теория состоит в том, что это вызвано неправильными параметрами dotnet publish.
Приведённый ниже набор результатов тестов должен помочь объяснить.

```
dotnet publish -c Release -r linux-x64 --no-self-contained SS14.Watchdog -o test
 RESULT: Mono.Posix.NETStandard.dll included, System.dll not included (as expected)

dotnet publish -c Release -r linux-x64 SS14.Watchdog -o test
 RESULT: Mono.Posix.NETStandard.dll included, System.dll included

dotnet publish -c Release SS14.Watchdog -o test
 RESULT: Mono.Posix.NETStandard.dll not included, System.dll not included
```

Поскольку Watchdog использует `Mono.Posix.NETStandard.dll` для пометки исполняемых файлов как исполняемых в Linux и Mac OS X, важно иметь его в этих ОС.

## Пример старой конфигурации

(Этот раздел извлечён из более старой версии данного руководства с небольшими изменениями на случай, если он всё ещё может быть полезен. Возможно, он устарел.)

Пример с наших официальных серверов (токены, очевидно, удалены):

```yml theme={null}
Serilog:
  Using: [ "Serilog.Sinks.Console", "Serilog.Sinks.Loki" ]
  MinimumLevel:
    Default: Information
    Override:
      SS14: Information
      Microsoft: "Warning"
      Microsoft.Hosting.Lifetime: "Information"
      Microsoft.AspNetCore: Warning

  WriteTo:
    - Name: Console
      Args:
        OutputTemplate: "[{Timestamp:HH:mm:ss} {Level:u3} {SourceContext}] {Message:lj}{NewLine}{Exception}"

  Enrich: [ "FromLogContext" ]

  # Раскомментируйте, чтобы watchdog логировал в Loki
  #Loki:
  #  Address: "{{ loki_addr }}"
  #  Name: "{{ server_id }}"
  #  Username: "{{ loki_user }}"
  #  password: "{{ loki_pass }}"

AllowedHosts: "*"

Notification:
  DiscordWebhook: "https://discord.com/api/webhooks/..."

# API URL, по которому ваш watchdog доступен.
# Это ОБЯЗАТЕЛЬНО нужно установить, чтобы игровые серверы могли связываться с watchdog.
# Если вы не хотите делать watchdog публично доступным, укажите `http://localhost:5000/`.
BaseUrl: https://builds.spacestation14.io/watchdog/

Servers:
  Instances:
    # ID вашего сервера.
    wizards_den:
      # Имя сервера
      Name: "Wizard's Den"
      ApiToken: "foobar" # API-токен для удалённого управления этим экземпляром, например, запуск обновлений, перезапуск сервера.
      ApiPort: 1212 # API-порт ИГРОВОГО СЕРВЕРА. Должен совпадать с HTTP API статуса на порту 1212 (описан ниже). В противном случае watchdog не сможет связаться с игровым сервером.
      
      # Конфигурация автообновления. Можно пропустить, если автообновления не нужны. Пример для наших официально размещённых сборок.
      # Смотрите выше альтернативы.
      UpdateType: "Manifest"
      Updates:
        ManifestUrl: "https://wizards.cdn.spacestation14.com/fork/wizards/manifest"
        
      # Любые переменные окружения, которые вы можете указать.
      EnvironmentVariables:
        Foo: bar
```
