<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ ipfs - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ Browse thousands of programming tutorials written by experts. Learn Web Development, Data Science, DevOps, Security, and get developer career advice. ]]>
        </description>
        <link>https://www.freecodecamp.org/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ ipfs - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Mon, 27 Jul 2026 15:22:58 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/tag/ipfs/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ A Technical Guide to IPFS – the Decentralized Storage of Web3 ]]>
                </title>
                <description>
                    <![CDATA[ By Lukas Lukac When you think about developing a decentralized application, a blockchain like Ethereum probably comes to mind. Blockchain is fantastic for managing state, automating processes via Smart Contracts, and exchanging economic value. You ca... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/technical-guide-to-ipfs-decentralized-storage-of-web3/</link>
                <guid isPermaLink="false">66d46179d7a4e35e384349c3</guid>
                
                    <category>
                        <![CDATA[ Blockchain ]]>
                    </category>
                
                    <category>
                        <![CDATA[ decentralization ]]>
                    </category>
                
                    <category>
                        <![CDATA[ ipfs ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Web3 ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Mon, 21 Jun 2021 16:38:36 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2021/06/tech_guide_ipfs_web3coach_banner-1.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Lukas Lukac</p>
<p>When you think about developing a decentralized application, a blockchain like Ethereum probably comes to mind.</p>
<p>Blockchain is fantastic for managing state, automating processes via Smart Contracts, and exchanging economic value.</p>
<p>You can <a target="_blank" href="https://www.freecodecamp.org/news/build-a-blockchain-in-golang-from-scratch/">follow this tutorial to learn blockchain by building one from scratch yourself</a> if you want to learn more.</p>
<p><strong>But where do you store your application's content?</strong> Images? Videos? The application's website front-end composed of all the HTML, CSS, and JS files? Are your application and your users' content loaded from a centralized AWS server?</p>
<p>Storing the content on the blockchain would be expensive and inefficient.</p>
<p>Your blockchain application needs decentralized storage!</p>
<p>In this tutorial, I will introduce you to the InterPlanetary File System, or IPFS. You will learn:</p>
<ol>
<li>How to store and retrieve content from a decentralized storage</li>
<li>How to run your IPFS node</li>
<li>All about the low-level internals of the IPFS protocol</li>
<li>And we'll read a Wikipedia website stored on IPFS</li>
</ol>
<p>Ready? Let's go.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><a class="post-section-overview" href="#heading-what-is-the-ipfs">What is the IPFS?</a></li>
<li><a class="post-section-overview" href="#heading-how-to-setup-an-ipfs-node">How to setup an IPFS node</a></li>
<li><a class="post-section-overview" href="#heading-how-to-use-ipfs">How to store and retrieve IPFS content using the CLI and HTTP</a></li>
<li><a class="post-section-overview" href="#heading-how-ipfs-content-addressing-works">What is CID – the IPFS content-based identifier</a></li>
<li><a class="post-section-overview" href="#heading-how-ipfs-stores-content-on-the-file-system">How to reverse engineer the IPFS datastore</a></li>
<li><a class="post-section-overview" href="#heading-how-to-connect-an-ipfs-node-to-the-p2p-network">How to connect an IPFS node to a decentralized network</a></li>
<li><a class="post-section-overview" href="#heading-how-nodes-exchange-data-using-the-bitswap-protocol">How to exchange data using the peer-to-peer Bitswap protocol</a></li>
<li><a class="post-section-overview" href="#heading-how-to-persist-content-from-the-p2p-network">How to persist content from the peer-to-peer network</a></li>
</ul>
<h2 id="heading-what-is-the-ipfs">What is the IPFS?</h2>
<p>The InterPlanetary File System, or IPFS for short, is a peer-to-peer hypermedia protocol designed to make the web faster, safer, and more open.</p>
<p><strong>IPFS is a protocol for storing and sharing content.</strong> As in the blockchain world, every user is running its node (server). The nodes can communicate between each other and exchange files.</p>
<h3 id="heading-what-is-unique-about-ipfs">What is unique about IPFS?</h3>
<p>First of all, the <strong>IPFS is decentralized</strong> because it loads the content from thousands of peers instead of one centralized server. Every piece of data is cryptographically hashed, resulting in a safe, unique <strong>content identifier</strong>: CID.</p>
<p>Store your website in IPFS to avoid censorship and a single point of failure. Your personal IPFS node goes offline? Don't worry, the website will still load from other nodes across the globe serving it.</p>
<p>For example, suppose your government bans Wikipedia. In that case, you can still access a decentralized version of Wikipedia indexed on April 17th by loading it from the IPFS peer-to-peer network persisted under CID:</p>
<blockquote>
<p><strong>"</strong>QmT5NvUtoM5nWFfrQdVrFtvGfKFmG7AHE8P34isapyhCxX"</p>
</blockquote>
<p>Second, the integrity of <strong>IPFS content can be cryptographically verified.</strong></p>
<p>And finally, <strong>the IPFS content is de-duplicated.</strong> If you tried storing two identical 1MB files in the same IPFS node, they would be stored only once, eliminating the duplication, because their hash would produce an identical <strong>CID.</strong></p>
<h2 id="heading-how-to-setup-an-ipfs-node">How to Setup an IPFS Node</h2>
<h3 id="heading-install-ipfs">Install IPFS</h3>
<p>Open the <a target="_blank" href="https://docs.ipfs.io/install/">official IPFS docs</a> installation page and follow the instructions depending on your operating system (Windows, macOS, Linux). I will be documenting the Ubuntu installation process below.</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://docs.ipfs.io/install/command-line/#official-distributions">https://docs.ipfs.io/install/command-line/#official-distributions</a></div>
<p>I prefer compiling the <a target="_blank" href="http://github.com/ipfs/go-ipfs">ipfs/go-ipfs</a> repository from scratch to debug the code when needed, and let's be honest: GoLang rocks.</p>
<h4 id="heading-compile-the-codebase-in-go">Compile the codebase in Go</h4>
<p>Clone the repository and run the install script in the Makefile.</p>
<pre><code>git clone https:<span class="hljs-comment">//github.com/ipfs/go-ipfs.git</span>
cd go-ipfs
git checkout v0<span class="hljs-number">.8</span><span class="hljs-number">.0</span>-rc2
make install
</code></pre><p>Or download pre-compiled IPFS:</p>
<pre><code>sudo snap install ipfs
</code></pre><h3 id="heading-validate-the-installation">Validate the installation</h3>
<p>Let's be honest. Go is amazing and compiling the codebase yourself is bad-ass and decentralized. The resulted binary will be created in your <code>$GOPATH</code>.</p>
<pre><code>which ipfs
&gt; <span class="hljs-regexp">/home/</span>web3coach/go/bin/ipfs

ipfs version
&gt; ipfs version <span class="hljs-number">0.8</span><span class="hljs-number">.0</span>-rc2
</code></pre><h3 id="heading-initialize-a-new-node">Initialize a new node</h3>
<p>Run <code>ipfs init</code> to create your new node. By default, it will create a folder and store all the data in <code>~/.ipfs</code> You can tweak this by configuring the <code>IPFS_PATH</code> ENV variable.</p>
<pre><code>IPFS_PATH=<span class="hljs-regexp">/home/</span>web3coach/.ipfs_tutorial ipfs init

&gt; generating ED25519 keypair...done
&gt; peer identity: <span class="hljs-number">12</span>D3Koo...dNs
&gt; initializing IPFS node at /home/web3coach/.ipfs_tutorial
</code></pre><p>Your node is now fully initialized, awaiting your content.</p>
<h2 id="heading-how-to-use-ipfs">How to Use IPFS</h2>
<h3 id="heading-add-content">Add content</h3>
<p>IPFS can handle all kinds of different data types – from simple strings to images, videos, and websites.</p>
<p>Start by storing a short message <code>hello IPFS world by Web3Coach</code>:</p>
<pre><code>echo <span class="hljs-string">"hello IPFS world by Web3Coach. BTW: Ethereum FTW"</span> | ipfs add
</code></pre><p>The content is now stored and <strong>indexed by a cryptographic hash function</strong> returning its unique content identifier (CID):</p>
<pre><code>&gt; added QmRBkKi1PnthqaBaiZnXML6fH6PNqCFdpcBxGYXoUQfp6z
&gt; <span class="hljs-number">49</span> B / <span class="hljs-number">49</span> B [========] <span class="hljs-number">100</span>%
</code></pre><p>Your IPFS node will generate the same CID on your local file system as in this tutorial. That's because IPFS hashes the content and returns its unique fingerprint, and as we know, a secure hash function will always return the same output given the same input.</p>
<h3 id="heading-pin-content">Pin content</h3>
<p>When you <code>add</code> content, you add it ONLY to your local node. The <strong>content does NOT automatically replicate</strong> across the entire network – this is a common confusion between IPFS users and developers.</p>
<p>When you store content via the <code>add</code> command, IPFS will also execute the <code>pin</code> command by default:</p>
<pre><code>ipfs pin add QmRBkKi1PnthqaBaiZnXML6fH6PNqCFdpcBxGYXoUQfp6z
</code></pre><p>To replicate content, <strong>you must take your node online, join the p2p network, and <code>pin</code> the specific CID from another node.</strong> You will learn how to do this further in the tutorial and find out what happens in the background.</p>
<h3 id="heading-read-content">Read content</h3>
<p>Copy-paste the <strong>CID</strong> to IPFS <code>cat</code> command to read it from disk:</p>
<pre><code>ipfs cat QmRBkKi1PnthqaBaiZnXML6fH6PNqCFdpcBxGYXoUQfp6z
&gt; hello IPFS world by Web3Coach. BTW: Ethereum FTW
</code></pre><p>The <code>add</code> , <code>pin</code> and <code>cat</code> commands are the most significant IPFS functions, and you just learned them. Congrats, well done!</p>
<h2 id="heading-how-ipfs-content-addressing-works">How IPFS Content Addressing Works</h2>
<p>What is QmRBkKi1PnthqaBaiZnXML6fH6PNqCFdpcBxGYXoUQfp6z?</p>
<p>It’s a self-describing content-based identifier.</p>
<p>What does "self-describing" actually mean? It means that by splitting the string following the IPFS specification, you will know everything you need to know about the data it indexes.</p>
<ul>
<li>what CID version it is</li>
<li>how to read the CID string (base32? base58? hex?)</li>
<li>how data is encoded</li>
<li>what hash function fingerprinted the data</li>
<li>the hash function's length</li>
</ul>
<p>The IPFS team built a convenient <a target="_blank" href="https://cid.ipfs.io/">website</a> for analyzing a CID:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/05/cid_analyse.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>By parsing the <strong>QmRBkKi1P…p6z</strong> CID, you discover:</p>
<ul>
<li>the CID follows version 0 spec because it starts with <strong>Qm</strong></li>
<li>the <strong>QmRBkKi1P…p6z</strong> string is encoded using <code>base58btc</code></li>
<li>the data "<strong>hello IPFS world by Web3Coach. BTW: Ethereum FTW</strong>" were encoded as <strong>DAG Protobuf</strong> under a codec <strong>0x70</strong> before being stored on disk</li>
<li>the hash code <strong>0x12</strong> signals the data fingerprint obtained using the <code>sha256</code> hash function, producing a unique 32 byte long digest</li>
</ul>
<p>"Slightly more complicated" than a simple auto-increment INT in a MySQL table... but extraordinarily potent and future proof. Let me explain.</p>
<h3 id="heading-cid-versions">CID Versions</h3>
<p>There are currently two CID versions: <strong>v0</strong> and <strong>v1</strong>.</p>
<p><strong>The CID v0</strong> is not flexible and limited to:</p>
<ul>
<li>start with characters "Qm"</li>
<li>where the CID string is encoded using base58btc</li>
<li>the data is encoded with dag-pb by default</li>
<li>can be converted to CID version 1, but not the other way around</li>
</ul>
<p><strong>The CID v1</strong> leverages several prefixes for maximum interoperability:</p>
<blockquote>
<p>CID v1 = Multibase + Multicodec + Multihash</p>
</blockquote>
<p>In another words, parsing the binary into a CID v1 string follows this spec:</p>
<p><code>&lt;base&gt;&lt;codec&gt;&lt;hash-function&gt;&lt;hash-length&gt;&lt;hash-digest&gt;</code></p>
<h3 id="heading-multihash">Multihash</h3>
<p>To be future-proof and enable different hashing algorithms, IPFS created the following standard:</p>
<p>CODE : SIZE : DIGEST</p>
<pre><code class="lang-go"><span class="hljs-keyword">type</span> DecodedMultihash <span class="hljs-keyword">struct</span> {
   Code   <span class="hljs-keyword">uint64</span> <span class="hljs-comment">// 0x12</span>
   Name   <span class="hljs-keyword">string</span> <span class="hljs-comment">// sha2-256</span>
   Length <span class="hljs-keyword">int</span>    <span class="hljs-comment">// 32 bytes</span>
   Digest []<span class="hljs-keyword">byte</span> <span class="hljs-comment">// Digest holds the raw multihash bytes</span>
}
</code></pre>
<p>Multihash has many advantages. When computers are more powerful in 5 years, you could use a stronger hash function like <code>sha3-512</code> as long as you configure the corresponding <code>0x13</code> code as the Multihash in the CID prefix – the protocol will be ready to handle it.</p>
<h3 id="heading-multicodec">Multicodec</h3>
<p>The <code>Code</code> attribute tells you <strong>how data is encoded</strong> before being stored on disk, so you know <strong>how to decode</strong> it back when the user wants to read it. It could be anything CBOR, Protobuf, JSON…</p>
<p>IPFS maintains a public list of all <a target="_blank" href="https://github.com/multiformats/multicodec/blob/master/table.csv">possible codecs</a>. The most common codecs are:</p>
<pre><code>raw       | ipld      | <span class="hljs-number">0x55</span> | raw binary
dag-pb    | ipld      | <span class="hljs-number">0x70</span> | MerkleDAG protobuf
dag-cbor  | ipld      | <span class="hljs-number">0x71</span> | MerkleDAG cbor

<span class="hljs-comment">// but you could also encode Ethereum blocks on IPFS!</span>
eth-block | ipld      | <span class="hljs-number">0x90</span> | Ethereum Block (RLP)
</code></pre><h3 id="heading-multibase">Multibase</h3>
<p>The problem with CID v0 and the <code>base58btc</code> encoding is the lack of interoperability between environments. A multibase prefix adds support for different encodings like <code>base32</code> to achieve DNS-friendly names.</p>
<p><a target="_blank" href="https://github.com/multiformats/multibase/blob/master/multibase.csv">A table with all Multibase encodings</a>:</p>
<pre><code>encoding  | code
base32    | b
base58btc | z
base64    | m
</code></pre><p>You spot a Multibase encoding based on the first character:</p>
<p><strong>Q</strong>mRBkKi1PnthqaBaiZnXML6fH6PNqCFdpcBxGYXoUQfp6z</p>
<ul>
<li>is CID <code>v0</code></li>
<li>the CID string is encoded with <code>base58btc</code></li>
</ul>
<p><strong>b</strong>afybeibkjmxftowv4lki46nad4arescoqc7kdzfnjkqux257i4jonk44w4</p>
<ul>
<li>CID <code>v1</code></li>
<li>the CID string is encoded with <code>base32</code></li>
</ul>
<p>Both CID versions can retrieve the same content because after you strip the encoding, it's the <strong>Multihash</strong> that indexes the blocks on the datastore level. In contrast, Multibase is only used to pass the CID correctly in different environments (CLI, URL, DNS).</p>
<pre><code>ipfs cat QmRBkKi1PnthqaBaiZnXML6fH6PNqCFdpcBxGYXoUQfp6z
&gt; hello IPFS world by Web3Coach. BTW: Ethereum FTW

<span class="hljs-comment">// equivalent to</span>
ipfs cat bafybeibkjmxftowv4lki46nad4arescoqc7kdzfnjkqux257i4jonk44w4
&gt; hello IPFS world by Web3Coach. BTW: Ethereum FTW
</code></pre><p>Phew. Things got "slightly complex" very quickly.</p>
<p>Speaking of complicated topics, IPFS is powerful because it doesn't treat content as just "data" but as <strong>data structures</strong> – specifically <strong>InterPlanetary Linked Data</strong> structure: <a target="_blank" href="https://docs.ipld.io/#what-is-ipld">IPLD</a>. In short, you can implement any file-system, database, or structure on top of IPLD.</p>
<p>For example, you can store all Ethereum blocks on IPFS as long as you set <code>eth-block</code> and <code>eth-tx</code> codecs and register an appropriate Decoder when working with the IPLD graph.</p>
<p>Let's dig into it and explore the default IPLD structure with the DAG Protobuf codec.</p>
<h2 id="heading-how-ipfs-stores-content-on-the-file-system">How IPFS Stores Content on the File-system</h2>
<p>“The <code>ipfs add</code> command will create a <strong>Merkle DAG</strong> out of the data following the <a target="_blank" href="https://github.com/ipfs/go-unixfs/blob/master/pb/unixfs.proto">UnixFS data format</a>. Your content is broken down into <strong>blocks</strong> using a <strong>Chunker</strong>, and then arranged in a <strong>tree-like structure using 'link nodes'</strong> to tie them together. The returned CID is the hash of the root node in the DAG.”</p>
<p>Confused?</p>
<p>Rolling back to basics.</p>
<h3 id="heading-lets-explore-the-nodes-data-directory">Let's explore the node’s data directory</h3>
<p>At the beginning of this tutorial, when you initialized your IPFS node with the <code>ipfs init</code> command, you generated the following directory:</p>
<pre><code><span class="hljs-keyword">export</span> IPFS_PATH=<span class="hljs-regexp">/home/</span>web3coach/.ipfs_tutorial
cd $IPFS_PATH
~/.ipfs_tutorial  tree

.
├── blocks
│   ├── <span class="hljs-number">6</span>Y
│   │   └── CIQA4XCGRCRTCCHV7XSGAZPZJOAOHLPOI6IQR3H6YQ.data
├── config
├── datastore
│   ├── <span class="hljs-number">000002.</span>ldb
│   ├── <span class="hljs-number">000003.</span>log
│   ├── CURRENT
│   ├── CURRENT.bak
│   ├── LOCK
│   ├── LOG
│   └── MANIFEST<span class="hljs-number">-000004</span>
├── datastore_spec
├── keystore
└── version
</code></pre><p>From a very <strong>high-level point of view:</strong></p>
<ul>
<li><code>blocks</code> — IPFS stores all the chunked data here, although the <code>go-ipfs</code> flexible interfaces <strong>allow you to swap the storage implementation</strong> for a different database</li>
<li><code>config</code> — Node’s settings (file-system, identity, specs, networking)</li>
<li><code>datastore</code> — Indexing and other logic</li>
</ul>
<p>Don't take my word for it. Create a new file with the following content on your local file system and then add it to IPFS:</p>
<pre><code>hello IPFS world by Web3Coach. Testing DAGs
hello IPFS world by Web3Coach. Testing DAGs
hello IPFS world by Web3Coach. Testing DAGs

ls -la hello_world.txt
&gt; <span class="hljs-number">131</span> bytes hello_world.txt

ipfs add hello_world.txt
&gt; added QmNtQtxeavDXTjCiWAAaxnhKK3LBYfFfpXUXjdMDYXwKtH
</code></pre><p>Reverse engineering the <code>go-ipfs</code> codebase, this is what is happening behind the scenes:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/06/IPFS_UNIX_FS_Protobuf.png" alt="Image" width="600" height="400" loading="lazy">
<em>IPFS UnixFS adding a new file and converting it to a block</em></p>
<p>Validate the persistence process by inspecting the blocks directory. You will find the content was written under the Multihash Datastore Key using <strong>DAG Protobuf encoding</strong> (131 bytes + Protobuf extra encoding).</p>
<pre><code>ls -la blocks/PV/
&gt; <span class="hljs-number">142</span> CIQAQIXXW2OAQSKZ6AQ2SDEYRZXWPDZNJUAFR3YORYN75I5CQ3LHPVQ.data

vim blocks/PV/CIQA...
&lt;<span class="hljs-number">8</span>b&gt;^A^H^B^R&lt;<span class="hljs-number">83</span>&gt;^Ahello IPFS world by Web3Coach. Testing DAGs
hello IPFS world by Web3Coach. Testing DAGs
hello IPFS world by Web3Coach. Testing DAGs^X&lt;<span class="hljs-number">83</span>&gt;^A
</code></pre><p>To interact with your raw content, use the <code>ipfs object</code> command.</p>
<pre><code>ipfs object get QmNtQtxeavDXTjCiWAAaxnhKK3LBYfFfpXUXjdMDYXwKtH | jq
</code></pre><pre><code class="lang-json">{
  <span class="hljs-attr">"Links"</span>: [],
  <span class="hljs-attr">"Data"</span>: <span class="hljs-string">"\b\u0002\u0012�\u0001hello IPFS world by Web3Coach. Testing DAGs\nhello IPFS world by Web3Coach. Testing DAGs\nhello IPFS world by Web3Coach. Testing DAGs\u0018�\u0001"</span>
}
</code></pre>
<ul>
<li>Because the content is only 131 bytes, it fits to one DAG Node</li>
<li>The Dag Node is persisted as one Block on disk</li>
<li>The DAG Node has zero links to other Nodes</li>
</ul>
<p>Time to experiment.</p>
<p>Add the same file again, but configure the Chunker to 64 bytes (or use a bigger file, but a smaller Chunker will demonstrate the concept better).</p>
<pre><code>ipfs add --chunker=size<span class="hljs-number">-64</span> hello_world.txt

&gt; <span class="hljs-number">131</span> bytes QmTwtTQgrTaait2qWXYjTsEZiF4sT7CD4U87VqQ27Wnsn8
</code></pre><p><strong>You get a new CID!</strong> </p>
<p>IPFS split the content into 4 DAG Nodes and wrote 4 Blocks with data encoded in DAG Protobuf format to disk.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/05/ipfs_chunker_4.png" alt="Image" width="600" height="400" loading="lazy">
<em>IPFS splits a file into multiple chunks (DAG Nodes + Blocks)</em></p>
<pre><code>ipfs object get QmTwtTQgrTaait2qWXYjTsEZiF4sT7CD4U87VqQ27Wnsn8 | jq
</code></pre><pre><code class="lang-json">{
  <span class="hljs-attr">"Links"</span>: [
    {
      <span class="hljs-attr">"Name"</span>: <span class="hljs-string">""</span>,
      <span class="hljs-attr">"Hash"</span>: <span class="hljs-string">"QmTbsuUYzy3nT6NApb5t7VUq3iQKZXrJJJY2j1miMVgaJU"</span>,
      <span class="hljs-attr">"Size"</span>: <span class="hljs-number">72</span>
    },
    {
      <span class="hljs-attr">"Name"</span>: <span class="hljs-string">""</span>,
      <span class="hljs-attr">"Hash"</span>: <span class="hljs-string">"QmNy9iFF8uU1Cn7trxpSgqxMsjmi4zQ7xgyEgsWff5rnfH"</span>,
      <span class="hljs-attr">"Size"</span>: <span class="hljs-number">72</span>
    },
    {
      <span class="hljs-attr">"Name"</span>: <span class="hljs-string">""</span>,
      <span class="hljs-attr">"Hash"</span>: <span class="hljs-string">"QmdEitCfYgBNxLhxTNvdLaDmTypSAWkGErjw33VZxUbWK3"</span>,
      <span class="hljs-attr">"Size"</span>: <span class="hljs-number">11</span>
    }
  ],
  <span class="hljs-attr">"Data"</span>: <span class="hljs-string">"\b\u0002\u0018�\u0001 @ @ \u0003"</span>
}
</code></pre>
<p>The ultimate test is to retrieve each DAG Node's data and verify the text is split into three chunks:</p>
<p><strong>DAG Protobuf Node 1:</strong></p>
<pre><code>ipfs object get QmTbsuUYzy3nT6NApb5t7VUq3iQKZXrJJJY2j1miMVgaJU | jq
</code></pre><pre><code class="lang-json">{
  <span class="hljs-attr">"Links"</span>: [],
  <span class="hljs-attr">"Data"</span>: <span class="hljs-string">"\b\u0002\u0012@hello IPFS world by Web3Coach. Testing DAGs\nhello IPFS world by \u0018@"</span>
}
</code></pre>
<p><strong>DAG Protobuf Node 2:</strong></p>
<pre><code>ipfs object get QmNy9iFF8uU1Cn7trxpSgqxMsjmi4zQ7xgyEgsWff5rnfH | jq
</code></pre><pre><code class="lang-json">{
  <span class="hljs-attr">"Links"</span>: [],
  <span class="hljs-attr">"Data"</span>: <span class="hljs-string">"\b\u0002\u0012@Web3Coach. Testing DAGs\nhello IPFS world by Web3Coach. Testing D\u0018@"</span>
}
</code></pre>
<p><strong>DAG Protobuf Node 3:</strong></p>
<pre><code>ipfs object get QmdEitCfYgBNxLhxTNvdLaDmTypSAWkGErjw33VZxUbWK3 | jq
</code></pre><pre><code class="lang-json">{
  <span class="hljs-attr">"Links"</span>: [],
  <span class="hljs-attr">"Data"</span>: <span class="hljs-string">"\b\u0002\u0012\u0003AGs\u0018\u0003"</span>
}
</code></pre>
<h3 id="heading-whats-the-benefit-of-splitting-the-content-into-multiple-chunks-and-use-content-addressing-and-cids">What’s the benefit of splitting the content into multiple chunks and use content-addressing and CIDs?</h3>
<ul>
<li>Data deduplication</li>
<li>Decentralization</li>
</ul>
<p>Next time you want to store a file that would share part of the content with another file, IPFS wouldn't store a duplicate block! It would instead link to an already existing DAG Node and only store the new, unique chunks.</p>
<p>Converting content to a directed acyclic graph with many nodes also helps to load the content in parallel. For example, a blog post, image, entire Wikipedia website can load from multiple IPFS peer nodes. Your node then verifies the integrity of received blocks by re-hashing all the data content and asserting the constructed CID.</p>
<p>You've now learned the bread and butter of IPFS – excellent progress!</p>
<p>One more critical component left: <strong>Networking</strong>.</p>
<h2 id="heading-how-to-connect-an-ipfs-node-to-the-p2p-network">How to Connect an IPFS Node to the p2p Network</h2>
<p>Every node has its <code>config</code> file generated during the <code>ipfs init</code> execution.</p>
<p>Open it.</p>
<pre><code>vim $IPFS_PATH/config
</code></pre><p>Other settings aside, you find your node’s <strong>Identity (PeerID + Private Key):</strong></p>
<pre><code><span class="hljs-string">"Identity"</span>: {
    <span class="hljs-string">"PeerID"</span>: <span class="hljs-string">"12D3KooWCBmDtsvFwDHEr..."</span>,
    <span class="hljs-string">"PrivKey"</span>: <span class="hljs-string">"CAESQCj..."</span>
  },
</code></pre><p>And a list of <strong>Bootstrap addresses:</strong></p>
<pre><code class="lang-json"><span class="hljs-string">"Bootstrap"</span>: [
    <span class="hljs-string">"/dnsaddr/bootstrap.libp2p.io/p2p/QmcZf59b...gU1ZjYZcYW3dwt"</span>,
    <span class="hljs-string">"/ip4/104.131.131.82/tcp/4001/p2p/QmaCpDMG...UtfsmvsqQLuvuJ"</span>,
    <span class="hljs-string">"/ip4/104.131.131.82/udp/4001/quic/p2p/Qma...UtfsmvsqQLuvuJ"</span>,
    <span class="hljs-string">"/dnsaddr/bootstrap.libp2p.io/p2p/QmNnooD5...BMjTezGAJN"</span>,
    <span class="hljs-string">"/dnsaddr/bootstrap.libp2p.io/p2p/QmQCU2Ec...J16u19uLTa"</span>,
    <span class="hljs-string">"/dnsaddr/bootstrap.libp2p.io/p2p/QmbLHAnM...Ucqanj75Nb"</span>
  ],
</code></pre>
<p>You connect to other peers in the IPFS network by running the <code>ipfs daemon</code> command. Your node will first establish a p2p connection with Protocol Labs (company behind IPFS) bootstrap nodes, and through these bootstrap nodes, you will further find hundreds of other peers.</p>
<pre><code>ipfs daemon 

&gt; Initializing daemon...

Swarm listening on /ip4/<span class="hljs-number">127.0</span><span class="hljs-number">.0</span><span class="hljs-number">.1</span>/tcp/<span class="hljs-number">4001</span>
Swarm listening on /ip4/<span class="hljs-number">127.0</span><span class="hljs-number">.0</span><span class="hljs-number">.1</span>/udp/<span class="hljs-number">4001</span>/quic
Swarm listening on /ip4/<span class="hljs-number">172.17</span><span class="hljs-number">.0</span><span class="hljs-number">.1</span>/tcp/<span class="hljs-number">4001</span>
Swarm listening on /ip4/<span class="hljs-number">172.17</span><span class="hljs-number">.0</span><span class="hljs-number">.1</span>/udp/<span class="hljs-number">4001</span>/quic
Swarm listening on /ip4/<span class="hljs-number">192.168</span><span class="hljs-number">.0</span><span class="hljs-number">.142</span>/tcp/<span class="hljs-number">4001</span>
Swarm listening on /ip4/<span class="hljs-number">192.168</span><span class="hljs-number">.0</span><span class="hljs-number">.142</span>/udp/<span class="hljs-number">4001</span>/quic
Swarm listening on /ip6/::<span class="hljs-number">1</span>/tcp/<span class="hljs-number">4001</span>
Swarm listening on /ip6/::<span class="hljs-number">1</span>/udp/<span class="hljs-number">4001</span>/quic
Swarm listening on /p2p-circuit
Swarm announcing /ip4/<span class="hljs-number">127.0</span><span class="hljs-number">.0</span><span class="hljs-number">.1</span>/tcp/<span class="hljs-number">4001</span>
Swarm announcing /ip4/<span class="hljs-number">127.0</span><span class="hljs-number">.0</span><span class="hljs-number">.1</span>/udp/<span class="hljs-number">4001</span>/quic
Swarm announcing /ip4/<span class="hljs-number">192.168</span><span class="hljs-number">.0</span><span class="hljs-number">.142</span>/tcp/<span class="hljs-number">4001</span>
Swarm announcing /ip4/<span class="hljs-number">192.168</span><span class="hljs-number">.0</span><span class="hljs-number">.142</span>/udp/<span class="hljs-number">4001</span>/quic
Swarm announcing /ip4/<span class="hljs-number">88.212</span><span class="hljs-number">.40</span><span class="hljs-number">.160</span>/udp/<span class="hljs-number">4001</span>/quic
Swarm announcing /ip6/::<span class="hljs-number">1</span>/tcp/<span class="hljs-number">4001</span>
Swarm announcing /ip6/::<span class="hljs-number">1</span>/udp/<span class="hljs-number">4001</span>/quic

API server listening on /ip4/<span class="hljs-number">127.0</span><span class="hljs-number">.0</span><span class="hljs-number">.1</span>/tcp/<span class="hljs-number">5001</span>
<span class="hljs-attr">WebUI</span>: http:<span class="hljs-comment">//127.0.0.1:5001/webui</span>

Gateway (readonly) server listening on /ip4/<span class="hljs-number">127.0</span><span class="hljs-number">.0</span><span class="hljs-number">.1</span>/tcp/<span class="hljs-number">8080</span>
Daemon is ready!
</code></pre><p>Keep in mind, that by running the <strong>IPFS Daemon</strong>:</p>
<ol>
<li>Your node connects to the p2p net and can <strong>exchange blocks with other nodes</strong></li>
<li><strong>Other peers can access the content on your node</strong> – as long they know the CIDs</li>
<li>Peers will talk to you through TCP, UDP on port: <strong>4001</strong></li>
<li>If you have an application, start storing and consuming your node's content via the HTTP API listening on port: <strong>5001</strong>.</li>
</ol>
<p>For application development, I recommend the official <a target="_blank" href="https://www.npmjs.com/package/ipfs-http-client">ipfs-http-client</a> library in JS exposing all the core commands – add, cat, object and others. It will speed up your coding progress.</p>
<p>I will use <code>curl</code> to interact with the API to keep this tutorial "short."</p>
<h3 id="heading-how-to-use-the-ipfs-http-api">How to use the IPFS HTTP API:</h3>
<p><strong>Add content:</strong> :5001/api/v0/add</p>
<pre><code>curl -X POST -F file=@/home/web3coach/go/src/github.com/ipfs/go-ipfs/hello_world.txt <span class="hljs-string">"http://127.0.0.1:5001/api/v0/add"</span>
</code></pre><pre><code class="lang-json">{<span class="hljs-attr">"Name"</span>:<span class="hljs-string">"hello_world.txt"</span>,<span class="hljs-attr">"Hash"</span>:<span class="hljs-string">"QmNtQtxeavDXTjCiWAAaxnhKK3LBYfFfpXUXjdMDYXwKtH"</span>,<span class="hljs-attr">"Size"</span>:<span class="hljs-string">"142"</span>}
</code></pre>
<p><strong>Read content:</strong> :5001/api/v0/cat</p>
<pre><code>curl -X POST <span class="hljs-string">"http://127.0.0.1:5001/api/v0/cat?arg=QmNtQtxeavDXTjCiWAAaxnhKK3LBYfFfpXUXjdMDYXwKtH"</span>

hello IPFS world by Web3Coach. Testing DAGs
hello IPFS world by Web3Coach. Testing DAGs
hello IPFS world by Web3Coach. Testing DAGs
</code></pre><p>See the <a target="_blank" href="https://docs.ipfs.io/reference/http/api/#getting-started">official HTTP API docs</a> for the complete list of available commands.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/05/Screenshot-from-2021-05-26-19-54-49.png" alt="Image" width="600" height="400" loading="lazy"></p>
<h3 id="heading-how-to-peer-with-other-ipfs-nodes">How to peer with other IPFS nodes</h3>
<p>Fun experiment. Use the <code>ipfs swarm</code> command and check how many nodes you already discovered:</p>
<pre><code>ipfs swarm peers

&gt; 
<span class="hljs-regexp">/ip4/</span><span class="hljs-number">85.70</span><span class="hljs-number">.151</span><span class="hljs-number">.37</span>/tcp/<span class="hljs-number">4001</span>/p2p/QmSuCtR...aPq6h4AczBPZaoej
/ip4/<span class="hljs-number">91.121</span><span class="hljs-number">.168</span><span class="hljs-number">.96</span>/udp/<span class="hljs-number">54001</span>/quic/p2p/QmeC7H..<span class="hljs-number">.8</span>j2TQ99esS
...
...
...

ipfs swarm peers | wc -l
&gt; <span class="hljs-number">186</span>
</code></pre><p>Bravo! You are connected to 186 peers forming an unstoppable peer-to-peer web.</p>
<h3 id="heading-what-about-privacy">What about privacy?</h3>
<p>Other peers can access all the content you add to your IPFS node. There is <strong>no built-in privacy mechanism, so never add unencrypted, sensitive/personal content</strong> to IPFS!</p>
<h2 id="heading-how-nodes-exchange-data-using-the-bitswap-protocol">How Nodes Exchange Data Using the Bitswap Protocol</h2>
<p>So far, you only interacted with your local content. Imagine you live in a place where the local government decided to block access to Wikipedia. No bueno. </p>
<p>Fortunately, because someone added all the Wikipedia content to IPFS, you can run your node and access its knowledge by requesting the content from peers across the globe.</p>
<p><a target="_blank" href="http://localhost:8080/ipfs/QmT5NvUtoM5nWFfrQdVrFtvGfKFmG7AHE8P34isapyhCxX/wiki/Anasayfa.html">http://localhost:8080/ipfs/QmT5NvUtoM5nWFfrQdVrFtvGfKFmG7AHE8P34isapyhCxX/wiki/Anasayfa.html</a></p>
<p>The DAG Service will check the blocks in your datastore, but it won’t find any for QmT5NvUtoM5nWFfrQdVrFtvGfKFmG7AHE8P34isapyhCxX.</p>
<p>The node will therefore create a network request to its peers using the Bitswap protocol via <code>exchange</code> component:</p>
<pre><code class="lang-go"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">getBlock</span><span class="hljs-params">(ctx context.Context, c cid.Cid, bs blockstore.Blockstore, fget <span class="hljs-keyword">func</span>()</span> <span class="hljs-title">exchange</span>.<span class="hljs-title">Fetcher</span>) <span class="hljs-params">(blocks.Block, error)</span></span> {
   err := verifcid.ValidateCid(c) <span class="hljs-comment">// hash security</span>
   <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
      <span class="hljs-keyword">return</span> <span class="hljs-literal">nil</span>, err
   }

   block, err := bs.Get(c)
   <span class="hljs-keyword">if</span> err == <span class="hljs-literal">nil</span> {
      <span class="hljs-keyword">return</span> block, <span class="hljs-literal">nil</span>
   }

   <span class="hljs-keyword">if</span> err == blockstore.ErrNotFound &amp;&amp; fget != <span class="hljs-literal">nil</span> {
      f := fget() <span class="hljs-comment">// Don't load the exchange until we have to</span>

      log.Debug(<span class="hljs-string">"Blockservice: Searching bitswap"</span>)
      blk, err := f.GetBlock(ctx, c)
</code></pre>
<p>Internally, the CID is added to a <code>Wantlist</code> :</p>
<pre><code class="lang-go"><span class="hljs-comment">// Wantlist is a raw list of wanted blocks and their priorities</span>
<span class="hljs-keyword">type</span> Wantlist <span class="hljs-keyword">struct</span> {
   set <span class="hljs-keyword">map</span>[cid.Cid]Entry
}

<span class="hljs-comment">// Entry is an entry in a want list, consisting of a cid and its priority</span>
<span class="hljs-keyword">type</span> Entry <span class="hljs-keyword">struct</span> {
   Cid      cid.Cid
   Priority <span class="hljs-keyword">int32</span>
   WantType pb.Message_Wantlist_WantType
}
</code></pre>
<p>And the <code>PeerManager</code> will iterate over known peers and their peers until it finds an online node capable of providing the wanted Block:</p>
<pre><code class="lang-go"><span class="hljs-comment">// PeerManager manages a pool of peers and sends messages to peers in the pool.</span>
<span class="hljs-keyword">type</span> PeerManager <span class="hljs-keyword">struct</span> {
   pqLk sync.RWMutex

   peerQueues <span class="hljs-keyword">map</span>[peer.ID]PeerQueue
   pwm        *peerWantManager

   createPeerQueue PeerQueueFactory
   ctx             context.Context

   psLk         sync.RWMutex
   sessions     <span class="hljs-keyword">map</span>[<span class="hljs-keyword">uint64</span>]Session
   peerSessions <span class="hljs-keyword">map</span>[peer.ID]<span class="hljs-keyword">map</span>[<span class="hljs-keyword">uint64</span>]<span class="hljs-keyword">struct</span>{}

   self peer.ID
}
</code></pre>
<p>The result?</p>
<p>You can consume the forbidden fruits from Wikipedia directly from <strong>localhost:8080</strong>:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/05/wikipedia_local_ipfs.png" alt="Image" width="600" height="400" loading="lazy">
<em>IPFS loading Wikipedia on your local node</em></p>
<p>Uncensorable, decentralized storage :)</p>
<h2 id="heading-how-to-persist-content-from-the-p2p-network">How to Persist Content from the p2p Network</h2>
<p>You must know a crucial thing about IPFS: the content you access from the network will be garbage collected unless you <strong>pin</strong> it.</p>
<h3 id="heading-pinning-and-garbage-collection">Pinning and Garbage Collection</h3>
<p>At the beginning of the article you learned that content added to your node via the <code>ipfs add</code> command or its HTTP equivalent is pinned by default.</p>
<pre><code>ipfs pin ls | grep QmNtQtxeavDXTjCiWAAaxnhKK3LBYfFfpXUXjdMDYXwKtH
&gt; QmNtQtxeavDXTjCiWAAaxnhKK3LBYfFfpXUXjdMDYXwKtH recursive
</code></pre><p><strong>Pinned blocks are marked as NOT TO BE DELETED</strong> when the Garbage Collection runs.</p>
<p>Why would the Garbage Collection delete some blocks? To keep your node healthy by controlling its storage size.</p>
<p>By reading Wikipedia or by accessing any other content from the p2p network, IPFS downloads its blocks. As the node's datastore grows in size, a periodic garbage collection process will prune unpinned blocks, so you don't run out of disk space.</p>
<p>If you want your content to be accessible 24/7 on the IPFS network, I recommend that you use a reliable remote provider to pin it: <strong><a target="_blank" href="https://infura.io/docs/ipfs?utm_source=web3coach&amp;utm_medium=article">Infura</a> -</strong> is the easiest way to get started, and you get 5GB free of decentralized storage.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/06/Screenshot-from-2021-06-16-09-24-58.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Follow the <a target="_blank" href="https://infura.io/docs/ipfs?utm_source=web3coach&amp;utm_medium=article">getting started docs.</a></p>
<h3 id="heading-how-to-pin-wikipedia-locally">How to pin Wikipedia locally</h3>
<p>Verify that the Wikipedia root-level CID (highest DAG node) isn't yet pinned on your node:</p>
<pre><code>ipfs pin ls | grep QmT5NvUtoM5nWFfrQdVrFtvGfKFmG7AHE8P34isapyhCxX
&gt; no output, not pinned
</code></pre><p>IPFS stores specific versions of Wikipedia in the form of a DAG. I recommend inspecting its graph before pinning:</p>
<pre><code>ipfs object get QmT5NvUtoM5nWFfrQdVrFtvGfKFmG7AHE8P34isapyhCxX | jq
</code></pre><pre><code class="lang-json">{
  <span class="hljs-attr">"Links"</span>: [
    {
      <span class="hljs-attr">"Name"</span>: <span class="hljs-string">"0C-"</span>,
      <span class="hljs-attr">"Hash"</span>: <span class="hljs-string">"QmSEwJo8Z5bqVX3AhocyimJzPWetr7HgbWbwCg6zbp43AP"</span>,
      <span class="hljs-attr">"Size"</span>: <span class="hljs-number">1248085</span>
    },
    {
      <span class="hljs-attr">"Name"</span>: <span class="hljs-string">"43I"</span>,
      <span class="hljs-attr">"Hash"</span>: <span class="hljs-string">"QmPW3kRjncDj145bP9DVNc791FowLPwYHnqbTzfe3whdyZ"</span>,
      <span class="hljs-attr">"Size"</span>: <span class="hljs-number">2611324931</span>
    },
    {
      <span class="hljs-attr">"Name"</span>: <span class="hljs-string">"58wiki"</span>,
      <span class="hljs-attr">"Hash"</span>: <span class="hljs-string">"QmRNXpMRzsTHdRrKvwmWisgaojGKLPqHxzQfrXdfNkettC"</span>,
      <span class="hljs-attr">"Size"</span>: <span class="hljs-number">12295304394</span>
    },
    {
      <span class="hljs-attr">"Name"</span>: <span class="hljs-string">"92M"</span>,
      <span class="hljs-attr">"Hash"</span>: <span class="hljs-string">"Qmbcvk7jpBTUKdgex139Nvv7BrKocE3pQVKhNJtTU77Qv5"</span>,
      <span class="hljs-attr">"Size"</span>: <span class="hljs-number">793</span>
    },
    {
      <span class="hljs-attr">"Name"</span>: <span class="hljs-string">"A0index.html"</span>,
      <span class="hljs-attr">"Hash"</span>: <span class="hljs-string">"QmNqbYogAxH4mmt5WhuKN7NFEUDZ9V3Scxh7QbLwTKBJDk"</span>,
      <span class="hljs-attr">"Size"</span>: <span class="hljs-number">191</span>
    }
  ],
  <span class="hljs-attr">"Data"</span>: <span class="hljs-string">"\b\u0005\u0012\u0015\u0001\u0000\u0004\u0000\u0000\u0000\u0000\u0000\u0000\u0001\u0000\u0000\b\u0000\u0000\u0000\u0000\u0000\u0000\u0010\u0000(\"0�\u0002"</span>
}
</code></pre>
<p>The root DAG object has five links. Four links are relatively small, but <strong>one link points to a DAG node with a total size of 12GB.</strong> If you inspect this DAG node, you will see 256 more links and a total cumulative (recursive) size of 12GB.</p>
<pre><code>ipfs object stat QmRNXpMRzsTHdRrKvwmWisgaojGKLPqHxzQfrXdfNkettC

<span class="hljs-attr">NumLinks</span>:       <span class="hljs-number">256</span>
<span class="hljs-attr">BlockSize</span>:      <span class="hljs-number">12075</span>
<span class="hljs-attr">LinksSize</span>:      <span class="hljs-number">12034</span>
<span class="hljs-attr">DataSize</span>:       <span class="hljs-number">41</span>
<span class="hljs-attr">CumulativeSize</span>: <span class="hljs-number">12295304394</span>
</code></pre><p>Every node with an important pinned article, video, documentary, or a cat meme makes the web more accessible, antifragile, decentralized, and robust.</p>
<pre><code>ipfs pin add QmT5NvUtoM5nWFfrQdVrFtvGfKFmG7AHE8P34isapyhCxX
</code></pre><p>The pinning process will recursively traverse the entire DAG node, fetch all its links from the Bitswap protocol and then pin every single Block to your local datastore.</p>
<p>Congratulations! In this article, you learned how decentralized storage works behind the scenes.</p>
<h3 id="heading-i-worked-47-hours-to-write-this-blog-post-but-you-can-re-tweet-it-in-just-5-seconds">I worked 47 hours to write this blog post… but you can re-tweet it in just 5 seconds:</h3>
<div class="embed-wrapper">
        <blockquote class="twitter-tweet">
          <a href="https://twitter.com/Web3Coach/status/1406997483281174528"></a>
        </blockquote>
        <script defer="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script></div>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ From Zero to Interplanetary Hero ]]>
                </title>
                <description>
                    <![CDATA[ By Carson Farmer A fun guide to getting started with browser-based ĐApps on IPFS _[â€œIf you can read this, congratulationsâ€”the archive youâ€™re using still knows about the mouseover textâ€!](https://xkcd.com/1683/" rel="noopener" target="blank" ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/from-zero-to-interplanetary-hero-7e62f7d4427/</link>
                <guid isPermaLink="false">66c34aef0fa3812cdd5ea9c1</guid>
                
                    <category>
                        <![CDATA[ Blockchain ]]>
                    </category>
                
                    <category>
                        <![CDATA[ dapps ]]>
                    </category>
                
                    <category>
                        <![CDATA[ ipfs ]]>
                    </category>
                
                    <category>
                        <![CDATA[ General Programming ]]>
                    </category>
                
                    <category>
                        <![CDATA[ technology ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Thu, 21 Jun 2018 18:53:56 +0000</pubDate>
                <media:content url="https://cdn-media-1.freecodecamp.org/images/1*GGQAuJS_S0gonQc3goq0Vw.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Carson Farmer</p>
<h4 id="heading-a-fun-guide-to-getting-started-with-browser-based-dapps-on-ipfs">A fun guide to getting started with browser-based ĐApps on IPFS</h4>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*GGQAuJS_S0gonQc3goq0Vw.png" alt="Image" width="800" height="304" loading="lazy">
_[â€œIf you can read this, congratulationsâ€”the archive youâ€™re using still knows about the mouseover textâ€!](https://xkcd.com/1683/" rel="noopener" target="<em>blank" title=")</em></p>
<p><a target="_blank" href="https://en.wikipedia.org/wiki/DAPP">ĐApps</a>, or decentralized apps, are all the rage right now, particularly over on the <a target="_blank" href="https://www.ethereum.org/">Etherium blockchain</a>. But did you know that ĐApps can also run on the <a target="_blank" href="https://ipfs.io/">Interplanatary File System (IPFS)</a>? You bet, and it’s a lot easier than you might think to get one up and going quickly.</p>
<p>In this post, we’re going to go through the steps required to get an IPFS-based ĐApp going quickly, and easily. We’re going to take advantage of some cool new <a target="_blank" href="https://blog.ipfs.io/35-ipfs-companion-2-2-0/#hn2">IPFS browser tools</a>, and my favorite online comic. In doing so, we’re going to help archive a precious resource (<a target="_blank" href="https://xkcd.com/">xkcd</a>!) for future visitors. So this post has it all: intrigue, excitement, and a commitment to the future of the web!</p>
<h3 id="heading-archiving-the-gems-of-the-web">Archiving the gems of the web</h3>
<p>The goal for this tutorial is to create a distributed web ‘clone’ of the <a target="_blank" href="https://xkcd.com/">xkcd website</a>. We’re going to use IPFS to fetch images from an archive of xkcd comics, and display them in a form familiar to fans of xkcd.</p>
<p>There are several reasons why we might want to do something like this. One, I like xkcd comics, and am always looking for an excuse to play around with them. Two, xkcd, along with several other archived resources, are available via <a target="_blank" href="https://archives.ipfs.io/">the IPFS archives</a>, which make them a handy example. Three, and this one is important, building content-based ĐApp on top of IPFS can help to archive the web!</p>
<p>What do I mean by that? Well, trends change, interests wain, and the Internet is a fickle place. Couple this with the increasing costs of maintaining servers, updating infrastructure, and keeping up with the latest trends, and you’ve got a recipe for dead links. IPFS and the distributed web is a great way to help combat <a target="_blank" href="https://en.wikipedia.org/wiki/Link_rot">link rot</a>.</p>
<p>Take our xkcd ĐApp for example. In a moment, we’re going to write some very simple JavaScript that will load a random xkcd comic each time our ĐApp is accessed. And so every time someone visits the ĐApp, the peer running in their browser fetches that comic, and temporarily caches that item, making it possible for others to retrieve it as well. In fact, the more we use the ĐApp, the better it is able to distribute and archive xkcd.</p>
<blockquote>
<p>The more we access and use things on the distributed web via IPFS, the more likely they are to stick around long-term — <a target="_blank" href="https://twitter.com/home?status=The%20more%20we%20access%20and%20use%20things%20on%20the%20distributed%20web%20via%20IPFS,%20the%20more%20likely%20they%20are%20to%20stick%20around%20long-term%20-%20%40carsonfarmer%20https%3A//medium.com/%40carsonfarmer/from-zero-to-interplanetary-hero-7e62f7d4427">tweet it</a></p>
</blockquote>
<p>This is a really powerful idea: the more we access and use things on the distributed web via IPFS, the more likely they are to stick around long-term. And what about things that are important but less <em>popular</em> (like historical documents)? This is where things like <a target="_blank" href="https://filecoin.io/">Filecoin</a> will help to pick up the slack. In the <a target="_blank" href="https://coincentral.com/filecoin-beginners-guide-largest-ever-ico/">filecoin world</a>, rather than relying on popularity to preserve documents and files, you can pay the network to store these things for you. It’s a very cool idea.</p>
<h3 id="heading-getting-started">Getting started</h3>
<p>For those of you who can’t wait, the full ĐApp is available from the <a target="_blank" href="https://github.com/textileio/xkcd-dapp-demo">Textile GitHub repo</a>. Feel free to clone that, and follow along with the code to make getting started easier. And since you’ve just saved yourself some time, why not <a target="_blank" href="https://www.youtube.com/watch?v=HUVmypx9HGI">watch this great video</a> on the IPFS vision by Juan Benet before moving on. You can also check out a <a target="_blank" href="https://ipfs.carsonfarmer.com/ipfs/QmYDEzjNKm6ZMCmQVVRAJqPnGL2H7c4EK81LBTK3GC4kCh/">‘live’ version here</a>.</p>
<p>For those of you who want a step-by-step approach, here are a few setup steps to get you started.</p>
<p>First, clone our vanilla IPFS <a target="_blank" href="https://github.com/textileio/dapp-template">Dapp Template</a>, and change into the new directory:</p>
<pre><code>git clone https:<span class="hljs-comment">//github.com/textileio/dapp-template.git xkcd-dappcd xkcd-dapp</span>
</code></pre><p>This template is pretty simple, and has fairly minimal <a target="_blank" href="https://github.com/textileio/dapp-template/blob/carson/xkcd-demo/package.json">dependencies</a>. Most of the dev dependencies are just for transpiling JavaScript so that we can run our ĐApp in the browser. For details on all those packages, refer to their respective GitHub repos, or <a target="_blank" href="https://www.textile.io/">get in touch</a> to ask a question or two.</p>
<p>So first things first, check out the <code>README.md</code> file from the repo. You’ll notice it says this app works best with <code>window.ipfs</code>, and that you can install the <a target="_blank" href="https://github.com/ipfs-shipyard/ipfs-companion">IPFS Companion</a> web extension by clicking on one of the links.</p>
<p>The IPFS Companion is a browser extension that simplifies access to IPFS resources by running a <a target="_blank" href="https://github.com/ipfs/js-ipfs">JavaScript IPFS peer</a> in your browser. Even better than this, it can expose an embedded IPFS node as <code>window.ipfs</code> on every webpage! This makes it possible for our ĐApp to detect if <code>window.ipfs</code> exists and opt-in to use it instead of creating our own one-off <code>js-ipfs</code> node. It is not <em>required</em> for running ĐApps, but it does make them run better (faster), and I highly recommend installing it.</p>
<p>But, we can’t expect the users of our ĐApp to install a browser extension before being able to use our ĐApp. So there is a nice JavaScript module called <code>[window.ipfs-fallback](https://github.com/tableflip/window.ipfs-fallback)</code>, which will detect the presence of <code>window.ipfs</code> and automatically fall back to downloading the <a target="_blank" href="https://unpkg.com/ipfs/dist/index.min.js">latest version of IPFS</a> from the CDN if it’s unavailable. So when building a ĐApp, it’s always a good idea to include this — and you get <code>window.ipfs</code> for free if available. Nice!</p>
<p>Ok, so just to make sure things are working nicely, let’s go ahead and install our required dependencies, and build and run our ĐApp locally. Enter the following into your terminal:</p>
<pre><code>yarn installyarn buildyarn start
</code></pre><p>You should see a pretty minimal (blank page) ĐApp with a footer and not much else. Now go ahead and open your Javascript developer console (Chrome:Ctl+Shift+J(Command+Option+Jon Mac), Firefox: Ctrl+Shift+K(Command+Option+Kon Mac), Safari: Command+Option+I). You should see something like <code>running js-ipfs/0.29.2 with ID Qm{hash}</code> where <code>Qm{hash}</code> is a long alphanumeric hash that represents your peer id.</p>
<p>Congrats, you are successfully running a ĐApp on the decentralized web! Now let’s make it do something interesting…</p>
<h3 id="heading-fetching-data-on-the-distributed-web">Fetching data on the distributed web</h3>
<p>Ok, let’s add some functionality to our ĐApp. We’ll start by simply fetching a random xkcd comic and displaying it on a blank page. Simple enough right? First, rather than <code>yarn start</code>ing our app, let’s <code>yarn watch</code> it so that any changes we make to the JavaScript will automatically be reflected when we refresh our browser window.</p>
<p>Now, you can go ahead and modify the <code>setup</code> function in <code>src/main.js</code> with the following code:</p>
<p>There’s a lot to parse there, but basically what is happening is:</p>
<ul>
<li>Lines 3 &amp; 5 are defining <em>which</em> random comic to fetch (<a target="_blank" href="https://ipfs.io/ipfs/QmWEAXcqwq5zY2u8Z1mii5m3MXricctd7efFep7sSEWZQz">from our archive</a>)</li>
<li>Lines 8 &amp; 10 are initializing an IPFS peer node, and connecting to a peer known to be pinning the xkcd archive (this second step isn’t always required, but I added it here to help bootstrap the ĐApp)</li>
<li>Line 14 is really the IPFS ‘magic’…it is fetching the files at the given CID and returning a promise, which we await and then do some work with in lines 15 to 27…</li>
<li>Lines 15 &amp; 16 simply loop through the binary objects returned from the previous step, and look for the actual png image</li>
<li>Lines 18 &amp; 20 convert the binary image data to a base64 encode string</li>
<li>And finally, lines 22 through 27 create an image element and add it to the ‘main’ div for display.</li>
</ul>
<p>Done!</p>
<h3 id="heading-cleaning-things-up">Cleaning things up</h3>
<p>From here, any additional changes are simply to make the ĐApp look and feel more like the original xkcd comic webpage.</p>
<p>I won’t go into the details in this post, but you can take a look in the <a target="_blank" href="https://github.com/textileio/xkcd-dapp-demo">xkcd-dapp-demo</a> repo for the full code example. There, I’ve added the nav buttons and styling from the xkcd website, along with some links to <a target="_blank" href="https://ipfs.io/ipfs/QmWEAXcqwq5zY2u8Z1mii5m3MXricctd7efFep7sSEWZQz/about.html">proper attribution</a>, <a target="_blank" href="https://ipfs.io/ipfs/QmWEAXcqwq5zY2u8Z1mii5m3MXricctd7efFep7sSEWZQz/license.html">license information</a>, and other goodies. We even have the fun hover comments! It’s almost all vanilla ES6 JavaScript, and I take good advantage of <a target="_blank" href="https://davidwalsh.name/async-await">async/await patterns</a> to make the code nice and readable.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*2DSOGJ4sBp5Njb7hN3RF_Q.png" alt="Image" width="800" height="645" loading="lazy"></p>
<p>So as you can see, it is relatively easy to get started making ĐApps on IPFS. Our xkcd ĐApp works best when run a) locally (via <code>yarn start</code> for example), and b) with the IPFS Companion browser extension enabled. If you want, you can actually fire up a local IPFS daemon, and run <code>ipfs add -r dist/</code>, to add the whole ĐApp to IPFS. Now, you can test it through your local IPFS gateway: <code>http://localhost:5001/ipfs/Qm{hash}/</code>(if your code isn’t identical to mine, your CID hash might differ, use the one output from the above <code>ipfs add</code> command).</p>
<h3 id="heading-wrapping-up">Wrapping up</h3>
<p>We hope that <a target="_blank" href="https://github.com/textileio/dapp-template">our template</a> will provide a quick and easy means to bootstrap additional ĐApps, and that the community of IPFS-based ĐApps will continue to grow. At <a target="_blank" href="https://www.textile.io/">Textile</a>, we’d really like to support a community of ĐApps around IPFS, so if you decide to use our template, let us know, and we’d be happy to add a link to <a target="_blank" href="https://github.com/textileio/dapp-template/blob/master/README.md">our template repo</a>. We’ll also keep an eye out for forks and try to promote them as best we can.</p>
<p>We hope you enjoyed our quick introduction to ĐApps on IPFS. If you enjoyed this, come <a target="_blank" href="https://www.textile.photos/">check us out</a> and learn more about what we’re up to. While you’re at it, jump on the <a target="_blank" href="https://www.producthunt.com/upcoming/textile-photos">Textile Photos waitlist</a> to request early access to a whole new way to control your photos, that also runs on IPFS and the permanent web.</p>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
