利用 ipfs 构建去中心化 django 博客系统

1,766 阅读4分钟
原文链接: zhuanlan.zhihu.com

0x01

运营 区块链日报 有一段时间了,访问量也在不断上涨,不过由于搭建在国外 vps 上,所以经常有同学反映网站打不开。这段时间尝试了一些方案,发现 ipfs 的去中心化方案能够完美这个问题。

关注区块链的同学也许已经对 ipfs 有过一定了解,我也在日报中推送过好几篇相关的文章,感兴趣的同学可以关注下。这里我简单介绍下,ipfs 是一个点对点的分布式文件系统,只要文件被添加到 ipfs 节点上,他就有个 hash 值来代表他的存在,哪怕只在文件中修改一个比特的数据,哈希都会完全不同。当下一步向 ipfs 分布式网络查找该哈希的时候,它通过使用一个分布式哈希表,可以快速地找到拥有数据的节点,从而检索该数据,并使用哈希验证这是否是正确的数据。而存储这些文件的节点我们可以认为也是一种矿工的形式,只是不像比特币利用算力来做工作量证明,而是存储和带宽。目前 ipfs 团队正在推进发布基于 POR (带激励机制的带宽,存储容量等资源相关的一种共识)的 filecoin。

0x02

好了,介绍完 ipfs,我们来看下 ipfs 如何和 django 结合起来搭建自己的去中心化 cdn。

由于 django 搭建的网站的网页是动态服务器渲染的,而 ipfs 只能存储静态文件,所以需要先将 django 的网页静态化,然后再上传到 ipfs。

区块链日报 为例,有两种方案可以实现

  1. 每次在 admin 后台创建日报保存的时候,生成静态网页文件
def generate_static_html(issue):
    articles = Article.objects.filter(issue=issue, status=2).order_by("-created")
    context = {'articles': articles, "issue": issue}
    static_html = os.path.join(settings.IPFS_ROOT, "%s.html" % issue.id)
    content = render_to_string('articles_ipfs.html', context)
    with open(static_html, 'w') as static_file:
        static_file.write(content.encode("utf-8"))

class IssueAdmin(admin.ModelAdmin):

    def save_model(self, request, obj, form, change):
        obj.save()
        if obj.status == Issue.PUBLISHED:
            generate_static_html(obj)

2. 定期生成全站的静态文件,然后同步到 ipfs

0x03

接下来我们利用 ipfs 上传上文生成的静态文件。

  1. 安装 ipfs 可直接参考官方教程,ipfs.io/docs/instal…, 这里假设安装的是 go-ipfs
  2. 然后执行 ipfs init,会在本地建立一个 ipfs 节点。
  3. 查看节点 id ipfs id
{
"ID": "QmYpbbyrVQspuNNqowRip3ShmYFcXvnUkAvB23GVyjfenV",
"PublicKey": "CAASpgIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDFsZQi+VdfZIHTcNwsAMfjaAo9fe7GtiusbF4ZWqGxo3v05sHXrHbM1fb+FRnCmzZ7tZ679EfgxCzN38q1bAvOQVtdD/TzDQQKrLJEOyorhnML8cOtMWua/Rkvfs56Ut6fPgVHvCFpuhrUZE8eBTwKInf5kJaEOZfT/u9pi3BO5HJMUO1oHE6R66IKO3QQda3QXahx4dndc3Sx7HX+MeBd6kUPTpOtqmeFIRJE0rDSXnIxiUGlqkMbfIAgBo4XKBuajm+UMLTCT5Wo/0cNu+j8mLuNLqwcOWNR7KKKCZzUFrm+TCxMjAusy2ujgunH19vIMluGlOgiXvydwrbmZiU1AgMBAAE=",
"Addresses": null,
"AgentVersion": "go-ipfs/0.4.13/",
"ProtocolVersion": "ipfs/0.1.0"
}
 

4. 启动节点服务器 ipfs daemon

Initializing daemon...
Swarm listening on /ip4/127.0.0.1/tcp/4001
Swarm listening on /ip4/172.22.0.29/tcp/4001
Swarm listening on /ip4/192.168.99.172/tcp/4001
Swarm listening on /ip6/::1/tcp/4001
Swarm listening on /p2p-circuit/ipfs/QmYpbbyrVQspuNNqowRip3ShmYFcXvnUkAvB23GVyjfenV
Swarm announcing /ip4/127.0.0.1/tcp/4001
Swarm announcing /ip4/172.22.0.29/tcp/4001
Swarm announcing /ip4/192.168.1.2/tcp/36734
Swarm announcing /ip4/192.168.99.172/tcp/4001
Swarm announcing /ip6/::1/tcp/4001
API server listening on /ip4/127.0.0.1/tcp/5001
Gateway (readonly) server listening on /ip4/127.0.0.1/tcp/8080
Daemon is ready

5. 这个时候访问 http://localhost:5001/webui ,就可以看到本地节点的一些信息,包括文件 hash ,正在连接的节点,配置项。你也可以直接在这里选择上传文件。

6. 我们可以通过命令直接上传整个静态文件目录 ipfs add -r ipfs, ipfs 为上文生成的静态文件目录。

7. 可以看到根路径的 hash 为 QmQ19m1wLVpvi4142Mr3HHJJBx5QmuS95ibLt8ivZyG9GE ,直接访问 ipfs.io/ipfs/QmQ19m…

8. 目前网址已经能够访问,不过会存在一个问题, hash 值会随着文件的变化而变化,也就是一旦网站有更新,上文的地址就变了,所以我们可以将网站发布到 IPNS,将节点的 id (不会随文件变化而变化)绑定到项目根目录 hash, 这样更新博客的时候,重新发布到 IPNS 即可。

9. 很简单的命令,执行 ipfs name publish <根目录 hash> 便可,发布完成后,可以执行 ipfs name resolve <节点 id>,查看是否绑定。

10. 最后访问 ipfs.io/ipns/QmYpbb… ,同样也能得到想要的页面。

0x04

最后简单介绍下区块链日报吧,区块链日报是一个博客,灵感来自于湾区日报。主要记录博主在学习区块链当中读过的高质量区块链文章,通过一些渠道(微博知乎TwitterRSS, Medium)定时发布推送。

网站采用 django 搭建,nginx 做负载均衡,supervisord 管理进程,Task Queue 是 Redis。Scheduler 用的是 Celery Beat,Async Worker 是 Celery