Opentracker - это реализация BitTorrent-трекера на языке C. Программа имеет открытый исходный код и распространяется по лицензии "beer ware". Умеет работать по TCP и UDP, умеет работать со списками доступа для торрентов по info-hash и для пользователей по адресам. Программу я пробовал собирать на машинах с процессором x86_64 и ARM. Везде программа собралась и даже заработала.
Зачем оно мне надо? Просто захотел поднять трекер для личных нужд, а потом уже начал навешивать на него всякие рюшечки.
Далее я расскажу, как поднимал кластер подобных трекеров из трёх нод, помещал перед ними сервер Nginx с балансировкой и https.
Моя система костылей и подпорок заработала со следующими исходными условиями:
- Наличие внешнего белого статического IP-адреса от провайдера;
- Наличие сертификата Let’s Encrypt.
Сборка программы.
Сборку я выполнял по инструкции с сайта, но перед компиляцией раскомментировал в файле "Makefile" следующие строки:
FEATURES+=-DWANT_V6 FEATURES+=-DWANT_SYNC_LIVE FEATURES+=-DWANT_COMPRESSION_GZIP FEATURES+=-DWANT_IP_FROM_PROXY FEATURES+=-DWANT_MODEST_FULLSCRAPES FEATURES+=-DWANT_SYSLOGS FEATURES+=-DWANT_FULLSCRAPE
Такими правками я включил поддержку протокола IPv6, работу в кластере, поддержку сжатия GZIP, поддержку syslog и scrape.
Настройка программы.
Я поместил всё необходимое для работы программы в каталог "/opt/opentracker". Туда я скопировал исполняемый файл программы "opentracker" и конфигурационный файл "opentracker.conf.sample" под именем "opentracker.conf".
В конфигурационном файле я изменил следующие параметры:
# адрес и порт для синхронизации нод livesync.cluster.listen 192.168.1.30:9696 # список нод для синхронизации # адреса всех трёх нод livesync.cluster.node_ip 192.168.1.28 livesync.cluster.node_ip 192.168.1.30 livesync.cluster.node_ip 192.168.1.17 # каталог для данных программы # пустой, но должен существовать tracker.rootdir /opt/opentracker/data # учётная запись для понижения прав tracker.user nobody # адрес вышестоящего http-сервера access.proxy 127.0.0.1
Последний параметр нужен, чтобы программа получала адрес пира не из свойств соединения, а из заголовка запроса "X-Forwarded-For". В документации об этом особо не написано, а параметр нашёл поиском по исходным текстам программы.
Установка и запуск программы.
После помещения всех необходимых файлов надо установить владельца каталога "data" в значение из параметра "tracker.user".
Для запуска через systemd я написал такой юнит:
#/opt/opentracker/opentracker.service [Unit] Description=Opentracker Wants=network-online.target After=network.target network-online.target [Service] ExecStart=/opt/opentracker/opentracker -f /opt/opentracker/opentracker.conf ExecReload=/bin/kill -s HUP $MAINPID Restart=on-abort [Install] WantedBy=multi-user.target
Установка и запуск юнита выполняется следующей командой:
sudo systemctl enable --now /opt/opentracker/opentracker.service
Программа должна появиться в списке процессов.
Подобную процедуру надо провести для всех трёх нод, заменив адрес в параметре "livesync.cluster.listen".
Настройка Nginx.
Nginx я выбрал из-за богатых возможностей настройки и хорошей документации.
Из-за того, что у меня трекер и клиент расположены в одной сети, а запросы к трекеру идёт через роутер, то в списке пиров вместо внешнего адреса я получаю внутренний адрес роутера, то есть "192.168.1.1". В таких условиях пользы от трекера примерно никакой. Чтобы это как-то исправить, я добавил в конфигурационный файл хоста некоторые костыли.
Сам файл выглядит так:
#/etc/nginx/sites-enabled/opentracker.conf upstream opentracker { server 127.0.0.1:6969; server 192.168.1.17:6969; server 192.168.1.28:6969; } server { listen 9999 ssl http2; server_name bt.example.ru; ssl_certificate /etc/letsencrypt/live/example.ru/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/example.ru/privkey.pem; access_log /var/log/nginx/access.opentracker.log; location / { set $xff $proxy_add_x_forwarded_for; set $xrip $remote_addr; if ($remote_addr = "192.168.1.1") { set $xff "внешний_IP-адрес"; set $xrip "внешний_IP-адрес"; } proxy_set_header Host $http_host; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-For $xff; proxy_set_header X-Real-IP $xrip; proxy_redirect off; proxy_read_timeout 120; proxy_connect_timeout 10; proxy_pass http://opentracker; } }
В секции "upstream" перечислены адреса всех нод. Сервер будет передавать им запросы по очереди, а синхронизироваться между собой ноды будут сами.
В секции "server" прописан порт и имя сервера, включена поддержка SSL и HTTP 2.0. Для SSL указаны пути к файлам ключа и сертификата. Указан путь к log-файлу конкретно для запросов этого хоста.
В секции "location" прописано условие изменения заголовков "X-Forwarded-For" и "X-Real-IP" в случае поступления запроса из локальной сети за роутером. Тут надо заменить текст "внешний_IP-адрес" на настоящий белый статический IP-адрес, который выдал провайдер. Я не уверен, что подойдёт доменное имя. Если адрес роутера другой, то его тоже надо исправить.
Решения для динамического белого IP-адреса я не придумал. Если у кого-то такое решение есть, то прошу им поделиться.
Для добавления в раздачи надо использовать адрес трекера "https://bt.example.ru:9999/announce". Имя сервера надо заменить на своё и указать порт, который проброшен на роутере.
Проверка решения.
Для проверки ответов трекера я добавил трекер в один из торрентов и подсмотрел строку запроса в логе сервера Nginx. Для запроса я использовал программу "curl", а ответ разбирал программой "hexdump" с подсмотренным в интернете шаблоном вывода.
curl --compressed 'https://bt.example.ru:9999/announce?info_hash=%6b%36%1a%4e%0a%24%c2%9c%85%e7%a7%a3%1f%5f%b2%7d%3c%e9%b1%d4&peer_id=-qB4400-)j!KFE-2Bfp0&port=65461&uploaded=1887594623&downloaded=0&left=0&corrupt=0&key=59E7D934&numwant=200&compact=1&no_peer_id=1&supportcrypto=1&redundant=0' --output - | hexdump -e'"%07.8_ad " 8/1 "%03d " " |"' -e'8/1 "%_p" "|\n"' 00000000 100 056 058 099 111 109 112 108 |d8:compl| 00000008 101 116 101 105 051 101 049 048 |etei3e10| 00000016 058 100 111 119 110 108 111 097 |:downloa| 00000024 100 101 100 105 049 101 049 048 |dedi1e10| 00000032 058 105 110 099 111 109 112 108 |:incompl| 00000040 101 116 101 105 048 101 056 058 |etei0e8:| 00000048 105 110 116 101 114 118 097 108 |interval| 00000056 105 049 054 053 048 101 049 050 |i1650e12| 00000064 058 109 105 110 032 105 110 116 |:min int| 00000072 101 114 118 097 108 105 056 050 |ervali82| 00000080 053 101 054 058 112 101 101 114 |5e6:peer| 00000088 115 054 053 052 058 000 000 000 |s654:...| ... skipped ...
После последней строки идёт список адресов раздающих. Среди десятичного представления байтов должен быть внешний адрес, а не "127.000.000.001" или адрес из локальной сети.
Для более широкого вывода можно расширить шаблон до 16 байт на строку:
hexdump -e'"%07.8_ad " 8/1 "%03d " " " 8/1 "%03d " " |"' -e'16/1 "%_p" "|\n"'
Для проверки заголовков я просто останавливал ноду и запускал вместо неё программу "netcat" в режиме сервера с прослушиванием того же порта:
nc -l -p 6969
Запрос в этом случае будет зависать, но заголовки, которые передаёт Nginx в сторону OpenTracker, будут видны полностью.
Для теста я пробовал качать торрент по magnet-ссылке из другой сети с выключенным поиском пиров по DHT. Пир из локальной сети подхватывался по внешнему адресу, а закачка начиналась сразу после получения торрента от пира.