Облегчённое зеркало этого сайта в IPFS по ENS-имени gluek.eth. Это ещё одно зеркало рядом с I2P, Tor, Yggdrasil и Reticulum, только адрес привязан к блокчейну и не зависит от DNS.
Открыть можно так:
- через шлюз gluek.eth.limo;
- в браузере с поддержкой ENS (Brave, Opera):
gluek.eth; - через NextDNS с включённым Web3:
gluek.eth/(со слэшем в конце).
Как это устроено
Цепочка от имени до файлов:
- В ENS у
gluek.ethзаписан contenthashipns://k51qzi5uqu5dgluek8dpf0or3fcnutet0cpztljxck6cm36zvhvwqg4se7ly7y. - Это адрес IPNS-ключа: запись под ним указывает на актуальный CID каталога с сайтом. Пока ключ тот же, ENS-запись менять не нужно, а значит, не нужно платить газ при каждом обновлении.
- CID указывает на папку в IPFS. Её раздаёт мой узел и два сервиса пиннинга.
Ещё есть запасной вариант: TXT-запись _dnslink.gluek.info с dnslink=/ipfs/<CID>, её скрипт тоже обновляет при каждой публикации.
Почему IPNS-ключ, а не DNSLink в ENS
Сначала я хотел записать в contenthash ipns://gluek.info и обновлять только DNS (бесплатно и мгновенно). Не вышло: приложение ENS принимает после ipns:// только ключ в base58 или base36 и на букве l в gluek.info отвечает ошибкой Unknown letter "l". Поэтому пришлось взять настоящий IPNS-ключ.
Красивый адрес ключа
Адрес вида k51qzi5uqu5d… у всех ed25519-ключей одинаковый в начале, а дальше случайный. Я перебрал ключи на Mac на всех ядрах, пока после фиксированной части не появилось gluek. Подбор занял 72 секунды (около 60 миллионов проб, скрипт на Python с библиотекой cryptography). Потом ключ импортировал в Kubo через PKCS8 PEM и сделал резервную копию.
Облегчённая версия
Весь сайт (около 4700 файлов) в бесплатные лимиты пин-сервисов не влезает, поэтому в IPFS публикуется урезанная версия: главная, раздел проектов (все проекты) и 10 последних постов, всего около 64 файлов и 1,4 МБ. Ссылки на всё остальное ведут на gluek.info, а пояснение про это показывается подсказкой на надписи «Showing 10 of …» и на кнопке «Next» в блоге.
Для этого в CI после обычной сборки зеркала запускается скрипт prune-mirror.mjs: он оставляет нужные страницы и всё, что им нужно (CSS, шрифты, картинки), а остальные внутренние ссылки переписывает на оригинальный сайт.
Стек
- Узел: Kubo в Docker Compose, профиль
lowpower, лимит 512 МБ памяти. На деле занимает около 110 МБ и 3% одного ядра. - Настройки: режим DHT-клиента, 20–40 соединений, mDNS и UPnP выключены, в DHT анонсируется только корневой CID. API слушает только localhost, наружу открыт один порт для swarm (4001 tcp и udp).
- Сборка: те же Forgejo Actions, что и для остальных зеркал. Скрипт
build-mirror.shделает относительные ссылки и подставляет имя зеркала в шапку,prune-mirror.mjsурезает версию. - Публикация: CI только кладёт собранный каталог в папку на сервере и обновляет файл-маркер. Следит за ним systemd path-юнит, который запускает скрипт публикации на хосте. Так токены не попадают в CI.
- Скрипт публикации: добавляет каталог в IPFS (CIDv1), хранит три последних CID, публикует IPNS-запись, обновляет DNSLink в Cloudflare через API (токен только на DNS одной зоны) и пинит версию во внешние сервисы.
Сервисы пиннинга
Чтобы зеркало жило и когда мой сервер лежит, версию дополнительно закрепляю на внешних сервисах через стандартный Pinning Service API (ipfs pin remote).
- Pinata: работает на бесплатном плане. Ключу нужно отметить права в блоке Pinning Services (иначе ошибка
NO_SCOPES_FOUND). Через API Pinata не показывает такие пины в списке и не даёт их снять, поэтому старые версии чищу вручную. Каталог считается одним файлом. - Octopin: пин проходит, а старые версии скрипт снимает сам. Сейчас у меня пробный платный план, как поведёт себя пин после перехода на бесплатный (1 ГБ и 500 файлов), проверю позже. ❓
- Filebase: пробовал, не подошёл. Pinning Service API там только на платном плане (
The Pinning Service API requires a paid account).
ENS: апгрейд до v2 и продление
Чтобы редактировать записи, имя пришлось обновить до ENSv2: пока этого не сделано, кнопка Edit Profile в приложении ENS неактивна («Upgrade name to edit profile»). Апгрейд состоит из двух подтверждений в кошельке: разрешение для контракта миграции и сам перенос имени, комиссия вышла около 0,0001 ETH. Записи профиля при этом сохраняются. В награду приложение предлагает заминтить памятный NFT «ENSv2 commemorative NFT», газ на него обошёлся меньше чем в 30 центов. Contenthash записывается отдельной транзакцией с обычным газом.
Продление: имя gluek.eth зарегистрировано 16 июня 2022. Я продлил его сразу на 6 лет за около 27 долларов, теперь оно оплачено до 18 августа 2033 (даты со страницы имени). Продлевать можно там же кнопкой Renew Name.
Что не решено
- Шлюз
eth.limoкэширует адрес, поэтому свежая версия появляется через несколько минут. - Если Octopin после пробного плана откажется принимать пины, останутся Pinata и мой узел.
- Резервную копию IPNS-ключа нужно держать отдельно от сервера: без неё при потере данных узла придётся менять contenthash в ENS.
Исходный код
Скрипты сборки лежат в репозитории сайта: git.gluek.info/gluek/gluek.info (scripts/build-mirror.sh, scripts/prune-mirror.mjs, шаг IPFS в .forgejo/workflows/deploy.yml).