This is continuation of my previous blog post How to create decentralised apps with Clojurescript re-frame and Ethereum.

As you might have noticed, I lied a bit in my previous tutorial when I said decentralised Clojurescript app. Although backend logic and database are decentralised on Ethereum, still HTML, JS and CSS files were deployed into centralised storage on Heroku. We’re gonna fix now and make the Clojurescript app fully decentralised & distributed!

What is IPFS?

IPFS stands literally for InterPlanetary File System and it’s basically peer-to-peer distributed file system that seeks to connect all computing devices with the same system of files. Please see nice post An Introduction to IPFS, if you’re not very familiar with it.

Deploying app files into IPFS

Turns out, using IPFS is pretty easy so it feels kinda like a magic!

You must install IPFS on your machine. So please follow here. Now let’s get back to our app from previous tutorial at github/clojurescript-ethereum-example. Clone repository, if you haven’t already. We want to deploy our app with advanced optimizations, so first we need to build it.

lein uberjar

In fact, you can deploy app with none optimizations and it will still work.

The key thing is not to forget to have relative paths everywhere, otherwise it won’t work.

These are several places where I had to change absolute path to relative:

:asset-path

JS file

CSS file

Contract ABI file

3. Let’s add our files into IPFS

ipfs add -r resources/public/

You should see bunch of hashes like

.

.

.

added QmUKC7dfwuFfuJvoDBw8Huu5yiXbnUh5NX8F5b6Dcgs66z public/css

added QmcExs4v7pn6XMpaMKQZ5VxwaCdsqiyBAUTCPxDyWAeJBK public/js/compiled

added QmRQYjNcPgdLVVPWXXRC6BwzDj87H4hvppdHDBkn7XFagu public/js

added QmXF33qVuVG75ES4c3QdakhawdqEvywckQGagjab8AVM7Z public/less

added QmQJicVRt7wskThaYvnxVBPjKbYSwKfADGssGcwMTbHfN9 public

The only hash we’re interested in is in fact last one, for public folder. Actually, in theory, if you haven’t changed cljs files anyhow, you could have the same hash as mine, because files with the same content always result in the same hash. This is smart trick to avoid duplicates on network. But in practice advanced optimizations probably produced bit different app.js for you, so that changes hashes all the way up to root (public) folder.

4. Now we need to actually start IPFS server, because so far you are the only one having those files. It hasn’t be pushed anywhere yet. Open new tab and write:

ipfs daemon

You should be able to open app at:

http://localhost:8080/ipfs/<YOUR_HASH_FOR_PUBLIC_FOLDER> # in my case

http://localhost:8080/ipfs/QmQJicVRt7wskThaYvnxVBPjKbYSwKfADGssGcwMTbHfN9/

If it works, great! Now, you should also be able to access app from outside world. Keep in mind, at beginning, you are the only one serving those files, so it might take while until network finds out you are the one having file(s) for this hash. After your file(s) gets more distributed this latency naturally decreases. More requests for hash = more distribution, I think.

https://ipfs.io/ipfs/<YOUR_HASH_FOR_PUBLIC_FOLDER> # in my case

https://ipfs.io/ipfs/QmQJicVRt7wskThaYvnxVBPjKbYSwKfADGssGcwMTbHfN9/

Nice, so it’s deployed! Yea, but…

Remember IPFS provides no guarantees about data availability or redundancy. Data added to IPFS is self hosted until another interested party decides to request it from you and re-host. You should try to shut down your IPFS daemon and refresh. If it works, good, it’s been already distributed on other nodes. The real financial incentive for others to store your files will be provided by filecoin, which is currently still under development. It is developed by the same people as IPFS.

What if I want to update my app?

You guessed it correctly, if you change some cljs file, compile again, ipfs add again, hash for your public folder will be different, therefore link to your app will be different. Old one will be still directing to old version of app, new one to a new version. Luckily, there’s an easy trick for that!

IPNS can store a reference to an IPFS hash

ipfs name publish <YOUR_HASH_FOR_PUBLIC_FOLDER> # in my case

ipfs name publish QmQJicVRt7wskThaYvnxVBPjKbYSwKfADGssGcwMTbHfN9

This will get you public hash that can always link to latest version of public folder.

Published to QmXj5vKEKSU4kkjGnWq9ZJeG4xrkacDugme4iXz6qtvPgN: QmQJicVRt7wskThaYvnxVBPjKbYSwKfADGssGcwMTbHfN9

Now I can access my app from outside on following link. Notice the directory is ipns not ipfs.

https://ipfs.io/ipns/QmXj5vKEKSU4kkjGnWq9ZJeG4xrkacDugme4iXz6qtvPgN/

Now whenever you will update app and get a new hash for public folder, you use following command to update IPNS:

ipfs name publish <YOUR_NEW_HASH_FOR_PUBLIC_FOLDER> <YOUR_IPNS_HASH> # in my case

ipfs name publish <SOME_HASH> QmXj5vKEKSU4kkjGnWq9ZJeG4xrkacDugme4iXz6qtvPgN

Alright, that’s it guys! IPFS is still very new, yet pretty amazing technology. It has a big ambition to eventually replace HTTP, so I personally can’t wait to see how far it’ll get ;)