💾 Archived View for causa-arcana.com › blog › 2021 › 03 › 25 › ipfs.html captured on 2022-04-29 at 02:31:53.
⬅️ Previous capture (2022-01-08)
-=-=-=-=-=-=-
<!DOCTYPE html> <html class="h-100" lang="ru"> <head> <meta charset="utf-8"/> <meta http-equiv="X-UA-Compatible" content="IE=edge"/> <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, shrink-to-fit=no, user-scalable=no"/> <title>Размещение сайтов в распределённой файловой системе IPFS | Causa Arcana</title> <link rel="canonical" href="https://causa-arcana.com/blog/2021/03/25/ipfs.html"/> <link rel="alternate" type="application/rss+xml" title="Causa Arcana" href="https://causa-arcana.com/blog/feed.xml"/> <meta name="description" content=" Логотип IPFS. В статье “Децентрализованные сервисы против распределённых” в качестве примера распределённой системы мы приводили IPFS (InterPlanerary File System). Пришла пора рассказать о ней подробнее, поскольку это одна из н..."/> <meta name="twitter:card" content="summary"/> <meta name="twitter:site" content="@causa_arcana"/> <meta name="twitter:creator" content="@causa_arcana"/> <meta name="twitter:title" content="Размещение сайтов в распределённой файловой системе IPFS | Causa Arcana"/> <meta name="twitter:description" content=" Логотип IPFS. В статье “Децентрализованные сервисы против распределённых” в качестве примера распределённой системы мы приводили IPFS (InterPlanerary File System). Пришла пора рассказать о ней подробнее, поскольку это одна из н..."/> <meta name="twitter:image" content="https://causa-arcana.com/assets/images/blog/ipfs.jpg"/> <meta property="og:type" content="website"/> <meta property="og:url" content="https://causa-arcana.com/blog/2021/03/25/ipfs.html"/> <meta property="og:title" content="Размещение сайтов в распределённой файловой системе IPFS | Causa Arcana"/> <meta property="og:description" content=" Логотип IPFS. В статье “Децентрализованные сервисы против распределённых” в качестве примера распределённой системы мы приводили IPFS (InterPlanerary File System). Пришла пора рассказать о ней подробнее, поскольку это одна из н..."/> <meta property="og:image" content="https://causa-arcana.com/assets/images/blog/ipfs.jpg"/> <link href="../../../../assets/images/logo.jpg" rel="icon" type="image/jpg" /> <link href="../../../../assets/stylesheets/site.css" rel="stylesheet" /> <script src="../../../../assets/javascripts/site.js"></script> </head> <body class="d-flex flex-column h-100"> <header> <nav class="navbar navbar-expand-lg navbar-dark bg-dark"> <div class="container-fluid"> <a href="../../../../index.html" class="navbar-brand"> <img src="../../../../assets/images/logo.jpg" width="30" height="30" alt="Логотип" /> Causa Arcana </a> <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation" > <span class="navbar-toggler-icon"></span> </button> <div class="collapse navbar-collapse" id="navbarSupportedContent"> <ul class="navbar-nav me-auto"> <li class="nav-item"> <a href="../../../feed.html" class="nav-link active "> Блог </a> </li> <li class="nav-item dropdown"> <a href="#" id="thirdPartyMaterialsDropdown" role="button" class="nav-link dropdown-toggle " data-bs-toggle="dropdown" aria-haspopup="true"> Сторонние материалы </a> <div class="dropdown-menu" aria-labelledby="thirdPartyMaterialsDropdown"> <a href="../../../../sources.html" class="dropdown-item "> Источники </a> </div> </li> <li class="nav-item dropdown"> <a href="#" id="aboutUsNavbarDropdown" role="button" class="nav-link dropdown-toggle " data-bs-toggle="dropdown" aria-haspopup="true"> О нас </a> <div class="dropdown-menu" aria-labelledby="aboutUsNavbarDropdown"> <a href="../../../../team/index.html" class="dropdown-item "> Наша команда </a> <hr class="dropdown-divider"> <a href="../../../../git.html" class="dropdown-item "> Репозитории Git </a> </div> </li> </ul> </div> </div> </nav> </header> <main> <article class="cl-blog-article container mt-4 mb-5"> <header> <h1>Размещение сайтов в распределённой файловой системе IPFS</h1> <p> <small class="text-muted"> <time datetime="2021-03-25T01:40:00Z"> 25 Март, 2021 01:40 </time> </small> • <small class="text-muted"> Александр Котов </small> • <a href="https://medium.com/causa-arcana/ipfs-a87b04790dc9"><i class="fab fa-medium"></i> Medium</a> <br/> <span class="badge bg-secondary me-2"> ipfs </span> <span class="badge bg-secondary me-2"> децентрализация </span> <span class="badge bg-secondary me-2"> распределённые приложения </span> </p> </header> <div class="blog-article--main mt-5 text-break"> <div class="d-flex justify-content-center"> <figure class="nice-figure"> <img src="../../../../assets/images/blog/ipfs.jpg" alt="Логотип IPFS."/> <figcaption> Логотип IPFS. </figcaption> </figure> </div> <p>В статье “<a href="../../../2020/06/04/decentralized-vs-distributed.html">Децентрализованные сервисы против распределённых</a>” в качестве примера распределённой системы мы приводили <a href="https://ipfs.io">IPFS (InterPlanerary File System)</a>. Пришла пора рассказать о ней подробнее, поскольку это одна из наиболее перспективных распределённых технологий.</p> <h2>Что такое IPFS?</h2> <p>IPFS – это глобальное хранилище неизменяемой информации. Работает как временный кэш, но также возможно использование специальных сервисов (платных или волонтёрских), гарантирующих сохранность информации.</p> <h3>Какие проблемы решает IPFS?</h3> <p>IPFS <a href="https://ipfs.io/ipfs/bafybeiaqdybghuhw5diqswi2nst2s4kx724ioklijwwgazsr4f5mrg5n5u/#why">должен заменить</a> некоторые функции HTTP (и HTTPS) из-за проблем этого протокола:</p> <ul> <li>HTTP загружает файл с одного сервера вместо того, чтобы получать его части из множества источников одновременно. Это увеличивает нагрузку на этот сервер и расходует его сетевой трафик. IPFS позволяет <a href="http://math.oregonstate.edu/~kovchegy/web/papers/p2p-vdn.pdf">сократить</a> эти расходы.</li> <li>HTTP требует, чтобы сервер, с которого происходит загрузка файла, присутствовал в этот момент по определённому в ссылке адресу. Это приводит к тому, что среднее время жизни веб-страницы в Интернете <a href="https://blogs.loc.gov/thesignal/2011/11/the-average-lifespan-of-a-webpage/">составляет</a> 100 дней. IPFS выполняет функцию веб-архива, позволяя сохранять полезную информацию.</li> <li>HTTP зависит от лежащих в его основе протоколов TCP, IP и DNS, которые управляются централизованными организациями, поэтому подвержены слежке и цензуре. IPFS не зависит от нижележащих протоколов и наличия прямого подключения к Интернету вообще.</li> <li>HTTP позволяет подменить отдаваемое содержимое. Хотя для многих задач жизненно необходимо постоянно его обновлять, некоторые файлы и веб-страницы должны оставаться неизменными. В IPFS идентификатор файла однозначно определяет его содержимое.</li> </ul> <h3>Устройство IPFS</h3> <p>В основе IPFS лежат <a href="https://ipfs.io/ipfs/bafybeiaqdybghuhw5diqswi2nst2s4kx724ioklijwwgazsr4f5mrg5n5u/#how">несколько простых принципов</a>:</p> <ul> <li>Каждым файлу и директории присваивается <strong>уникальный идентификатор</strong> (<a href="https://ipfs.io/ipfs/bafybeifoottvirj3crpx66qdsey7lxlp6qwk57wl37xygjqymeobwixy5e/concepts/content-addressing/">CID – Content Identifier</a>) на основе применения к его содержимому <strong>криптографической хэш-функции</strong>. Одинаковые файлы получают одинаковый идентификатор, разные файлы – разные идентификаторы.</li> <li>Сеть <strong>устраняет дублирование</strong>. Например, если при загрузке новой версии директории часть файлов не изменились, то они будут разделены между новой и предыдущей версиями.</li> <li><strong>Адресация</strong> содержимого осуществляется <strong>по его уникальному идентификатору</strong> (<a href="https://ipfs.io/ipfs/bafybeifoottvirj3crpx66qdsey7lxlp6qwk57wl37xygjqymeobwixy5e/concepts/content-addressing/">content addressing</a>), то есть не зависит от его фактического положения в сети.</li> <li>Каждый <strong>узел содержит только ту информацию, в которой он заинтересован</strong>, а также некоторую дополнительную информацию, необходимую для поиска файлов в сети (<a href="https://ipfs.io/ipfs/bafybeifoottvirj3crpx66qdsey7lxlp6qwk57wl37xygjqymeobwixy5e/concepts/dht/">DHT – Distributed Hash Table</a>).</li> </ul> <p>За более подробной информацией обратитесь к <a href="https://ipfs.io/ipfs/bafybeibjo6pfdtnaqscxeu5bmsy5n27eg2kntswt2jmmv3enaejjbc45ce">whitepaper</a> и к <a href="https://docs.ipfs.io">документации</a>.</p> <p><strong>ВНИМАНИЕ!</strong> IPFS является полностью публичной сетью. Любой помещённый в неё файл доступен каждому участнику сети. Для ограничения доступа используйте шифрование. Также возможно создание приватной сети на основе IPFS. Более подробно читайте <a href="https://ipfs.io/ipfs/bafybeifoottvirj3crpx66qdsey7lxlp6qwk57wl37xygjqymeobwixy5e/concepts/privacy/">в документации</a>.</p> <h3>Фиксация содержимого</h3> <p>IPFS по умолчанию не даёт никаких гарантий того, что файлы будут храниться в сети. Как уже было сказано, узлы хранят только те файлы, которые используют.</p> <p>Для сохранения файлов существует механизм закрепления (<a href="https://ipfs.io/ipfs/bafybeifoottvirj3crpx66qdsey7lxlp6qwk57wl37xygjqymeobwixy5e/concepts/persistence/">pinning</a>). Есть несколько сценариев его использования:</p> <ul> <li>Вы можете закрепить файл на своём рабочем компьютере или ноутбуке. При этом для вас он будет доступен всегда, даже в отсутствие доступа к Интернету, но другие пользователи сети не смогут получить к нему доступ, когда вы не в сети.</li> <li>Вы можете запустить узел IPFS на сервере, который запущен постоянно. При этом файл будет доступен всегда, однако появляются расходы на содержание сервера (оплата услуг VDS, администрирование).</li> <li>Вы можете закрепить файл на чужом сервере IPFS, лично обратившись к его администратору, а также воспользовавшись веб-интерфейсом или API сервиса, если таковые имеются.</li> </ul> <p>Для надёжности следует использовать все способы и закреплять файлы на нескольких узлах. Чем больше узлов хранит файл, тем меньше вероятность того, что он пропадёт, если узел будет закрыт.</p> <p>На данный момент единственным известным нам сервисом по фиксации файлов в IPFS, работающим в автоматическом режиме, является <a href="https://pinata.cloud">Pinata</a>. Он предоставляет 1 ГБ бесплатно, сверх этого хранение стоит $0.15 в месяц за 1 ГБ.</p> <h3>Шлюзы</h3> <p>Для доступа к файлам, размещённым в IPFS, требуется установка специального <a href="https://ipfs.io/ipfs/bafybeiaqdybghuhw5diqswi2nst2s4kx724ioklijwwgazsr4f5mrg5n5u/#install">программного обеспечения</a>. Расширение для веб-браузеров <a href="https://github.com/ipfs-shipyard/ipfs-companion">IPFS Companion</a> делает опыт взаимодействия в веб-браузере со страницами из IPFS неотличимым от взаимодействия с обычными веб-страницами. <a href="https://github.com/ipfs-shipyard/ipfs-desktop">IPFS Desktop</a> позволяет рядовому пользователю легко использовать IPFS. Для администраторов серверов или для продвинутых пользователей возможна установка с помощью <a href="https://github.com/ipfs/ipfs-update">ipfs-update</a>, из <a href="https://ipfs.io/ipfs/bafybeifoottvirj3crpx66qdsey7lxlp6qwk57wl37xygjqymeobwixy5e/install/command-line/">бинарных репозиториев</a> или путём компиляции и�� <a href="https://github.com/ipfs/go-ipfs">исходного кода</a>.</p> <p>Необходимость установки программного обеспечения, даже если она не вызывает больших трудностей, сильно ограничивает потенциал IPFS. Для решения этой проблемы были придуманы шлюзы (<a href="https://ipfs.io/ipfs/bafybeifoottvirj3crpx66qdsey7lxlp6qwk57wl37xygjqymeobwixy5e/concepts/ipfs-gateway/">gateways</a>) – обычные веб-сайты, которые отдают содержимое из IPFS.</p> <p>Как это работает? Допустим, в IPFS имеется файл с адресом <code>ipfs://bafybeifoottvirj3crpx66qdsey7lxlp6qwk57wl37xygjqymeobwixy5e/concepts/ipfs-gateway/</code>. Традиционное программное обеспечение не умеет открывать такие адреса. Поэтому мы можем сформировать обычную ссылку: <a href="https://ipfs.io/ipfs/bafybeifoottvirj3crpx66qdsey7lxlp6qwk57wl37xygjqymeobwixy5e/concepts/ipfs-gateway/">https://ipfs.io/ipfs/bafybeifoottvirj3crpx66qdsey7lxlp6qwk57wl37xygjqymeobwixy5e/concepts/ipfs-gateway/</a>. Здесь <code>ipfs.io</code> – это шлюз, который принадлежит разработчикам IPFS. Он использует способ разрешения имён через путь запроса. В общем случае URL выглядит так:</p> <pre><code>https://{URL шлюза}/ipfs/{CID}/{путь к ресурсу} </code></pre> <p>У такого способа разрешения имён есть два недостатка. Во-первых, если файл является веб-страницей, то ссылки на ней должны быть относительными. Во-вторых, если файл является веб-страницей, содержащей интерактивное одностраничное веб-приложение, то это угроза безопасности, поскольку приложение работает на том же домене, что и другие, посторонние приложения.</p> <p>Поэтому существует ещё способ разрешения имён через поддомен. Ссылка на наш файл в этом случае будет иметь вид <a href="https://bafybeifoottvirj3crpx66qdsey7lxlp6qwk57wl37xygjqymeobwixy5e.ipfs.dweb.link/concepts/ipfs-gateway/">https://bafybeifoottvirj3crpx66qdsey7lxlp6qwk57wl37xygjqymeobwixy5e.ipfs.dweb.link/concepts/ipfs-gateway/</a>, где <code>ipfs.dweb.link</code> – это шлюз, который поддерживает такой способ разрешения имён. В общем случае URL выглядит так:</p> <pre><code>https://{CID}.ipfs.{URL шлюза}/{путь к ресурсу} </code></pre> <p>Список шлюзов имеется по ссылке <a href="https://ipfs.github.io/public-gateway-checker/">https://ipfs.github.io/public-gateway-checker/</a>. Необходимо понимать, что использование сторонних шлюзов нивелирует преимущества IPFS. Одной из проблем сторонних шлюзов является то, что они без труда могут осуществить атаку MitM (man-in-the-middle), то есть подменить содержимое, однако это решается использованием собственного шлюза, поэтому вы вполне можете использовать IPFS для размещения серьёзных веб-сайтов и веб-приложений, не создавая неудобств для пользователей.</p> <h3>IPNS</h3> <p>Поскольку IPFS использует адресацию на основе содержимого, малейшее изменение полностью меняет адрес. Для того, чтобы иметь постоянную ссылку на меняющееся содержимое, поверх IPFS построена система <a href="https://ipfs.io/ipfs/bafybeifoottvirj3crpx66qdsey7lxlp6qwk57wl37xygjqymeobwixy5e/concepts/ipns/">IPNS (InterPlanetary Name System)</a>. Эта система очень простая. С использованием приватного ключа узел сообщает сети, что он хочет опубликовать по адресу, связанному с этим ключом, определённый CID. Эта привязка остаётся действительной некоторый промежуток времени, обычно сутки. Чтобы адрес оставался актуальным, требуется периодически повторно осуществлять эту операцию, что можно автоматизировать, например, с помощью <a href="https://ru.wikipedia.org/wiki/Cron">Cron</a>.</p> <p>К сожалению, этот процесс нельзя делегировать стороннему сервису, как это возможно в случае простого хранения файлов, не передавая ему свой приватный ключ. Однако, это позволяет раздавать веб-сайт, например, с постоянно включенного домашнего компьютера, даже если он находится за NAT. Система IPNS ещё развивается. Возможно, в будущем это ограничение будет устранено.</p> <p>В качестве примера приводим постоянный адрес веб-сайта Causa Arcana в IPNS (через шлюз): <a href="https://k51qzi5uqu5ditckag7gw12c301kwxac5fpobs62i21uysuiry3bobotvbenmc.ipns.dweb.link/">https://k51qzi5uqu5ditckag7gw12c301kwxac5fpobs62i21uysuiry3bobotvbenmc.ipns.dweb.link/</a>.</p> <h3>DNSLink</h3> <p>IPNS использует в качестве идентификатора CID. Это очень длинная и ничего не значащая для человека строка, её неудобно произносить вслух и вводить вручную. Благодаря <a href="https://ipfs.io/ipfs/bafybeifoottvirj3crpx66qdsey7lxlp6qwk57wl37xygjqymeobwixy5e/concepts/dnslink/">DNSLink</a> можно привязать содержимое IPFS к традиционному доменному имени. Например, веб-сайт <a href="https://causa-arcana.com">https://Causa-Arcana.com</a> работает через DNSLink. При этом пользователи, у которых стоит программное обеспечение IPFS, получают содержимое из этой сети, а остальные пользователи получают содержимое через шлюз.</p> <p>Для привязки CID к доменному имени необходимо создать две записи в DNS:</p> <pre><code>causa-arcana.com. IN CNAME cloudflare-ipfs.com. _dnslink.causa-arcana.com. IN TXT "dnslink=/ipfs/bafybeic7vznjiq3tby7fezgdux6225x2pj3f6lkmrmivz3j4vbvb43yvhm" </code></pre> <p>Здесь <code>cloudflare-ipfs.com</code> – это адрес шлюза, который поддерживает DNSLink.</p> <p>Преимуществом DNSLink перед IPNS, помимо более удобного имени веб-сайта и отсутствия необходимости иметь сервер для постоянного повторения процесса публикации, является отсутствие в ссылке доменного имени конкретного шлюза. Если шлюз перестал работать или заблокировал ваш веб-сайт, то достаточно выбрать другой шлюз и вписать его в запись DNS типа CNAME. В то же время, этот способ подразумевает привязку к традиционной системе доменных имён, которая является централизованной, в ней возможны цензура и изъятие домена.</p> <h3>Виды CID</h3> <p>Существует два вида идентификаторов содержимого:</p> <ul> <li><strong>CIDv0</strong>: <code>QmesV3cwCMeweAMePKhPCkoKNh2A3cMgEYQwRPUUf3Cvy7</code></li> <li><strong>CIDv1</strong>: <code>bafybeihvuei3zko5ao5v7k2tutds4b2fm7gcbc3mjete7ifkzsqayuq7ai</code></li> </ul> <p>Хотя CIDv0 всё ещё является стандартным для содержимого, помещаемого в IPFS, он плохо подходит для поддоменов, поскольку использует и заглавные, и строчные буквы, в то время как доменные имена не чувствительны к регистру.</p> <p>Один и тот же идентификатор CIDv1 может использовать различные кодировки:</p> <ul> <li><strong>Base32</strong>: <code>bafzaajaiaejca2m4edvf5zdbgnbj5nvz2nm7chdtwzfcupmoaaarifdonsl7ibqu</code></li> <li><strong>Base36</strong>: <code>k51qzi5uqu5ditckag7gw12c301kwxac5fpobs62i21uysuiry3bobotvbenmc</code></li> </ul> <p>Именно CIDv1 с кодировкой Base36 используется для поддоменов.</p> <p>Для преобразования между различными видами CID существует сервис <a href="https://cid.ipfs.io">https://cid.ipfs.io</a>.</p> <h2>Публикуем веб-сайт в IPFS</h2> <p>Вам потребуются операционная система на основе GNU/Linux, навыки работы в командной строке и <a href="https://ipfs.io/ipfs/bafybeifoottvirj3crpx66qdsey7lxlp6qwk57wl37xygjqymeobwixy5e/install/command-line/">программное обеспечение IPFS</a>.</p> <h3>Создаём веб-сайт</h3> <p>Для начала создадим простой веб-сайт, состоящий из двух страниц. Создайте пустую директорию в вашем домашнем каталоге и перейдите в неё:</p> <pre><code>$ cd $ mkdir hello_ipfs $ cd hello_ipfs </code></pre> <p>Также создайте директорию для второй страницы сайта. Это нужно для демонстрации работы относительных ссылок:</p> <pre><code>$ mkdir subdir </code></pre> <p>В директории верхнего уровня создайте файл <code>index.html</code>. Буквы после слова <code>random</code> (здесь это <code>74eownSL2tdYBsXm</code>) замените на любые случайные буквы. Можете просто нажимать произвольные буквы на клавиатуре.</p> <pre><code class="html"><!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> </code></pre> <p>В директории <code>subdir</code> также создайте файл <code>index.html</code>. Аналогичным образом замените буквы после слова <code>random</code> (здесь это <code>TKj20YgXq9fsqYTr</code>) на случайные буквы.</p> <pre><code class="html"><!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> </code></pre> <h3>Помещаем веб-сайт в IPFS</h3> <p>Перейдите в корневую директорию вашего проекта и наберите команду <code>ipfs add -r .</code>, после чего вы должны увидеть примерно следующий текст:</p> <pre><code>$ 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% </code></pre> <p>Если вы точно следовали инструкциям и использовали случайные символы, то указанные в каждой строке после слова <code>added</code> CID у вас будут отличаться от представленных. Нас интересует последний CID (здесь это <code>Qmd8QkqLB6xu1p6n6C3bWvtspidsPbx1gJ81fvXQiLdu6s</code>). Наберите его в адресной строке вашего веб-браузера после адреса любого шлюза. Получится похожая ссылка: <a href="https://ipfs.io/ipfs/Qmd8QkqLB6xu1p6n6C3bWvtspidsPbx1gJ81fvXQiLdu6s">https://ipfs.io/ipfs/Qmd8QkqLB6xu1p6n6C3bWvtspidsPbx1gJ81fvXQiLdu6s</a>. Если вы перейдёте по ней, вы увидите ваш веб-сайт. Ссылка с одной его страницы должна вести на вторую, и наоборот.</p> <div class="d-flex justify-content-center"> <figure class="nice-figure"> <img src="../../../../assets/images/blog/ipfs-hello.png" alt="Страницы веб-сайта."/> <figcaption> Страницы веб-сайта. </figcaption> </figure> </div> </div> </article> </main> <footer class="mt-auto py-4 bg-dark text-light"> <div class="container"> <div class="d-sm-none"> <div class="row row-cols-1"> <div class="col"> <ul class="list-unstyled mb-0"> <li><a href="https://t.me/causa_arcana" class="link-light"><i class="fab fa-telegram"></i> Канал в Telegram</a></li> <li><a href="https://t.me/causa_arcana_chat" class="link-light"><i class="fab fa-telegram"></i> Чат в Telegram</a></li> <li><a href="https://www.youtube.com/c/CausaArcana" class="link-light"><i class="fab fa-youtube"></i> YouTube</a></li> <li><a href="https://medium.com/causa-arcana" class="link-light"><i class="fab fa-medium"></i> Medium</a></li> <li><a href="https://qoto.org/@causa_arcana" class="link-light"><i class="fab fa-mastodon"></i> Mastodon</a></li> <li><a href="https://diode.zone/video-channels/causa_arcana" class="link-light"><i class="fab fa-mastodon"></i> PeerTube</a></li> <li><a href="https://matrix.to/#/#causa-arcana:matrix.org" class="link-light"><i class="far fa-comments"></i> Matrix</a></li> <li><a href="https://twitter.com/causa_arcana" class="link-light"><i class="fab fa-twitter"></i> Twitter</a></li> </ul> </div> </div> </div> <div class="d-none d-sm-block d-md-none"> <div class="row row-cols-2"> <div class="col"> <ul class="list-unstyled mb-0"> <li><a href="https://t.me/causa_arcana" class="link-light"><i class="fab fa-telegram"></i> Канал в Telegram</a></li> <li><a href="https://t.me/causa_arcana_chat" class="link-light"><i class="fab fa-telegram"></i> Чат в Telegram</a></li> <li><a href="https://www.youtube.com/c/CausaArcana" class="link-light"><i class="fab fa-youtube"></i> YouTube</a></li> <li><a href="https://medium.com/causa-arcana" class="link-light"><i class="fab fa-medium"></i> Medium</a></li> </ul> </div> <div class="col"> <ul class="list-unstyled mb-0"> <li><a href="https://qoto.org/@causa_arcana" class="link-light"><i class="fab fa-mastodon"></i> Mastodon</a></li> <li><a href="https://diode.zone/video-channels/causa_arcana" class="link-light"><i class="fab fa-mastodon"></i> PeerTube</a></li> <li><a href="https://matrix.to/#/#causa-arcana:matrix.org" class="link-light"><i class="far fa-comments"></i> Matrix</a></li> <li><a href="https://twitter.com/causa_arcana" class="link-light"><i class="fab fa-twitter"></i> Twitter</a></li> </ul> </div> </div> </div> <div class="d-none d-md-block d-lg-none"> <div class="row row-cols-3"> <div class="col"> <ul class="list-unstyled mb-0"> <li><a href="https://t.me/causa_arcana" class="link-light"><i class="fab fa-telegram"></i> Канал в Telegram</a></li> <li><a href="https://t.me/causa_arcana_chat" class="link-light"><i class="fab fa-telegram"></i> Чат в Telegram</a></li> <li><a href="https://www.youtube.com/c/CausaArcana" class="link-light"><i class="fab fa-youtube"></i> YouTube</a></li> </ul> </div> <div class="col"> <ul class="list-unstyled mb-0"> <li><a href="https://medium.com/causa-arcana" class="link-light"><i class="fab fa-medium"></i> Medium</a></li> <li><a href="https://qoto.org/@causa_arcana" class="link-light"><i class="fab fa-mastodon"></i> Mastodon</a></li> <li><a href="https://diode.zone/video-channels/causa_arcana" class="link-light"><i class="fab fa-mastodon"></i> PeerTube</a></li> </ul> </div> <div class="col"> <ul class="list-unstyled mb-0"> <li><a href="https://matrix.to/#/#causa-arcana:matrix.org" class="link-light"><i class="far fa-comments"></i> Matrix</a></li> <li><a href="https://twitter.com/causa_arcana" class="link-light"><i class="fab fa-twitter"></i> Twitter</a></li> </ul> </div> </div> </div> <div class="d-none d-lg-block"> <div class="row row-cols-4"> <div class="col"> <ul class="list-unstyled mb-0"> <li><a href="https://t.me/causa_arcana" class="link-light"><i class="fab fa-telegram"></i> Канал в Telegram</a></li> <li><a href="https://t.me/causa_arcana_chat" class="link-light"><i class="fab fa-telegram"></i> Чат в Telegram</a></li> </ul> </div> <div class="col"> <ul class="list-unstyled mb-0"> <li><a href="https://www.youtube.com/c/CausaArcana" class="link-light"><i class="fab fa-youtube"></i> YouTube</a></li> <li><a href="https://medium.com/causa-arcana" class="link-light"><i class="fab fa-medium"></i> Medium</a></li> </ul> </div> <div class="col"> <ul class="list-unstyled mb-0"> <li><a href="https://qoto.org/@causa_arcana" class="link-light"><i class="fab fa-mastodon"></i> Mastodon</a></li> <li><a href="https://diode.zone/video-channels/causa_arcana" class="link-light"><i class="fab fa-mastodon"></i> PeerTube</a></li> </ul> </div> <div class="col"> <ul class="list-unstyled mb-0"> <li><a href="https://matrix.to/#/#causa-arcana:matrix.org" class="link-light"><i class="far fa-comments"></i> Matrix</a></li> <li><a href="https://twitter.com/causa_arcana" class="link-light"><i class="fab fa-twitter"></i> Twitter</a></li> </ul> </div> </div> </div> <hr/> <p class="mb-0"> <i class="fas fa-rss-square"></i> RSS: <a href="https://causa-arcana.com/blog/feed.xml" class="text-reset">https://causa-arcana.com/blog/feed.xml</a> </p> <p class="mb-0"> <i class="fab fa-creative-commons-by"></i> Содержимое доступно на условиях лицензии <a rel="license" href="https://creativecommons.org/licenses/by/4.0/" class="text-reset">Creative Commons Attribution</a>. </p> <p class="mb-0"> <i class="far fa-envelope"></i> Связь с администрацией: <a href="mailto:admin@causa-arcana.com" class="text-reset"> admin@causa-arcana.com </a> </p> </div> </footer> </body> </html>