/ HOWTO_IPFS.md
HOWTO_IPFS.md
1 # Static Webpages on IPFS and IPNS 2 3 demo webpage in `./web-static` 4 5 ## deploy a static web page to IPFS 6 7 ```bash 8 ipfs add -r ./web-static --pin 9 # added QmWYZ65vwQLrqRWKhYL86kHrJwt1d7bJzmGDSvJZ8wX9Ha web-static/index.html 10 # added QmTe4hAzoc2vS6ikp8TENnxZY3at1fzkv54Jh2LNPCHEJD web-static/skunk.jpg 11 # added QmU2JQChEeGJaX3jqABaWaTBZ37EX5oJAMaNxqmGVJmcUA web-static 12 ``` 13 14 That will already be enough for some browsers (e.g. brave) to resolve the content using IPFS. 15 16 [ipfs://QmU2JQChEeGJaX3jqABaWaTBZ37EX5oJAMaNxqmGVJmcUA](ipfs://QmU2JQChEeGJaX3jqABaWaTBZ37EX5oJAMaNxqmGVJmcUA) 17 18 many browsers, especially on mobile, need a gateway url: 19 https://ipfs.io/ipfs/QmU2JQChEeGJaX3jqABaWaTBZ37EX5oJAMaNxqmGVJmcUA 20 21 ## improve availability 22 23 IPFS routing is very unreliable, so we may want to use a pinning service like infura and pinata in addition to our own ipfs nodes. 24 25 ### pin on self-hosted mirror node 26 27 connect your local node to the remote one explicitly (not mandatory, but improves success rate) 28 ```bash 29 ipfs swarm connect /ip4/129.212.213.82/tcp/4001/p2p/12D3KooWCtS4Li5YJhjj2fWWKxgqZi7t6FReuVtrN9MRQtLrg7Tj 30 ``` 31 32 then pin the content: 33 34 ```bash 35 curl -u <USER>:<PWD> -s -X POST "https://ipfs2-api.encointer.org/api/v0/pin/add?recursive=true&arg=QmU2JQChEeGJaX3jqABaWaTBZ37EX5oJAMaNxqmGVJmcUA" 36 ``` 37 38 ### pin with CRUST 39 40 See [HOWTO_CRUST.md](HOWTO_CRUST.md). Not sure how long they will survive, but: For public files, CRUST is a good and cheap upload & pinning solution with multiple replicas. No need for email: Login with crust wallet 41 42 ## publish to ENS 43 44 See [HOWTO-ENS.md](HOWTO-ENS.md) 45 46 ## publish an IPNS address 47 48 **DISCOURAGED!** see [multiparty-control](#multiparty-control) below for why 49 50 For reference, here's how to do it anyway: 51 52 Create a new named owner key for IPNS publishing: 53 54 ```bash 55 ipfs key gen --type ed25519 --ipns-base b58mh skunk-funk 56 # 12D3KooWJiYyq1qRNCoTELgeqV84Yko27ZV2adcqsTN15SZSHryk 57 ``` 58 59 Publish the IPNS address: 60 61 ```bash 62 ipfs name publish --key skunk-funk QmU2JQChEeGJaX3jqABaWaTBZ37EX5oJAMaNxqmGVJmcUA 63 # Published to k51qzi5uqu5djh8k8yfnjs21pe4sgqkorynz26b3y5g72pjrfuumjlsgio7mkv: /ipfs/QmU2JQChEeGJaX3jqABaWaTBZ37EX5oJAMaNxqmGVJmcUA 64 ``` 65 66 Now you can visit the webpage using the IPNS address: 67 68 https://ipfs.io/ipns/k51qzi5uqu5djh8k8yfnjs21pe4sgqkorynz26b3y5g72pjrfuumjlsgio7mkv 69 70 ### update the webpage 71 72 Only the owner key can update the IPNS target. 73 74 1. edit 75 2. ipfs add 76 3. call ipfs name publish again with the new IPFS CID 77 78 ### multiparty control 79 80 We don't like single-party ownership. Our requirement is 81 * any curator can update the webpage, if possible applying a threshold of 2 curators 82 * the curator set should be able to change 83 84 **There is currently no out-of-the-box solution. use ENS in combination with SAFE instead!** 85 86 #### best: threshold multisig 87 88 [tracking issue to add multisig support to IPNS](https://github.com/ipfs/specs/issues/416) 89 90 also includes a PoC on Go 91 92 No solution for changing signatories in the future yet. Use ENS instead 93 94 ### simple: share the owner key with all curators 95 96 Not very secure, but straightforward: share the owner key file with all curators. Any curator can then update the webpage. 97 98 ```bash 99 ipfs key export skunk-funk 100 # will dump the key to `./skunk-funk.key` 101 ``` 102 103 Share that keyfile with all other members securely. They import it with 104 105 ```bash 106 ipfs key import skunk-funk ./skunk-funk.key 107 ``` 108 109 #### slightly more secure: Shamir's secret sharing 110 111 One curator creates the key and splits the secret into N shares, of which M are necessary to recover the secret 112 113 * linux cli tool: `ssss-split` and `ssss-combine` 114 115 ## light cluster of IPFS nodes 116 117 Goal: follow whatever your friends are pinning and mirror these pins. No strict cluster coupling, no consensus. Just publish your pins to IPNS for your friends to consume and mirror if they want to. This is a very lightweight way to increase availability of our content without relying on a third party pinning service. 118 119 create/edit your config in `./pin-follower/config.json`: 120 ```json 121 { 122 "ipfsApi": "http://localhost:5001", 123 "publishIntervalSeconds": 1800, 124 "syncIntervalSeconds": 3600, 125 "ipnsLifetime": "24h", 126 "resolveTimeout": "60s", 127 "stateDir": "~/.pin-follower", 128 "friends": [ 129 { "name": "encointer-do", "ipnsKey": "12D3KooWCtS4Li5YJhjj2fWWKxgqZi7t6FReuVtrN9MRQtLrg7Tj" } 130 ] 131 } 132 ``` 133 134 ```bash 135 ./scripts/pin-follower.sh --once 136 #2026-02-24T11:56:12Z [pin-follower] Waiting for IPFS API at http://localhost:5001 ... 137 #2026-02-24T11:56:12Z [pin-follower] IPFS API is ready (PeerID: 12D3KooWNf2yMKjkgLkqcBcfAzb5jiHn5zZxG3EPUJQuhpbDA8n2) 138 #2026-02-24T11:56:12Z [pin-follower] Share this with friends: {"name":"<yourname>","ipnsKey":"12D3KooWNf2yMKjkgLkqcBcfAzb5jiHn5zZxG3EPUJQuhpbDA8n2"} 139 #2026-02-24T11:56:12Z [pin-follower] Running once 140 #2026-02-24T11:56:12Z [pin-follower] Publish: collecting pins... 141 #2026-02-24T11:56:13Z [pin-follower] Publish: 26 own pins (excluding friend pins) 142 #2026-02-24T11:56:13Z [pin-follower] Publish: pin list CID=QmeBbCVLADyEiKH9yq12XTwbFeESMhLzjFsAA2A25Hw9aC, publishing to IPNS (this can take minutes)... 143 #2026-02-24T11:56:31Z [pin-follower] Publish: done, IPNS=k51qzi5uqu5dkxr7ol779xt3ygop35pg82fzbl2l56qeaadc2l2dv0l2ar0uhj, CID=QmeBbCVLADyEiKH9yq12XTwbFeESMhLzjFsAA2A25Hw9aC, pins=26 144 #2026-02-24T11:56:31Z [pin-follower] Sync: processing 1 friend(s)... 145 #2026-02-24T11:56:31Z [pin-follower] Sync [encointer-do]: resolving 12D3KooWCtS4Li5YJhjj2fWWKxgqZi7t6FReuVtrN9MRQtLrg7Tj ... 146 #2026-02-24T11:56:36Z [pin-follower] Sync [encointer-do]: resolved to /ipfs/QmWHYL72unWXhZWuY7zxUvVuRUSXg3yrQmwjjaU6HJ69Na 147 #2026-02-24T11:56:39Z [pin-follower] Sync [encointer-do]: pinning 1 new CIDs... 148 #2026-02-24T11:56:39Z [pin-follower] Sync [encointer-do]: pinned QmRWzCGwYZ3WPGdBdkSzWfHX9Q2MGnYKVYYZrBDqED4muA 149 #2026-02-24T11:56:39Z [pin-follower] Sync [encointer-do]: done (new=1, stale=0) 150 #2026-02-24T11:56:40Z [pin-follower] Done 151 ``` 152 153 Install as cronjob 154 ```bash 155 crontab -e 156 # sync pins once per hour 157 0 * * * * CONFIG_FILE=$HOME/.pin-follower/config.json $HOME/pin-follower.sh --once >> $HOME/.pin-follower/cron.log 2>&1 158 ```