# Встановлення BitTorrent трекера Aquatic в Linux

Давно збирався підняти BitTorrent трекер відкритого типу для мережі Yggdrasil.

Детальніше про мережу Yggdrasil читайте тут:
=> yggdrasil-is-network-with-distributed-routing.gmi Yggdrasil - мережа з децентралізованою маршрутизацією

Вже існує відомий сервер з 15-річною історією розробки OpenTracker:
=> https://erdgeist.org/arts/software/opentracker

Але останнім часом, я надаю перевагу більш сучасній мові Rust, тим паче що потім планую реалізувати цією мовою додатковий веб-агрегатор на базі кешованих трекером інфо-хешів у зв'язці з бібліотекою rqbit:
=> https://github.com/ikatson/rqbit

Трохи полиставши результати пошуку на GitHub, віднайшов сервер Aquatic:
=> https://github.com/greatest-ape/aquatic

Він також підтримує IPv4/IPv6, протоколи UDP, HTTP, WS і так само зберігає дані в оперативній пам'яті, не зношуючи своєю роботою носій SSD. Нижче опишу покрокову інструкцію збірки, встановлення та налаштування для мережі Yggdrasil, можливо даний матеріал буде цікавий початківцям, зокрема - для використання в класичній мережі Інтернет.

## Підготовка системи

### Створення системного користувача

Як і для інших програм Linux, що збираються з початкового коду і запускаються через systemd, я створюю окремого системного користувача з домашньою текою, для ізоляції прав доступу:
``` bash
useradd -m aquatic
```

### Встановлення системних залежностей

Програмне середовище Rust у мене розгорнуте в профілі root, куди я клоную репозиторії і засобами профілю якого проводжу збірку всіх бінарних файлів.
Якщо в системі не встановлена інфраструктура Rust (rustc, cargo та інше) тоді вам сюди:
=> https://rustup.rs

Стандартна інсталяція залежностей Rust вимагає близько 2 Гб дискового простору. Якщо ви, як і я, користуєтесь VPS - встановіть лише необхідні для роботи компілятора пакунки.

Для цього при першому запуску команди:
``` bash
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
```

* оберіть пункт "Customize installation"
* замість стандартного "Profile (which tools and data to install)" вкажіть "minimal"

Це пропустить встановлення зайвих на сервері пакунків, що зменшить розмір до ~600 Мб.

У випадку використання "minimal", для збірки також важливо до-встановити глобальні залежності:
``` bash
apt install clang libclang-dev
```
* при інсталяції rustup в режимі "default", цей крок можна пропустити.

Якщо rustup вже встановлено, також переконаймось, що використовуються актуальні версії:
``` bash
rustup update
cargo update
```

### Встановлення Aquatic

Виконуємо наступні кроки у послідовності:
``` bash
su root && cd ~
```
* логінимось (якщо досі не root) і переходимо в домашню теку
``` bash
git clone https://github.com/greatest-ape/aquatic.git && cd aquatic
```
* клонуємо вихідний код і переходимо до теки проєкту
``` bash
cargo build --release -p aquatic_udp
```
* збираємо оптимізовані бінарні пакети aquatic_udp

Таким чином, бінарники будуть доступні у теці "/root/aquatic/target/release/*". Оскільки ми будемо використовувати сервіс systemd, де відсутні змінні середовища, важливо скопіювати (або залінкувати) необхідні пакети в системне розташування, де вони матимуть відповідні права на виконання:
``` bash
install /root/aquatic/target/release/aquatic_udp /usr/local/bin/aquatic_udp
```
* мені потрібен тільки сервер UDP, якщо ви хочете підняти HTTP та WS, виконайте аналогічні кроки для інших саб-крейтів;
* тут ми використовуємо команду "install" замість "cp", оскільки вона автоматично встановлює правильні права доступу;
* якщо не плануєте оновлення, на даному етапі можна видалити не потрібні вихідні коди.

### Файл конфігурації

Сервер Aquatic можна запускати зі стандартним набором опцій, без аргументів (отримати поточні налаштування для конфігурації сервера можна командою:
``` bash
aquatic_udp -p
```

Оскільки мій сервер буде працювати в режимі Yggdrasil-only, як скопіюю цей вивід у спільний системний файл конфігурації командою:
``` bash
aquatic_udp -p > /etc/aquatic.toml
```
* приклад systemd нижче буде використовувати цей модифікований файл

Стандартна конфігурація передбачає запуск на всіх інтерфейсах і порті 3000, я ж змінюю на окрему адресу підмережі Yggdrasil і більш типовий для відкритих UDP трекерів порт 6969. Детальніше про те, як створити адресу підмережі Yggdrasil - читайте тут:
=> http://[222:a8e4:50cd:55c:788e:b0a5:4e2f:a92c]/yggdrasil:subnet_setting

``` aquatic.toml
# вимикаю IPv4, так як цей інтерфейс в Yggdrasil не обслуговується
use_ipv4 = false
# "[xxx:xxxx:xxxx:xxxx::fdb]" - актуальна адреса IPv6,
# "fdb" - це імпровізований постфікс у діапазоні A-f0-9 типу "file database"
address_ipv6 = "[xxx:xxxx:xxxx:xxxx::fdb]:6969"
```

Якщо потрібен вивід публічної веб-статистики, вказуємо також:
``` aquatic.toml
write_html_to_file = true
# шлях може бути іншим
# * у цьому випадку створіть каталог командою `mkdir /var/www/aquatic`
# * надайте відповідні права `chown aquatic:aquatic /var/www/aquatic`
html_file_path = "/var/www/aquatic/index.html"
```

В конфігурації хосту nginx додаємо наступне (не забуваємо також відкрити 80 порт):
``` /etc/nginx/default.conf
server {
    # актуальна адреса IPv6
    listen [xxx:xxxx:xxxx:xxxx::fdb]:80;
    server_name xxx:xxxx:xxxx:xxxx::fdb;

    root /var/www/aquatic;
    index index.html;

    location / {
        try_files $uri $uri/ =404;
    }
}
```

Не забуваємо застосувати зміни:
``` bash
nginx -t
systemctl reload nginx
```

Інші налаштування лишаю стандартними.

### Налаштування Firewall

В системах Debian, в режимі UDP / Yggdrasil-only (трекер прийматиме та віддаватиме виключно внутрішньомережеві адреси пірів) я використовую наступне перманентне правило ufw для iptables:
``` bash
ufw allow from 0200::/7 to xxx:xxxx:xxxx:xxxx::fdb port 6969 proto udp
```
* якщо в конфігурації вказано інший порт, використовуйте його замість 6969

Якщо у вас звичайний Інтернет трекер, можна просто додати дозвіл на всі вхідні типи підключень:
``` bash
ufw allow 6969
```

Не забуваємо по аналогії відкрити порт на веб-статистику, якщо така використовується у конфігурації вище!

### Сервіс systemd

Від root створюємо новий файл конфігурації:
``` bash
nano /etc/systemd/system/aquatic.service
```

У цьому файлі, на моєму прикладі, вказано тільки запуск сервера UDP, якщо буде потрібно, додам й інші протоколи в рамках спільного сервісу (послідовністю команд групи "exec" або додатковим скриптом). Ви можете створити для себе окремі юніти типу "aquatic_ws.service", але на мою думку це не зручно і краще адмініструвати спільною короткою командою.

Зміст файлу приблизно такий:
``` /etc/systemd/system/aquatic.service
[Unit]
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
User=aquatic
Group=aquatic
ExecStart=/usr/local/bin/aquatic_udp -c /etc/aquatic.toml
StandardOutput=file:/home/aquatic/debug.log
StandardError=file:/home/aquatic/error.log

[Install]
WantedBy=multi-user.target
```

Керування процесом відбувається наступними командами:

``` bash
systemctl daemon-reload
```
* оновлюємо конфігурацію systemd
``` bash
systemctl enable aquatic
```
* автостарт при запуску системи
``` bash
systemctl start aquatic
```
* запуск

## Тестування

Після запуску сервісу, перевіряємо наявність активного процесу:
``` bash
netstat -tulpn | grep aquatic_udp
```

На прикладі моєї конфігурації Yggdrasil, має бути щось типу такого:
``` bash
udp6 0 0 xxx:xxxx:xxxx:xxxx:6969 :::* 123456/aquatic_udp
```

Також дивимось журнали:
* /home/aquatic/debug.log
* /home/aquatic/error.log

На стороні клієнта, створюємо новий торент (в qBittorrent це "Tools" -> "Torrent Creator")
і вказуємо адресу нашого нового трекеру, після чого перевіряємо оновлення веб-статистики;
так само, можна додати трекер до наявної роздачі.

В принципі, це все, якщо комусь цікаво - мій сервер розташований тут:
```
udp://[202:68d0:f0d5:b88d:1d1a:555e:2f6b:3148]:6969
```

Веб-статистика:
=> http://[202:68d0:f0d5:b88d:1d1a:555e:2f6b:3148]:6969
=> http://tracker.ygg

Також, на разі працюю над агрегатором Aquatic для підписок на оновлення трекеру в різних форматах:
=> https://github.com/YGGverse/aquatic-crawler aquatic-crawler (Rust)

## Дивіться також

=> rust-cross-compilation-with-cross-crate.gmi Простий спосіб крос-компіляції Rust з cross