Невдовзі, після своїх роздумів про p2p, вирішив спробувати підняти власний експериментальний інстанс Fediverse. При чому, зробити це засобами оверлейної мережі Yggdrasil, оскільки я не планую купувати для цієї іграшки виділений IP чи VPS, натомість буду хоститись з модему, одноплатника або взагалі з ПК, коли буваю онлайн, з динамічною адресою за NAT.
Пишу цю нотатку в першу чергу - для себе, а також, вона може бути корисною для тих, хто як і я тільки починає свої експерименти у сфері адміністрування власного вузла Fediverse і цікавиться альтернативними мережами, в контексті Linux.
Що таке Snac
Snac - це мінімалістична, JS-less, написана мовою C альтернатива серверу Mastodon, яка також не потребує інсталяції PostgreSQL, натомість зберігає усі дані профілю у файлах JSON. Нещодавно, до цього серверу було додано підтримку IPv6, а отже - він буде працювати й з діапазоном Yggdrasil 0200::/7
Оскільки Yggdrasil дозволяє безкоштовно генерувати не обмежену кількість статичних IP (на базі приватного ключа Ed25519), тут немає звичної потреби в DNS. Хоча, можна опціонально прикрутити Alfis, але особисто я цим ділом не користуюсь (зокрема, й через досі не вирішену проблему #364) тому також не хочу нав'язувати його в рамках протоколу ActivityPub - буде просто формат username@IPv6
, який мені не потрібно а ні оновлювати, а ні майнити потім.
Встановлення
-
Точний перелік пакетів для Debian я не знаю, оскільки моя система не нова і вже має встановлені раніше пакунки. Як вказано в README, я тільки встановив
libssl-dev
іlibcurl4-openssl-dev
(для Fedora має бути приблизно те само з постфіксом*-devel
) -
Далі, створюємо окремого системного юзера, щоб ізолюватись від потенційних вразливостей:
useradd -m snac
- Змінюємо для зручності середовище на
bash
у файлі/etc/passwd
- Логінимось через
su snac
і переходимо в домашню директорію цього юзера:cd
- Завантажуємо останній вихідний код:
git clone https://codeberg.org/grunfink/snac2.git
- Заходимо в робочу директорію
cd snac2
- Компілюємо
make && sudo make install
і встановлюємо з відповідними правами - Ініціалізуємо серверне сховище:
snac init /home/snac/storage
- І додамо до нього нашого першого юзера
snac adduser /home/snac/storage
- Далі продовжуємо від
root
виконавши командуexit
Налаштування
Я вже маю встановлений і налаштований вузол Yggdrasil, якщо комусь цікавий процес встановлення, скористайтесь попередньою публікацією або офіційною документацією.
Адреса підмережі Yggdrasil
Можна пропустити цей крок і використовувати основну адресу 2*
, якщо порти 80
чи 8001
не зайняті. Але зауважте, що в рамках API протоколу ActivityPub, сервер Snac надаватиме вашу адресу хосту іншим нодам, а ті - її кешуватимуть, як частину ID і оскільки локально адреса хосту зберігається по файлам, а не в БД, потім буде важко її замінити. Тому краще виділити окрему, особливо - якщо це продакшн:
yggdrasilctl getself
- дізнаємось свій айпішник, зокрема вивідIPv6 subnet
ifconfig lo inet6 add IP
- замість IP вказуємо довільну адресу для отриманого діапазону, наприклад3xx:xxxx:xxxx:xxxx::fed/64
, деfed
- така собі гра слів в рамках "словника" IPv6 (0-9A-F).- варто зауважити, що дані маршрутизації
ifconfig
не зберігаються після ребуту системи, для цього потрібно додати відповідний запис (команду з пункту 2), наприклад до/etc/netplan/01-ygglo.yaml
,/etc/network/interfaces
, або безпосередньо до systemdyggdrasil.service
(секціяExecStartPost=
) - залежно від операційної системи.
- варто зауважити, що дані маршрутизації
Проксі Nginx
На моєму сервері вже встановлено веб-сервер Nginx, який займає порт 80
, я поки не хочу нічого змінювати, а також не хочу мати публічні адреси Snac з його стандартним портом 8001
. Тому, оскільки вже маю виділену адресу підмережі, просто запроксую API на 80
порт через новий віртуальний хост, частково використавши оригінальний приклад конфігурації:
# /etc/nginx/sites-available/default
server {
listen [3xx:xxxx:xxxx:xxxx::fed]:80;
server_name 3xx:xxxx:xxxx:xxxx::fed;
location @proxy {
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_redirect off;
proxy_connect_timeout 90;
proxy_send_timeout 90;
proxy_read_timeout 90;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Proxy "";
proxy_pass_header Server;
proxy_buffering on;
tcp_nodelay on;
proxy_pass http://[3xx:xxxx:xxxx:xxxx::fed]:8001;
proxy_set_header Host $http_host;
}
location /.well-known/webfinger {
try_files $uri @proxy;
}
location /.well-known/nodeinfo {
try_files $uri @proxy;
}
location / {
try_files $uri @proxy;
}
location /fedi/ {
try_files $uri @proxy;
}
}
systemctl reload nginx
- застосовуємо зміни- можливо, захочете створити окремий конфігураційний файл для Nginx, замість
default
- в мене він один на всі хости. - опціонально, засобами Nginx, можна закрити окремі локації по IP
Як бачите, на прикладі вище не вказано порт 443
, а також немає сертифікатів SSL. Це зроблено спеціально, оскільки Yggdrasil вже має захищений канал, і я не хочу створювати тут зайвий шар.
Оскільки клієнтські підключення Yggdasil також мають статичну адресу, я вирішив обмежити доступ до адміністративного API (адмінка усіх акаунтів + oauth
) по IP. Наскільки це ефективно і чи не забув про інші адреси - я не знаю, але додам свій приклад регулярного виразу для location
:
location ~ /([^\/]+/admin|oauth) {
allow ADMIN_IP;
deny all;
try_files $uri @proxy;
}
Конфігурація Snac
Відредагуємо раніше згенерований командою snac init
файл /home/snac/storage/server.json
:
{
"host": "[3xx:xxxx:xxxx:xxxx::fed]",
"prefix": "",
"address": "3xx:xxxx:xxxx:xxxx::fed",
"port": 8001,
"layout": 2.7,
"dbglevel": 0,
"queue_retry_minutes": 2,
"queue_retry_max": 10,
"queue_timeout": 6,
"queue_timeout_2": 8,
"cssurls": [
""
],
"def_timeline_entries": 50,
"max_timeline_entries": 50,
"timeline_purge_days": 120,
"local_purge_days": 0,
"min_account_age": 0,
"admin_email": "",
"admin_account": "",
"title": "",
"short_description": "",
"short_description_raw": false,
"protocol": "http",
"fastcgi": false
}
- звертаю увагу, що протокол у моєму прикладі змінено на
http
Доступи iptables
Конфігурація у прикладах не передбачає доступу до ноди з мережі Інтернет, тому я відкрив порт тільки для Yggdrasil, щоб інші вузли в рамках цієї мережі могли взаємодіяти між собою на івентах типу фоловінгу (обидва вузли мають бути онлайн для транзакції):
ufw allow from 0200::/7 to any port 80
- якщо не користуєтесь Nginx, або сервер має стандартний чи інший порт, просто замість
80
вкажіть актуальний, наприклад8001
- якщо обмежуєте трафік по діапазону
0200::/7
, також зверніть увагу на зауваження щодо приватного режиму, про який описано нижче
Налаштування systemd
Є готовий офіційний приклад конфігурації, але я його трохи доповнив:
# /etc/systemd/system/snac.service
[Unit]
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=snac
Group=snac
ExecStart=/usr/local/bin/snac httpd /home/snac/storage
StandardOutput=file:/home/snac/debug.log
StandardError=file:/home/snac/error.log
[Install]
WantedBy=multi-user.target
systemctl daemon-reload
- оновлюємо конфігураціюsystemd
systemctl enable snac
- автостарт при запуску системиsystemctl start snac
- запускsystemctl status snac
- перевіряємо статус
Резервне копіювання
Оскільки база даних Snac зберігається у файловому форматі, досить просто бекапити профіль по лише одній локації.
Я роблю це засобами rsync
для різних часових інтервалів наступною командою crontab -e
:
@daily /usr/bin/rsync -av --delete /home/snac/storage /path/to/snac/daily
@weekly /usr/bin/rsync -av --delete /home/snac/storage /path/to/snac/weekly
@monthly /usr/bin/rsync -av --delete /home/snac/storage /path/to/snac/monthly
Користування
Після запуску Snac командою snac httpd /home/snac/storage
або через сервіс systemd
, можна спробувати відкрити у браузері http://[3xx:xxxx:xxxx:xxxx::fed]
.
Тестування взаємодії (API)
Щоб перевірити взаємодію з іншим вузлом Yggdrasil, повторюємо для нього ті само дії і робимо тестовий фоловінг чи переписку між користувачами через Web UI або підключений зовнішній клієнтський застосунок.
Тюнінг браузеру
Якщо вперше користуєтесь сайтами Yggdrasil у Firefox, можливо знадобиться оптимізувати обробку "сирих" IPv6 адрес в about:config
:
browser.fixup.fallback-to-https
:false
- вимкнути редіректhttp
->https
browser.fixup.alternate.enabled
:false
- викнути автоматичну обробку префіксуwww
Теми Web UI
В README є перелік посилань на CSS теми, за допомогою яких можна кастомізувати веб-інтерфейс Snac на власне вподобання.
Спочатку я не зрозумів, як підключати нові теми, і додав посилання на умовний файл /theme.css
до /home/snac/storage/server.json
, а також створив на нього аліас локального шляху в Nginx (щоб задовольнити браузерну політику CORS):
location /theme.css {
alias /var/www/snac/theme.css;
}
- цей приклад я лишаю на випадок, якщо ви захочете підключити додаткові
cssurls
Але згодом виявилось, що при створенні інстансу, генерується стандартний файл у теці /home/snac/storage/style.css
який буде конфліктувати з новою темою (адже він підключатиметься окремо від масиву конфігурації cssurls
).
Таким чином, потрібно просто переписати вміст стандартного файлу /home/snac/storage/style.css
обраною темою, а масив cssurls
потрібен тільки для тюнінгу поточної теми, без правки її оригіналу. Щоб повернутись до оригінальної теми - достатньо видалити цей файл, після чого згенерується стандартний файл Snac.
Специфіка клієнтських застосунків
Особисто, я встиг перевірити тільки Tuba. Як виявилось, даний клієнт має захардкожену обробку схеми HTTPS, тому якщо користуєтесь цим застосунком, доведеться налаштувати окремий інтерфейс Nginx на порті 443
з використанням сертифікату, хоч у випадку з Yggdrasil - це зайва "капуста" і мабуть поки що лишусь на веб-інтерфейсі або зроблю і викладу потім патч.
UPD 1. розробник виявився супер-оперативним і вже створив гілку з патчем (Flatpak в Артефактах), єдине що - тільки поки не "завезли" валідацію IPv6 у вікно авторизації, тому я тимчасово користуюсь аліасом в /etc/hosts
і вказую у якості URL авторизації http://alias
. Можливо, у наступних випусках додатка це вже буде не актуально.
UPD 2. Наразі, гілка об'єднана з main
, тому замість аліасів для IPv6, можна просто додати при запуску TUBA_SKIP_STRICT_VALIDATION=1
, наприклад:
TUBA_SKIP_STRICT_VALIDATION=1 'builddir/dev.geopjr.Tuba'
UPD 3. Особисто я користуюсь окремою гілкою, де ця нубська валідація HTTP випиляна, і жодних додаткових флагів для запуску не потрібно:
Для збірки з форку:
git clone https://github.com/YGGverse/Tuba.git
git checkout multiprotocol-address-support
make && make install
- або для Flatpak:
flatpak-builder --force-clean build\
--install-deps-from=flathub\
--install\
--repo=repo\
--user\
build-aux/dev.geopjr.Tuba.Devel.json
Також, в мене є ще одна, окрема гілка, де я форсовано застосовую українську локаль для постів, адже сервер Snac має певний недопил по синхронізації даного API.
Скачати All-in-One збірку можна тут, виконавши для встановлення кроки вище (з git checkout ps
).
Моніторинг трафіку
Оскільки сервер Snac не передбачає користування JS інтерфейсом, а поточна конфігурація використовує Nginx, можу по ходу справи також порадити goaccess - CLI утиліту для зручного моніторингу статистики користувацького трафіку, якщо такий буде:
goaccess /var/log/nginx/access.log
Приватний режим
Yggdrasil дозволяє маскувати реальний IP, якщо ви користуєтесь власним вихідним вузлом. Звісно, таку можливість не варто розглядати в контексті анонімізації окремо без додаткових шарів, оскільки використання протоколу Yggdrasil без наприклад таких проксі, як Shadowsocks - легко виявляється.
Ця тема виходить за рамки матеріалу, але зверну увагу на деякі аспекти, якщо ви плануєте користуватись збіркою Snac + Yggdrasil в режимі "інкогніто". Протокол ActivityPub передбачає "спілкування" між серверами для обміну івентами. Тобто потенційний фоловер може відправити запит підписки на на дозволений у фаєрвол інтерфейс 0200::/7
, але вказати в заголовках події ActivityPub - зворотній DNS на вузол в мережі Інтернет. Таким чином, ваша система здійснить транзакцію з білого IP через системний резольвер або без нього, використовуючи локальний Curl API від Snac.
Потенційних сценаріїв витоку можна придумати багато. Я переглянув вихідний код Snac, та не знайшов у ньому жодних фільтрів взаємодії на вихідні підключення. Тому, як і для іншого не спеціалізованого софту, для цієї мети бажано використовувати ізоляцію роутера з контейнера Docker, LXC або віртуалізуватись засобами QEMU.
При використанні клієнтського API, окремого аудиту потребуватиме обробка віддаленого вмісту постів, аватарів та іншого. У цьому напрямку, є перші кроки, зокрема по частині Web UI (PR#394, гілка), але я не впевнений, що буду пиляти це довгий час, адже з цих причин, давно користуюсь протоколом Gemini.
Можна, в принципі, додати правило на "останній рубіж" iptables
, наприклад заблокувати вихідні пакети в Інтернет:
ufw default deny outgoing
Якщо користуєтесь Yggdrasil в оверлейному режимі (тобто через публічний пір), важливо додати його до білого списку:
ufw allow out to PUBLIC_PEER_IP
- якщо вузлів декілька, додаємо їх послідовно
- перевірити поточні правила
ufw
можна командоюufw status verbose
- можливо, для тесту конекту варто перезапустити сервіс
systemctl restart yggdrasil
- також, не забудьте про системний DNS резольвер та інші служби, що залежать від вихідних з'єднань!
На останок, дозволяємо локальні запити для взаємодії між вузлами:
ufw allow out to 0200::/7 from 0200::/7
Багато-мережевий режим
Можливо, згодом (коли розберусь) окремо опишу, як запустити інстанс у різних мережах одночасно, наприклад Інтернет + Yggdrasil, але наскільки бачу по коду Snac, його файлова реалізація сховища дозволяє працювати тільки в рамках однієї мережі / хосту.
Думаю, тут можна буде погратись з проксуванням з авто-заміною, організувати реплікацію або використанням "білого" DNS і записів A
/AAAA
відповідно до типу з'єднання клієнтського резольвера. Так чи інакше, це - вже зовсім інша історія!
Посилання
Інших вузлів я поки не зустрічав, тому підписуйтесь на мій - для тестів і спілкування:
Можливо, колись сформується нове локальне сузір'я :)
Коментарі (1)