devzone.org.ua/post/rozhortannia-veb-infrastruktury-radicle-na-prykladi-overleynykh-merez.md
2026-02-13 06:36:02 +02:00

14 KiB
Raw Blame History

Розгортання Веб-інфраструктури Radicle на прикладі оверлейних мереж

У попередньому гайді серії про децентралізований Git-хостинг Radicle, було розглянуто приклад налаштування публічного сіда, для поширення коду персональних репозиторіїв в оверлейному режимі з вибірковою політикою "Selective".

Цього разу, опишу особистий досвід розгортання публічного Веб-інтерфейсу на його основі, для користувачів оверлейних IPv6 мереж Yggdrasil і Mycelium. Мотивація - зробити сідуючий сервер доступним для локальних користувачів, які бажають переглядати репозиторії "всередині" оверлейної мережі та мати можливість забирати код як з rad clone так і через шлюз HTTP звичною командою git clone.

Веб-інфраструктура Radicle ділиться на дві основні частини: сервер JSON/API (за яку відповідає пакунок radicle-httpd) і статичний асинхронний клієнт (на базі технологій HTML і JavaScript). Обидва рішення є частиною репозиторію radicle-explorer.

Отримання початкового коду

У попередньому гайді, на сервері вже було створено користувача radicle, тож спочатку залогінимось від нього:

su radicle

Оскільки на моєму сервері немає Інтернет-інтерфейсу як такого, але вже є підключений до глобальної мережі (засобами Tor over Yggdrasil) radicle-node, я буду тягнути вихідний код засобами команди rad а не git (для якого в моєму випадку знадобився б вихідний проксі). Це за одно дозволить звикнути до нової обгортки і скористатись перевагами пірингового обміну без прив'язки до конкретної мережі:

rad clone rad:z4V1sjrXqjvFdnCUbxPFqd5p4DtH5 radicle-explorer

Якщо таки збираєте клієнт без локального вузла Radicle:

git clone https://iris.radicle.xyz/z4V1sjrXqjvFdnCUbxPFqd5p4DtH5.git radicle-explorer

Сервер JSON/API (radicle-httpd)

Інструкції з розгортання також описані в офіційній документації: Radicle Seeder Guide: Running the HTTP Daemon.

Якщо коротко, то робимо наступне:

cd radicle-explorer/radicle-httpd
cargo build --release

Копіюємо отриманий бінарник target/release/radicle-httpd до /usr/local/bin на сервері і переконуємось що користувач radicle має відповідні права на його виконання:

sudo chown radicle:radicle /usr/local/bin/radicle-httpd
sudo chmod +x /usr/local/bin/radicle-httpd

Системний сервіс

Сервіс я оголосив на локальному інтерфейсі [::1] (для IPv4 - це може бути 127.0.0.1) з портом 8788 і подальшим проксуванням через Nginx з публічних IP відповідних мереж.

[Unit]
Description=Radicle HTTP Daemon
After=network.target network-online.target
Requires=network-online.target

[Service]
User=radicle
Group=radicle
ExecStart=/usr/local/bin/radicle-httpd --listen [::1]:8788
Environment=RAD_HOME=/home/radicle/.radicle RUST_BACKTRACE=1 RUST_LOG=info NO_COLOR=1
KillMode=process
Restart=always
RestartSec=1

StandardOutput=file:///home/radicle/httpd-debug.log
StandardError=file:///home/radicle/httpd-error.log

[Install]
WantedBy=multi-user.target

Додаємо сервіс до авто-запуску зі стартом системи і запускаємо сервер:

sudo systemctl enable --now radicle-httpd

Nginx

server {
	listen [202:68d0:f0d5:b88d:1d1a:555e:2f6b:3148]:8788;
	listen [505:6847:c778:61a1:5c6d:e802:d291:8191]:8788;

	# Поки не визначився
	# server_name _;

	access_log /var/log/nginx/radicle.access.log;

	location / {
		proxy_pass http://[::1]:8788;

		proxy_http_version 1.1;
		proxy_set_header   Connection        "";

		proxy_set_header   Host              $host;
		proxy_set_header   X-Forwarded-For   $proxy_add_x_forwarded_for;
		proxy_set_header   X-Forwarded-Proto $scheme;
	}
}
  • для мереж Yggdrasil і Mycelium - HTTPs звичайно не використовується, тому приклад налаштування спрощено

Застосовуємо оновлення конфігурації:

systemctl reload nginx

Фаєрвол

sudo ufw allow from 0200::/7 to 202:68d0:f0d5:b88d:1d1a:555e:2f6b:3148 port 8788 proto tcp comment 'radicle-httpd'
sudo ufw allow from 0400::/7 to 505:6847:c778:61a1:5c6d:e802:d291:8191 port 8788 proto tcp comment 'radicle-httpd'

Тестування бекенду

В рамках цього прикладу, перевірити роботу JSON/API, можна за адресами:

Якщо встановлено Alfis DNS:

По аналогії, на бекенд можна легко причепити тунелі I2P і Tor.

Клієнт (radicle-explorer)

По суті, це статичний Веб-компонент на базі HTML/JavaScript, що звертається до вказаного в його налаштуваннях сервера. Оптимізована статика збирається засобами пакетного менеджера npm, після чого отримані файли з теки build копіюються до публічного простору, наприклад Nginx: /var/www/radicle.

Налаштування підключення до бекенду

Перед тим, як збирати оптимізований білд, важливо спочатку вказати актуальні налаштування підключення до серверів JSON/API - власних або сторонніх. Робиться це у файлі config/default.json. Після збірки, ці налаштування будуть "вбудовані" в компонент build/assets/components-xxx.js і при наступних оновленнях конфігу, особисто я перезбираю клієнт видаливши попередню теку build, хоча в останніх версіях можна скопіювати до кореню статичний файл (див. коментар Nginx).

У своїй конфігурації, поки використовую два інтерфейси: Yggdrasil і Mycelium свого сіда. По аналогії, до масиву об'єктів preferredSeeds додаються й альтернативні DNS, тунелі I2P або приховані сервіси Tor.

Важливим є той факт, що поточна версія radicle-explorer ніяк не проксує через бекенд preferredSeeds і тому якщо в клієнта не встановлено роутер Mycelium, то перебуваючи на хості Yggdrasil - він не зможе з меню 0200::/7 відкрити сід 0400::/7. Більше того, там є баг, який при відсутності зв'язку з сідом буде зависати на його сесії, допоки руками не почистити Локальне сховище. Навожу приклад міксованого з'єднання, але рекомендую користуватись одним сімейством адрес для одного фронтенду.

{
  "nodes": {
    "fallbackPublicExplorer": "https://app.radicle.xyz/nodes/$host/$rid$path",
    "requiredApiVersion": "~0.18.0",
    "defaultHttpdPort": 443,
    "defaultLocalHttpdPort": 8080,
    "defaultHttpdScheme": "https"
  },
  "source": {
    "commitsPerPage": 30
  },
  "supportWebsite": "https://radicle.zulipchat.com",
  "deploymentId": null,
  "preferredSeeds": [
    {
      "hostname": "[202:68d0:f0d5:b88d:1d1a:555e:2f6b:3148]",
      "port": 8788,
      "scheme": "http"
    },
    {
      "hostname": "ygg.ua.srv",
      "port": 8788,
      "scheme": "http"
    },
    {
      "hostname": "[505:6847:c778:61a1:5c6d:e802:d291:8191]",
      "port": 8788,
      "scheme": "http"
    },
    {
      "hostname": "myc.ua.srv",
      "port": 8788,
      "scheme": "http"
    }
  ]
}

Стандартні поля секції nodes - свідомо не зміню, бо в коді клієнта є такі упороті моменти:

$: portFragment =
  baseUrl.scheme === config.nodes.defaultHttpdScheme &&
  baseUrl.port === config.nodes.defaultHttpdPort
    ? ""
    : `:${baseUrl.port}`;
  • через що може не працювати внутрішня навігація по сідам а також приклади команд типу git clone, виключаючи з URL не типовий для HTTP/80 порт (8788) якщо той використовується

Компіляція

Після завершення конфігурації, на локальній машині збираємо оптимізовану статику і для зручності передачі на сервер, запаковуємо вміст build до архіву radicle-explorer.tar.gz:

cd radicle-explorer
npm install && npm run build
tar -czvf radicle-explorer.tar.gz -C build .

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

Отриманий архів radicle.tar.gz копіюємо на сервер до якоїсь тимчасової теки і розпаковуємо вміст архіву за призначенням /var/www/radicle, оновивши за одно права для доступу служби Nginx:

sudo mkdir -p /var/www/radicle
sudo tar -xzvf /tmp/radicle-explorer.tar.gz -C /var/www/radicle
sudo rm /tmp/radicle-explorer.tar.gz
sudo chown www-data:www-data /var/www/radicle

Nginx

Тут все просто: вказуємо актуальний шлях до статики /var/www/radicle з адресацією усіх запитів на index.html:

server {
	listen [202:68d0:f0d5:b88d:1d1a:555e:2f6b:3148]:8780;
	listen [505:6847:c778:61a1:5c6d:e802:d291:8191]:8780;

	# Ще не визначився
	# server_name _;

	access_log /var/log/nginx/radicle.access.log;
	root /var/www/radicle;

	location / {
		try_files $uri $uri/ /index.html;
	}

	# При збірці radicle-explorer з репозиторію, публічна тека `build` не міститиме файлу `config.json`
	# тому я скопіював `config/default.json` до `/config.json` на сервері
	# https://app.radicle.xyz/nodes/iris.radicle.xyz/rad%3Az4V1sjrXqjvFdnCUbxPFqd5p4DtH5/tree/README.md#run-time-configuration
	#
	# location = /config.json {
	#	root /;
	# 	try_files /etc/radicle-explorer/config.json /usr/share/radicle-explorer/config.json =404;
	# }

	# Цей блок є опціональним і дозволяє публікувати `radicle-httpd` і `radicle-explorer`
	# на одному інтерфейсі одночасно (на прикладі це може спільний порт `8780`)
	# таким чином, індексна сторінка API буде заміщена користувацьким Веб-інтерфейсом
	#
	# location ~ "^/(raw|api|[a-zA-Z0-9]{28,29}(\.git)?)(/|$)" {
	# 	proxy_pass http://[::1]:8788;
	#
	# 	proxy_http_version 1.1;
	# 	proxy_set_header   Connection        "";
	#
	# 	proxy_set_header   Host              $host;
	# 	proxy_set_header   X-Forwarded-For   $proxy_add_x_forwarded_for;
	# 	proxy_set_header   X-Forwarded-Proto $scheme;
	# }
}

Застосовуємо оновлення конфігурації:

systemctl reload nginx

Фаєрвол

sudo ufw allow from 0200::/7 to 202:68d0:f0d5:b88d:1d1a:555e:2f6b:3148 port 8780 proto tcp comment 'radicle-explorer'
sudo ufw allow from 0400::/7 to 505:6847:c778:61a1:5c6d:e802:d291:8191 port 8780 proto tcp comment 'radicle-explorer'

Тестування фронтенду

В рамках цього прикладу, перевірити роботу можна за адресами:

Якщо встановлено Alfis DNS: