Blogging on IPFS

With Hugo, IPNS, dnslink, and Cloudflare IPFS gateway

A little fun fact about this site

This blog is a static site generated by Hugo, hosted on IPFS. I personally run an IPFS node, and the files are pinned on my node. If you came here though your own IPFS gateway, then congrats! You already know where this is going. Otherwise, keep reading and I’ll explain the entire setup of the site.

  • The site lives permanently by the IPNS name
/ipns/QmTctHYiuy3LXguP5jBP4DJAmnCD22gQbBAV24wH394vSs
  • https://push32.com gets you on Cloudflare IPFS gateway, which actually resolves to
https://cloudflare-ipfs.com/ipns/<site-ipns-name>
  • digging the TXT record of _dnslink.push32.com will give you the IPNS name as well

The site can be accessed by:

  • Simply going to https://push32.com
  • Use an IPFS gateway and go to
/ipns/push32.com
  • You can resolve this to IPNS name with ipfs dns push32.com
  • Use an IPFS gateway and go to
/ipns/QmTctHYiuy3LXguP5jBP4DJAmnCD22gQbBAV24wH394vSs
  • You can resolve this with
ipfs name resolve QmTctHYiuy3LXguP5jBP4DJAmnCD22gQbBAV24wH394vSs
  • Once you resolved the IPNS name you can use an IPFS gateway and go to /ipfs/<resolved-ipfs-path>

I’m writing this post as a tutorial on setting up your own uncensorable blog on IPFS.

Requirements

  • Have hugo and ipfs installed
  • A server that’s connected to the internet, that can run an IPFS node
  • Basic Linux knowledge
  • Basic DNS knowledge

Hugo setup

Assume you already have a working site generated by Hugo. If you don’t I would refer you to their quick start guide.

Config

Make sure you add this in the config.toml of your Hugo site

relativeurls = true

Generating the site

Once the config is updated, run hugo to generate the site. The static site should be generated in public folder.

IPFS setup

The IPFS setup should be done on whatever server you wish to run the IPFS node on. This can be your own laptop or whatever, but keep in mind that the server has to always be running IPFS node if you want your site to be always available.

Init

In case you have not already init’d IPFS, run

ipfs init

This will create ~/.ipfs folder with default configs, and a fresh keypair. You probably want to back up ~/.ipfs/config file as your private key is in it.

Starting IPFS daemon

ipfs daemon

This will run IPFS daemon on your server. Add & if you want to run it in the background.

Protip: If you just want to try it out without annoncing your embarrassing “hello world” post to the world, run it with --offline flag.

Adding the files

Now we can add the public folder to IPFS.

ipfs add public/ -r

This command should return all the files added along with their IPFS paths. The files are added to the local IPFS node. If the node is running with --offline flag, the files will not be accessible outside localhost.

You shouldn’t have to do ipfs pin add since the files get pinned when you publish.

Publishing to IPNS

Copy the IPFS path of the public folder from the output of the previous step.

ipfs name publish <root-folder-ipfs-path>

What this essentially does is that IPFS uses the private key to write a signed message saying that “an IPNS lookup with my peer-ID should resolve to this particular IPFS path”. So when other people do an IPNS lookup with your peer ID, they will see the IPFS path you published.

This command outputs both your IPNS name (peer-ID) and the IPFS path of the public folder.

Checking the IPNS name record

ipfs name resolve <my-peer-id>

You can see your peer ID with ipfs id. The output should match the IPFS path from the previous step.

Now, you should be able to see your site by going to

http://localhost:8080/ipns/<peer-id>

in your favorite browser.

dnslink setup

dnslink gives us the ability to resolve a DNS record like example.org to either an IPFS path or IPNS name, so we don’t have to remember our long peer-id.

Now, depending on whether or not you want to use CNAME records to point at the DNS records of the gateway, there are 2 ways to set up dnslink.

Without CNAME to gateway

This method allows you to use any subdomain you wish, like sub.my.domain. The drawback is you won’t be able to use CNAME with it, so you can’t just open up a browser and go to http://sub.my.domain. You would have to use a gateway and do /ipns/<sub.my.domain>.

Set up a DNS TXT record on the domain you wish to resolve to your IPNS name

dnslink=/ipns/<peer-id>

Once you’re done, wait until the DNS is propagated. Then you should be able to visit your site by going to

http://localhost:8080/ipns/<sub.my.domain>

Or replace localhost with some other gateway, like gateway.ipfs.io or cloudflare-ipfs.com, if your IPFS node isn’t running offline.

With CNAME to gateway

With CNAME you can visit your site by directly typing in the domain in the browser address bar. But the drawback is you can only put one dnslink on your domain.

Set up a DNS TXT record for _dnslink.my.domain

dnslink=/ipns/<peer-id>

Then set up a CNAME record for my.domain to point to an IPFS gateway.

  • You can try Cloudflare IPFS gateway, which is cloudflare-ipfs.com
    • This comes with HTTPS and all the fancy stuff. In reality, you don’t really need HTTPS if you aren’t too worried about privacy, since the client can always verify the integrity of the data over IPFS. Your ISP or whoever MITM is can see your request, but IPFS itself does not provide PIR (private information retrieval) privacy anyway.
  • You can also try the gateway hosted by ipfs.io, which is gateway.ipfs.io

Once you are done, go to http://my.domain and see your shiny new site.

Bonus: Script for the lazy

Assume you have your hugo site source and ipfs on your server. Put this script to your hugo site source directory, run it to build site, add to ipfs, then publish.

#!/bin/sh
echo Building site...
hugo
echo Adding to IPFS...
ROOTHASH=$(ipfs add -r public/ | awk '{print $(NF-1)}' | tail -1)
echo "Root hash of the site is $ROOTHASH"
echo Publishing to IPNS...
ipfs name publish $ROOTHASH
echo Done!