Размещение сайтов в распределённой файловой системе IPFS

ipfs децентрализация распределённые приложения

Логотип IPFS.
Логотип IPFS.

В статье “Децентрализованные сервисы против распределённых” в качестве примера распределённой системы мы приводили IPFS (InterPlanerary File System). Пришла пора рассказать о ней подробнее, поскольку это одна из наиболее перспективных распределённых технологий.

Что такое IPFS?

IPFS - это глобальное хранилище неизменяемой информации. Работает как временный кэш, но также возможно использование специальных сервисов (платных или волонтёрских), гарантирующих сохранность информации.

Какие проблемы решает IPFS?

IPFS должен заменить некоторые функции HTTP (и HTTPS) из-за проблем этого протокола:

  • HTTP загружает файл с одного сервера вместо того, чтобы получать его части из множества источников одновременно. Это увеличивает нагрузку на этот сервер и расходует его сетевой трафик. IPFS позволяет сократить эти расходы.
  • HTTP требует, чтобы сервер, с которого происходит загрузка файла, присутствовал в этот момент по определённому в ссылке адресу. Это приводит к тому, что среднее время жизни веб-страницы в интернете составляет 100 дней. IPFS выполняет функцию веб-архива, позволяя сохранять полезную информацию.
  • HTTP зависит от лежащих в его основе протоколов TCP, IP и DNS, которые управляются централизованными организациями, поэтому подвержены слежке и цензуре. IPFS не зависит от нижележащих протоколов и наличия прямого подключения к интернету вообще.
  • HTTP позволяет подменить отдаваемое содержимое. Хотя для многих задач жизненно необходимо постоянно его обновлять, некоторые файлы и веб-страницы должны оставаться неизменными. В IPFS идентификатор файла однозначно определяет его содержимое.

Устройство IPFS

В основе IPFS лежат несколько простых принципов:

  • Каждым файлу и директории присваивается уникальный идентификатор (CID — Content Identifier) на основе применения к его содержимому криптографической хэш-функции. Одинаковые файлы получают одинаковый идентификатор, разные файлы — разные идентификаторы.
  • Сеть устраняет дублирование. Например, если при загрузке новой версии директории часть файлов не изменились, то они будут разделены между новой и предыдущей версиями.
  • Адресация содержимого осуществляется по его уникальному идентификатору (content addressing), то есть не зависит от его фактического положения в сети.
  • Каждый узел содержит только ту информацию, в которой он заинтересован, а также некоторую дополнительную информацию, необходимую для поиска файлов в сети (DHT — Distributed Hash Table).

За более подробной информацией обратитесь к whitepaper и к документации.

ВНИМАНИЕ! IPFS является полностью публичной сетью. Любой помещённый в неё файл доступен каждому участнику сети. Для ограничения доступа используйте шифрование. Также возможно создание приватной сети на основе IPFS. Более подробно читайте в документации.

Фиксация содержимого

IPFS по умолчанию не даёт никаких гарантий того, что файлы будут храниться в сети. Как уже было сказано, узлы хранят только те файлы, которые используют.

Для сохранения файлов существует механизм закрепления (pinning). Есть несколько сценариев его использования:

  • Вы можете закрепить файл на своём рабочем компьютере или ноутбуке. При этом для вас он будет доступен всегда, даже в отсутствие доступа к интернету, но другие пользователи сети не смогут получить к нему доступ, когда вы не в сети.
  • Вы можете запустить узел IPFS на сервере, который запущен постоянно. При этом файл будет доступен всегда, однако появляются расходы на содержание сервера (оплата услуг VDS, администрирование).
  • Вы можете закрепить файл на чужом сервере IPFS, лично обратившись к его администратору, а также воспользовавшись веб-интерфейсом или API сервиса, если таковые имеются.

Для надёжности следует использовать все способы и закреплять файлы на нескольких узлах. Чем больше узлов хранит файл, тем меньше вероятность того, что он пропадёт, если узел будет закрыт.

На данный момент единственным известным нам сервисом по фиксации файлов в IPFS, работающим в автоматическом режиме, является Pinata. Он предоставляет 1 ГБ бесплатно, сверх этого хранение стоит $0.15 в месяц за 1 ГБ.

Шлюзы

Для доступа к файлам, размещённым в IPFS, требуется установка специального программного обеспечения. Расширение для веб-браузеров IPFS Companion делает опыт взаимодействия в веб-браузере со страницами из IPFS неотличимым от взаимодействия с обычными веб-страницами. IPFS Desktop позволяет рядовому пользователю легко использовать IPFS. Для администраторов серверов или для продвинутых пользователей возможна установка с помощью ipfs-update, из бинарных репозиториев или путём компиляции из исходного кода.

Необходимость установки программного обеспечения, даже если она не вызывает больших трудностей, сильно ограничивает потенциал IPFS. Для решения этой проблемы были придуманы шлюзы (gateways) — обычные веб-сайты, которые отдают содержимое из IPFS.

Как это работает? Допустим, в IPFS имеется файл с адресом ipfs://bafybeifoottvirj3crpx66qdsey7lxlp6qwk57wl37xygjqymeobwixy5e/concepts/ipfs-gateway/. Традиционное программное обеспечение не умеет открывать такие адреса. Поэтому мы можем сформировать обычную ссылку: https://ipfs.io/ipfs/bafybeifoottvirj3crpx66qdsey7lxlp6qwk57wl37xygjqymeobwixy5e/concepts/ipfs-gateway/. Здесь ipfs.io — это шлюз, который принадлежит разработчикам IPFS. Он использует способ разрешения имён через путь запроса. В общем случае URL выглядит так:

https://{URL шлюза}/ipfs/{CID}/{путь к ресурсу}

У такого способа разрешения имён есть два недостатка. Во-первых, если файл является веб-страницей, то ссылки на ней должны быть относительными. Во-вторых, если файл является веб-страницей, содержащей интерактивное одностраничное веб-приложение, то это угроза безопасности, поскольку приложение работает на том же домене, что и другие, посторонние приложения.

Поэтому существует ещё способ разрешения имён через поддомен. Ссылка на наш файл в этом случае будет иметь вид https://bafybeifoottvirj3crpx66qdsey7lxlp6qwk57wl37xygjqymeobwixy5e.ipfs.dweb.link/concepts/ipfs-gateway/, где ipfs.dweb.link — это шлюз, который поддерживает такой способ разрешения имён. В общем случае URL выглядит так:

https://{CID}.ipfs.{URL шлюза}/{путь к ресурсу}

Список шлюзов имеется по ссылке https://ipfs.github.io/public-gateway-checker/. Необходимо понимать, что использование сторонних шлюзов нивелирует преимущества IPFS. Одной из проблем сторонних шлюзов является то, что они без труда могут осуществить атаку MitM (man-in-the-middle), то есть подменить содержимое, однако это решается использованием собственного шлюза, поэтому вы вполне можете использовать IPFS для размещения серьёзных веб-сайтов и веб-приложений, не создавая неудобств для пользователей.

IPNS

Поскольку IPFS использует адресацию на основе содержимого, малейшее изменение полностью меняет адрес. Для того, чтобы иметь постоянную ссылку на меняющееся содержимое, поверх IPFS построена система IPNS (InterPlanetary Name System). Эта система очень простая. С использованием приватного ключа узел сообщает сети, что он хочет опубликовать по адресу, связанному с этим ключом, определённый CID. Эта привязка остаётся действительной некоторый промежуток времени, обычно сутки. Чтобы адрес оставался актуальным, требуется периодически повторно осуществлять эту операцию, что можно автоматизировать, например, с помощью Cron.

К сожалению, этот процесс нельзя делегировать стороннему сервису, как это возможно в случае простого хранения файлов, не передавая ему свой приватный ключ. Однако, это позволяет раздавать веб-сайт, например, с постоянно включенного домашнего компьютера, даже если он находится за NAT. Система IPNS ещё развивается. Возможно, в будущем это ограничение будет устранено.

В качестве примера приводим постоянный адрес веб-сайта Causa Arcana в IPNS (через шлюз): https://k51qzi5uqu5ditckag7gw12c301kwxac5fpobs62i21uysuiry3bobotvbenmc.ipns.dweb.link/.

DNSLink

IPNS использует в качестве идентификатора CID. Это очень длинная и ничего не значащая для человека строка, её неудобно произносить вслух и вводить вручную. Благодаря DNSLink можно привязать содержимое IPFS к традиционному доменному имени. Например, веб-сайт https://Causa-Arcana.com работает через DNSLink. При этом пользователи, у которых стоит программное обеспечение IPFS, получают содержимое из этой сети, а остальные пользователи получают содержимое через шлюз.

Для привязки CID к доменному имени необходимо создать две записи в DNS:

causa-arcana.com.          IN CNAME cloudflare-ipfs.com.
_dnslink.causa-arcana.com. IN TXT   "dnslink=/ipfs/bafybeic7vznjiq3tby7fezgdux6225x2pj3f6lkmrmivz3j4vbvb43yvhm"

Здесь cloudflare-ipfs.com — это адрес шлюза, который поддерживает DNSLink.

Преимуществом DNSLink перед IPNS, помимо более удобного имени веб-сайта и отсутствия необходимости иметь сервер для постоянного повторения процесса публикации, является отсутствие в ссылке доменного имени конкретного шлюза. Если шлюз перестал работать или заблокировал ваш веб-сайт, то достаточно выбрать другой шлюз и вписать его в запись DNS типа CNAME. В то же время, этот способ подразумевает привязку к традиционной системе доменных имён, которая является централизованной, в ней возможны цензура и изъятие домена.

Виды CID

Существует два вида идентификаторов содержимого:

  • CIDv0: QmesV3cwCMeweAMePKhPCkoKNh2A3cMgEYQwRPUUf3Cvy7
  • CIDv1: bafybeihvuei3zko5ao5v7k2tutds4b2fm7gcbc3mjete7ifkzsqayuq7ai

Хотя CIDv0 всё ещё является стандартным для содержимого, помещаемого в IPFS, он плохо подходит для поддоменов, поскольку использует и заглавные, и строчные буквы, в то время как доменные имена не чувствительны к регистру.

Один и тот же идентификатор CIDv1 может использовать различные кодировки:

  • Base32: bafzaajaiaejca2m4edvf5zdbgnbj5nvz2nm7chdtwzfcupmoaaarifdonsl7ibqu
  • Base36: k51qzi5uqu5ditckag7gw12c301kwxac5fpobs62i21uysuiry3bobotvbenmc

Именно CIDv1 с кодировкой Base36 используется для поддоменов.

Для преобразования между различными видами CID существует сервис https://cid.ipfs.io.

Публикуем веб-сайт в IPFS

Вам потребуются операционная система на основе GNU/Linux, навыки работы в командной строке и программное обеспечение IPFS.

Создаём веб-сайт

Для начала создадим простой веб-сайт, состоящий из двух страниц. Создайте пустую директорию в вашем домашнем каталоге и перейдите в неё:

$ cd
$ mkdir hello_ipfs
$ cd hello_ipfs

Также создайте директорию для второй страницы сайта. Это нужно для демонстрации работы относительных ссылок:

$ mkdir subdir

В директории верхнего уровня создайте файл index.html. Буквы после слова random (здесь это 74eownSL2tdYBsXm) замените на любые случайные буквы. Можете просто нажимать произвольные буквы на клавиатуре.

<!DOCTYPE html>
<html>
  <head>
    <!-- random: 74eownSL2tdYBsXm -->
    <meta charset="utf-8"/>
    <title>Hello, IPFS!</title>
  </head>
  <body>
    <h1>Hello, IPFS!</h1>
    <a href="subdir/index.html">Subdir</a>
  </body>
</html>

В директории subdir также создайте файл index.html. Аналогичным образом замените буквы после слова random (здесь это TKj20YgXq9fsqYTr) на случайные буквы.

<!DOCTYPE html>
<html>
  <head>
    <!-- random: TKj20YgXq9fsqYTr -->
    <meta charset="utf-8"/>
    <title>Hello from subdir, IPFS!</title>
  </head>
  <body>
    <h1>Hello from subdir, IPFS!</h1>
    <a href="../index.html">Root</a>
  </body>
</html>

Помещаем веб-сайт в IPFS

Перейдите в корневую директорию вашего проекта и наберите команду ipfs add -r ., после чего вы должны увидеть примерно следующий текст:

$ ipfs add -r .
added QmfGCviBGivYgbRGd1JfCgxhiXAUgszjwESBtVa9AoxFoW hello_ipfs/index.html
added QmdkXcfsSkpgaeh6GvQLBKVHsCoPEgBso7LW2rQdBoMgUo hello_ipfs/subdir/index.html
added QmPYofiX37wLX7ZDgxvsqNmqSDjDAzz3aurbgdZiSbyMGj hello_ipfs/subdir
added Qmd8QkqLB6xu1p6n6C3bWvtspidsPbx1gJ81fvXQiLdu6s hello_ipfs
 490 B / 490 B [========================================================] 100.00%

Если вы точно следовали инструкциям и использовали случайные символы, то указанные в каждой строке после слова added CID у вас будут отличаться от представленных. Нас интересует последний CID (здесь это Qmd8QkqLB6xu1p6n6C3bWvtspidsPbx1gJ81fvXQiLdu6s). Наберите его в адресной строке вашего веб-браузера после адреса любого шлюза. Получится похожая ссылка: https://ipfs.io/ipfs/Qmd8QkqLB6xu1p6n6C3bWvtspidsPbx1gJ81fvXQiLdu6s. Если вы перейдёте по ней, вы увидите ваш веб-сайт. Ссылка с одной его страницы должна вести на вторую, и наоборот.

Страницы веб-сайта.
Страницы веб-сайта.