If you're not familiar with the Interplanetary File System (IPFS) I highly encourage you to look at their site. IPFS aims to be the distributed peer-to-peer web. Files and web pages can be shared on multiple machines, starting with the one you share the content with. Additionally, user's can "pin" files and web pages on their local IPFS nodes to then further share them with others. This is as opposed to a centralized web where a webpage is served from a central source.
Having the ability to share my content (this Hugo site) with others in a distributed fashion, where others can even cache offline versions of this content, was the main motivator to put my site onto IPFS. There are many more interesting and ground breaking features of IPFS but this article only showcases the basic case of putting a statically generated Hugo site onto IPFS.
To stay consistent, I'll document the terms I'll use and what they mean.
- Site hash - IPFS addresses file and directories by their hashes. I refer to the hash of the root directory for the static hugo site as the site hash. Essentially, the site hash is the way of finding/addressing the static site's directory in IPFS.
- IPNS hash - Technically a hash of your IPFS private key. IPNS is used to pin a stable address to an every changing IPFS hash. This is because IPFS hashes change when the content changes.
In the Hugo site's config.xml
, set relativeURLs = true
. The reason is that when we access the site through a remote or local IPFS gateway the site won't be at the root (e.g. example.com
) but instead something like http://example.com/subfolder
. In the case of the IPFS gateway specifically the root of our site will not be the root of the IPFS gateway: http://localhost:8080/ipfs/<hash-for-site>
.
Generate the site by running hugo
. The static site will be generated and output into the public
directory. The public
directory is the one I serve in the traditional sense via the centralized web.
Now we'll publish our statically generated Hugo site to IPFS by running ipfs add -r public/
. This command will place the directory "into" IPFS. In the background the entire directory structure is chunked, hashed, and transformed into the structure needed to access/share this directory (our site) on IPFS. At this point the site will be ready to serve from our local IPFS node. The add command will give us a hash, something like QmV7PaSSAmS7r55y7jVAYM2dZ5oXfhV9m7LZPPNCGwBAbo
, which will uniquely identify our site's directory. It will typically be on the last line of output, with the name of the folder (public
in our case). This is our content will be addressed in IPFS.
Using the local gateway provided by the IPFS daemon. The content can then be view with the URL: http://127.0.0.1:8080/ipfs/<site-hash>
.
Before we move to the next step, we should backup our IPFS private key. The private key will be needed to create and update the IPNS hash. If we lose it we'll lose access to update that IPNS hash to the new site hash. The IPFS private key will typically be in the file ~/.ipfs/config
where ~
is the user's home directory.
We may want to update our site and not have to advertise the new site hash every time. In order to solve this we'll create an IPNS hash to point to our site hash and then update this IPNS hash to the new site hash on every site update. The command will be ipfs name publish <site-hash>
. This will return the IPNS hash. More information on IPNS can be found here.
When we update our site we will get a new site hash and we will run the same command to update the IPNS hash pointer to the new site hash.
To access content on IPFS that content must be on at least one running IPFS instance. In step 3 we placed our static site on our local IPFS node. This is fine for serving assuming this local machine is always going to be online for others to download our site from. This may not always be the case and therefore it's preferable to "pin" the site on other IPFS nodes to ensure our site remains live. We can setup IPFS on a home server and run ipfs pin add -r /ipns/<ipns-hash>
. This will instruct the IPFS daemon on that server to store a copy of the site locally, enabling it to be served to others.
Please note that when we update IPNS to point to our new site hash we will need to rerun the pin command. Based on what I've read this may not be necessary in future versions of IPFS.
There are also third party pinning services that can store your site, or really any IPFS content, for you. More information can be found here.
As an example, I pinned my site using Pinata cloud. After setup, all I needed to do was run the command: ipfs pin remote add --service=pinata /ipns/<ipns-hash>
.
Though the IPNS hash will always point to the latest site hash it's impossible to memorize this and hard to share with others. One way to bridge the gap is by using DNS Link. We can make our site addressable using our current domain name. For example, this site is addressable with /ipns/jacobzelek.com
and /ipns/kg6mwi.com
. To use DNS Link a TXT DNS entry needs to be added to the existing domain. For my site I had to add the record dnslink=/ipns/<ipns-hash>
as a TXT record to _dnslink.jacobzelek.com
. Here's a screenshot of how it looks like in my GoDaddy account.
More information can be found here.