gemlog/public/uk/rust-crates-mirroring-with-kellnr.gmi
2026-02-25 02:02:16 +02:00

208 lines
No EOL
11 KiB
Text
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Організація локального дзеркала залежностей Cargo з Kellnr
Давно задумуюсь про організацію локального дзеркала залежностей crates.io, щоб не ходити за ними в Інтернет. При чому, я не маю достатньо простору для хостингу повної копії репозиторію, утім готовий ділитися тими крейтами, якими користуюся сам.
Трішки прозондувавши тему, віднайшов проєкт Kellnr:
=> https://kellnr.io
Це рішення позиціонується як Self Hosted Solution для хостингу крейтів, та головне - має фічу вбудованого кешуючого проксі, що власне під мої задачі підходить.
Дане рішення постачається з Веб-інтерфейсом для адміністрування: зокрема, керування правами доступу.
=> rust-crates-mirroring-with-kellnr/index-page.png Головна сторінка каталогу (скріншот)
Сторінка пошуку містить відповідну перемичку фільтрації:
=> rust-crates-mirroring-with-kellnr/proxy-filter.png Фільтрація кешованих пакунків в Kellnr (скріншот)
Отже, має бути зручно, особливо для візуалізації результатів CLI-експериментів. Нижче занотую процес встановлення і налаштування публічної ноди (бо варіант з Docker мені не підходить як і автоматичне встановлення скриптом `.sh` - якщо пускатиму в контейнері, то робитиму це руками в LXC)
## Встановлення
``` bash
git clone https://github.com/kellnr/kellnr.git
cd kellnr
```
Якщо планується компіляція кореневого `Cargo.toml` то потрібно спочатку зібрати компонент `ui`, інакше буде помилка на етапі `crates/embedded-resources`:
``` bash
cd ui
npm install
npm run build
```
На цьому етапі, важливо зкопіювати результат білду до теки `crates/embedded-resources/static`, вміст якої статично додається до бінарного пакету `kellnr`:
``` bash
cp -r ui/dist/. crates/embedded-resources/static/
```
Тепер збираємо корінь .rs:
``` bash
cd ..
cargo build --release
```
## Запуск
Перш, як почепити налаштований демон на systemd, службу можна запустити на локалхост:
``` bash
target/release/kellnr start --registry-data-dir /path/to/kellnr \
--proxy-enabled true --local-ip 127.0.0.1 -l debug
```
Після запуску, зайшов до адмінки, вказавши логін `admin` і пароль `admin`:
=> http://127.0.0.1:8000/login?redirect=settings
* на віддаленому сервері потрібно цей пароль змінити (в моїй версії була помилка не співпадіння - проігноруйте її, бо пароль насправді змінюється)
База даних тут стандартно SQLite, вона буде розташована за вказаним шляхом `/path/to/kellnr`.
## Підключення клієнта
Щоб почати наповнення індексу запланованим мною способом (тобто через кешування проксі) додаю наступні рядки до клієнтського файлу `~/.cargo/config.toml`:
``` ~/.cargo/config.toml
# Оголошуємо параметри підключення до сервера
[registries.kellnr]
index = "sparse+http://127.0.0.1:8000/api/v1/crates/"
# Вказуємо Cargo замінити стандартне джерело crates.io на Kellnr
[source.crates-io]
replace-with = "kellnr"
```
Тепер, якщо відкрити будь який проєкт Rust і виконати в ньому оновлення індексу, то отримаємо наступне:
``` bash
$ cargo update
Updating `kellnr` index
error: no matching package named `libadwaita` found
```
Ця помилка відбувається тому, що ми "залінкувались" на статичне сховище, яке наразі порожнє. Тому в даному випадку, повертаємось до `~/.cargo/config.toml` і змінюємо `index` на URL з суфіксом `cratesio`:
``` bash
index = "sparse+http://127.0.0.1:8000/api/v1/cratesio/"
```
Повторюємо оновлення і бачимо, що залежності почали відбудовуватись, а кеш - наповнюватись:
=> rust-crates-mirroring-with-kellnr/proxy-index-update.png Оновлення кешованого індексу проксі на головній сторінці Kellnr (скріншот)
Інші способи глобального і локального оголошення джерела пакунків описані в документації, зупинятись окремо на кожному не будемо:
=> https://kellnr.io/documentation#configure-cargo
## Спільний сервер
За схожою логікою, можна розгорнути суспільний сервіс, замінивши хост з `127.0.0.1` на `0.0.0.0` або `::`.
Такий сервіс буде зручно запускати від окремого користувача `kellnr` через systemd:
``` bash
useradd -mr kellnr
```
* в домашній теці - будуть зберігатись журнали і власне дані сервера
Системний сервіс у мене виглядає наступним чином:
``` /etc/systemd/system/kellnr.service
[Unit]
After=network.target
Wants=network.target
[Service]
Type=simple
User=kellnr
Group=kellnr
ExecStart=/usr/local/bin/kellnr start --registry-data-dir /home/kellnr \
--proxy-enabled true \
--local-ip :: \
--local-port 8180 \
-l warn
Environment="NO_COLOR=1"
StandardOutput=file:///home/kellnr/debug.log
StandardError=file:///home/kellnr/error.log
[Install]
WantedBy=multi-user.target
```
* для Tor і I2P достатньо лише перекинути на будь-який IP "прихований сервіс" або "тунель"
* теоретично, можна оголоситись на `::1` і перекинути проксі Nginx, але не знаю чи це працюватиме в контексті `sparse`
Після цього відкривається порт:
``` bash
ufw allow from 0200::/7 to 202:68d0:f0d5:b88d:1d1a:555e:2f6b:3148 port 8180 proto tcp
ufw allow from 0400::/7 to 505:6847:c778:61a1:5c6d:e802:d291:8191 port 8180 proto tcp
```
* у прикладі використовуються дозволи для мереж Yggdrasil і Mycelium
Керування сервісом відбувається за класикою:
* `systemctl restart kellnr` - (пере) запуск
* `systemctl enable kellnr` - авто-старт з системою
* `systemctl status kellnr` - перевірка статусу
---
Варто враховувати, що простір може швидко заповнитись, якщо проксі-сервер активно використовується.
Стосовно перманентного хостингу проєктів - як правило, використовуються облікові записи і згенеровані для них токени, утім це вже інша тема.
### Налаштування вихідного проксі
На моєму сервері немає Інтернет-інтерфейсу, тому я не можу забрати пакунки з crates.io напряму. Схоже, що Kellnr також поки не підтримує таку функціональність, тому я створив відповідний тікет #1096 і згодом знайшов тимчасове рішення у зв'язці з Nginx - засобами якого я "підставляю" потрібні заголовки згідно до URI:
``` /etc/nginx/sites-available/default
server {
listen [::1]:8200;
access_log /var/log/nginx/kellnr.outproxy.access.log;
location / {
proxy_pass http://[::1]:8118;
proxy_set_header X-Forwarded-Proto "https";
proxy_set_header Host "index.crates.io";
}
location /crates {
proxy_pass http://[::1]:8118;
proxy_set_header X-Forwarded-Proto "https";
proxy_set_header Host "static.crates.io";
}
}
```
* `[::1]:8118` - це будь-який локальний проксі (типу privoxy або gost) який вміє обробляти HTTP
* теоретично, можна пускати трафік через Tor, без проксі-посередника, але в моїй редакції Arti підтримується тільки SOCKS, а той - не підтримується Nginx
Відповідно до нашого прикладу Nginx, при запуску сервера Kellnr, потрібно додати два аргументи:
``` bash
kellnr start .. \
--proxy-index=http://[::1]:8200/ \
--proxy-url=http://[::1]:8200/crates/
```
* тут я також пробував різні аналоги proxychains і "магічні" URL типу `http://[::1]:8118/index.crates.io/` - але цей фокус не пройшов, тому ось такий костиль з Nginx, який працює.
## Зауваження щодо безпеки
Хоча в Cargo передбачається декілька рівнів перевірки цілісності пакетів, буде не зайвим переконатись в наявності оригінального файлу `Cargo.lock` для вашого проєкту, що містить хеші залежностей. Ці хеш-суми стандартно не доступні в реєстрах crates.io, утім вони звичайно зберігаються в репозиторіях Git.
При використанні будь яких проксі, рекомендую збиратись з використанням аргументу `--locked`:
``` bash
cargo build --locked
```
## Посилання
Наш експериментальний вузол в мережах Yggdrasil і Mycelium, побачимо що з того вийде:
* `http://[202:68d0:f0d5:b88d:1d1a:555e:2f6b:3148]:8180` | http://ygg.ua.srv:8180
* `http://[505:6847:c778:61a1:5c6d:e802:d291:8191]:8180` | http://myc.ua.srv:8180