如何在浏览器中实现IPFS连接的指引(详解教程)
我们看到很多关于在浏览器里使用js-ipfs的问题。这篇文章展示了用js-ipfs搭建最小化的聊天应用的例子,这个应用可以在浏览器中运行。它使用WebRTC去实现浏览器对浏览器的连接(在可用时),如不可用则使用回路中继(Circuit Relay)去连接浏览器节点。消息的传递是通过libp2p的pubsub功能实现。
获取代码
你可以在这里(https://ipfs.io/ipfs/bafybeia5f2yk6td7ciroeped2uwfivo333b524t3zmoderfhl3xn7wi7aa/)查看演示。如果你想要一个可以自行编辑的本地拷贝,可以使用IPFS下载整个目录:
ipfs get bafybeia5f2yk6td7ciroeped2uwfivo333b524t3zmoderfhl3xn7wi7aa
然后,只要在浏览器中打开index.html,就可以立即自动连接到节点并寻找连接资源。
你也可以在GitHub上分叉 heDiscordian/browser-ipfs-chat(https://github.com/TheDiscordian/browser-ipfs-chat) 项目,就可以立刻开始测试了!如果你想部署自己的版本,只要编辑index.html并遵循以下的设置信息:
在这个例子中使用的库是js-ipfs 和 Bootstrap (只包含了最小化的CSS样式文件)。如果你想要一个新版本的js-ipfs,可以下载这个(https://cdn.jsdelivr.net/npm/ipfs/dist/index.min.js) 以获得最新的可用版本。
让我们看一下这个过程的工作原理。
目录表
节点发现和连接(#peer-discovery-and-connectivity)
* Docker容器 (可选)(#docker-optional)
* 创建一个存储卷(#create-a-volume)
* 配置域名(#configure-a-domain)
* 运行容器(#running-the-container)
WebRTC-Star(#webrtc-star)
* 使用(#usage)
* 设置(#setup)
p2p-circuit(#p2p-circuit)
* 使用(#usage-2)
* 设置(#setup-2)
* 公告(#advertising)
SSL证书 (Nginx)(#ssl-nginx)
* 通讯(#communication)
*PubSub(#pubsub)
*可能存在的浏览器问题(#possible-browser-pitfalls)
* 保持与节点的连接(#staying-connected-to-peers)
* 保持与回路中继的连接(#staying-connected-to-the-circuit-relay)
总结(#conclusion)
节点发现和连接
在浏览器中,发现和连接到节点可能是有难度的,因为我们无法监听新节点,也没法访问分布式哈希表(DHT)。为了实现在浏览器中运行的最佳体验,理解如何寻找节点和保持与其的连接是很重要的。
聊天应用的例子通过两种方式实现此目标。使用WebRTC-Star,我们实现了直接的浏览器对浏览器通讯,并配置了两者之间的回路中继。
这个聊天应用也在左上方配置了一个状态指示器,让你知道自己的连接种类。绿色表示你连接到了中继(即便是通过另一个节点来连接);黄色表示你只看到直接连接的节点;红色表示你没有连接到节点(至少在聊天应用中没有连接)。
上图展示了一个有3名用户的网络是什么样子的。值得注意的是浏览器节点也可以与 go-ipfs节点通讯。因此,浏览器C并不需要是一个浏览器,也可以是一个go-ipfs节点。
Docker容器 (可选)
如果你不想使用Docker容器,可以直接跳到WebRTC-Star(#webrtc-star) 的章节。
在这个章节后,我们会涵盖WebRTC-Star和回路中继的作用,以及相关的设置方法。不过,如果你想通过Docker快速上手,我已经准备了一个可用的镜像。它可能不是最佳的长期解决方案,不过如果你只是想快速上手和进行实验的话,就是很好的方式了。
创建一个存储卷(volume)
首先,创建一个存储卷去存储密钥和节点数据这样的长期数据。
docker volume create ipfs_bundle
配置一个域名
你需要一个域名和SSl证书以在浏览器节点里使用这个套件。下面有两个选项:第一个会运行certbot证书机器人程序并自动获取域名证书。另一个选项不会处理SSl证书,你需要将9091端口反向代理到9090端口(SSL),且4011端口反向代理到4430端口(SSL)。
你可以选择其中一种方式,然后你的IPFS节点会初始化并提供像 PeerID(节点ID)和回路中继地址这样的信息。
记住,你想将这个信息编辑到聊天客户端里,这样可以使用自己的节点 (参考 WebRTC-Star 使用(#usage) and p2p-circuit 使用(#usage-2) 以获得示例,或者编辑 index.html文件并将我的节点的多个地址设定(multiaddresses)换成你自己的。
使用certbot证书机器人
确保80端口没有被占用,然后对比下面的检查清单,接着运行下面的命令:
docker run --mount source=ipfs_bundle,destination=/root -p 9091:9091 -p 4011:4011 -p 9090:9090 -p 4430:4430 -p 80:80 -it trdiscordian/ipfsbundle certbot DOMAIN.COM
不使用certbot证书机器人 (禁用SSL证书)
如果你使用这个选项,容器不会处理SSL证书,你需要将9091端口反向代理到9090端口(SSL),且4011端口反向代理到4430端口(SSL)。
docker run --mount source=ipfs_bundle,destination=/root -p 9091:9091 -p 4011:4011 -it trdiscordian/ipfsbundle DOMAIN.COM
检查清单
- 将DOMAIN.COM替换成你的域名
- 确保域名被正确指向到容器运行的机器上(子域名也能正常工作)
运行容器
在配置好后,运行容器是很简单的。最起码要确保4430端口和9090端口被转发。
docker run --mount source=ipfs_bundle,destination=/root -p 9091:9091 -p 4011:4011 -p 9090:9090 -p 4430:4430 -it trdiscordian/ipfsbundle
现在你应该将此机器作用WebRTC-Star节点或p2p-circuit节点。
WebRTC-Star
我们可以使用 WebRTC-Star (https://github.com/libp2p/js-libp2p-webrtc-star)节点来帮助发现其他可以直接通过浏览器对浏览器连接的节点。
如果你已经熟悉了这个概念的话,我觉得可以将此看成跟STUN类似。实际上,每一个连接节点将会被赋予一个WebRTC-Star multiaddress 地址,这样其他节点可以直接发现和连接到你的浏览器。这意味着如果你与其他star节点连接上了,当star节点下线时,你依然保持连接。
使用
连接到一个star节点是很简单的:
设置
请注意这个例子使用了我自己的star节点。不过,这些节点并不一定可以在任何时候都连接上。当前重要的事情是要么找一个可靠的star节点,要么搭建自己的。
你可以很容易地根据(https://github.com/libp2p/js-libp2p-webrtc-star#rendezvous-server-aka-signaling-server)这里的指示来以原生的方式搭建自己的节点。
也可以根据(https://github.com/libp2p/js-libp2p-webrtc-star/blob/master/DEPLOYMENT.md)这里的信息来使用Docker容器(包含为SSL功能配置的Nginx)。
如果你选择原生的方式,我们会在这篇文章的后面介绍Nginx反向代理过程和SSL证书取回的方法。
这是一个简洁、高效的P2P通讯方式。不过有时候NAT网络会带来障碍。我们使用p2p-circuit 来绕过它。
p2p-circuit
使用 p2p-circuit对在NAT网络(或VPN等)后面的节点是很有用的。我发现p2p-circuit的中继与TURN(https://en.wikipedia.org/wiki/Traversal_Using_Relays_around_NAT)是很相似的,如果你对那概念熟悉的话,应该就很容易理解了。
使用
当 p2p-circuit的所有服务就绪后,可以用几种方式连接到节点。首先,在启动时仅连接到我们的节点:
或者可以之后添加我们自己的节点,然后手动初始化连接:
如果你想不复制例子并实现自己的客户端,那确保你与公告频道(announce channel)也在进行通讯,这在公告(#advertising)这里描述了。在聊天演示应用中,相关的代码简化如下:
设置
就如star节点,你要认识到这篇文章里列出的节点是在任何时候都可能下线的,所以架设自己的节点是很重要的。
为了实践这个例子,你还需要在架设自己的go-ipfs节点的服务器上做一些事情。你还需要一个可用的Nginx安装配置,它将会被SSl证书使用,这个证书是浏览器所需要的。
首先配置Go节点,启用WebSocket支持,然后通过编辑~/.ipfs/config并添加以下的设置来将其指定为一个中继,这样就可以从浏览器里与其通讯了:
以自己习惯的方式重启go-ipfs节点 (可能是systemctl --user restart ipfs命令),这样就差不多就绪了。我们已经启用了支持中继的常规WebSockets接口,不过还需要安全的WebSockets接口配置(在下面的SSL章节有介绍),否则浏览器就无法与我们连接。
公告
使用p2p-circuit可能会有点麻烦。当我们从浏览器连接到中继时,我们并不会向网络公告自己将会通过中继接受连接。为实现这个目的,我创建了go-ipfs一起使用的Python脚本,它可以通过p2p-circuit multiaddress以及PubSub来公告其发现的浏览器js-ipfs节点。
你可以在这里(https://gist.github.com/TheDiscordian/51962fea72f8d5a5c3bba79dd7009e1c)找到该Python脚本,运行方式可以是python ipfs_peeradvertiser.py 命令。
不过,确保你先以自己的节点信息编辑 CIRCUIT,否则就无法正确地公告这些节点,这些节点也无法知道如何使用你的中继连接到其他节点。
你可以简单地获取自己的信息。在你的go-ipfs节点上运行ipfs id命令获得你的PeerID标识,然后以下面的方式构造回路URL地址:
/dns6/ipfs.YOURDOMAIN.COM/tcp/4430/p2p/YOUR_PEERID/p2p-circuit/p2p/
可以看到,这里只要填入你拥有SSL证书的域名地址,以及自己节点的PeerID标识。在脚本里,前面的斜杠和后面的斜杠都是需要填入的。
注意
根据你的地址类型(IPv4或IPv6),确保你指定了对应的DNS6或DNS4域名解释服务。使用DNS解析服务是很重要的,否则浏览器节点很可能无法连接。同样要关注4430端口,如果你使用了另一个端口,就需要进行指定。
SSL证书 (Nginx服务)
现在我们在没有SSL证书的情况下设置了WebRTC-Star和 p2p-circuit(除非你使用了 WebRTC-Star的docker容器方案)。
如果你想在互联网上通过浏览器使用节点,就需要支持SSL证书。如果你使用了当前的默认配置,那么WebRTC-Star应该是在9090端口(非SSL)上运行,而p2p-circuit应该会在4011端口(非SSL)上运行。我们将会把这些端口各自指向给9091端口(SSL)和4430端口(SSL)。
首先确保Nginx服务安装好了,然后获取并安装Certbot证书机器人(https://certbot.eff.org/docs/install.html)。
我们将从下面的模板创建两个文件。确保你将类似YOURDOMAIN.COM这样的配置更改成你实际想用在服务上的完整域名(包含子域名)。
在这个例子中,你可以看到我们在4430端口上接受SSL连接,这就是我们的 "wss端口" (安全的WebSocket端口) ,然后转发到本地的4011非安全端口(即我们的ws端口)。因此如果我们想通过浏览器连接到这个节点,就使用4430端口。
然后,运行以下命令:
现在Nginx服务已作为反向代理运行,为你提供安全的WebSockets端口了。
通讯
哇!你已经有这么多进展了,可能会想通讯是什么样子的?幸运的是,相比于节点发现,通讯是非常简单的,只是可能会有一点小坑。我们将简单介绍如何在聊天的例子中使用PubSub(https://docs.libp2p.io/concepts/publish-subscribe/) 并在此过程中发现的一些坑。
PubSub
使用PubSub,我们可以订阅主题并取回这些主题下发布的信息。在js-ipfs中,我们可以设置一个回调函数,这样在收到信息时就可以得到通知了:
发布也是很简单的:
这就是这个聊天演示应用的功能。它订阅了一个名为"discochat-global"的全局主题,并简单地将人们输入的信息通过PubSub进行中继。
可能存在的浏览器问题
假设你的操作都正确完成了,就可以使用WebRTC-Star和 p2p-circuit来寻找节点。太棒了!不过,你可能会发现连接超时,而且无法恢复。我并不确定这种行为发生的原因(可能是某些浏览器策略);不过我们还是可以努力尝试应对这些问题的!
与节点保持连接
我们有几种方式与节点保持连接。第一种是更直接的:每隔4秒通过discochat-keepalive订阅和发送"keepalive"信息:
这应该能帮助确保我们为有意向聊天的节点提供更高的优先度。此外,我们每隔15秒通过announce-circuit进行汇报,以确保维持与回路中继的连接,这样就可以连接到NAT网络后的节点。可通过以下的方式实现:
在p2p-circuit#使用(#usage)可以找到简化版本的processAnnounce。
回路中继上的Python脚本会每隔4秒汇报一个保持活跃连接(keepalive)信息。你可能已经注意到我们汇报的是 "peer-alive" 而不是"keep-alive"信息;这是为了将节点请求与中继请求区分来开,让我们更容易知道缺乏可用中继的情况。
与回路中继保持连接
在processAnnounce的简化版本之外,在真实的版本中有几个变量用于追踪keep-alive和peer-alive信息。它们各自是lastAlive和lastPeer。我们甚至可以通过lastBootstrap来追踪最近一次的初始化启动(bootstrap)时间。
通过这些,我们可以在只连接到节点(通过lastPeer追踪)时展示黄色的状态,而在35秒内没有看到keep-alive信息时(且没有在60秒内尝试初始化启动时)可以尝试重新连接到初始化启动中继(并展示红色状态)。可通过以下的方式实现:
上述方法应该与processAnnounce的完整版本一起使用,因为它依赖于简化版本中没有包含的lastAlive和 lastPeer功能。
总结
我希望这些信息足够带你上手了。如果你成功遵循这个指引,你就有能力部署可完全在浏览器中运行的功能强大的IPFS应用,并在任何地方利用去中心化的P2P网络。我选择了一些有用的资源并分享在下面以供进一步阅读:
- js-ipfs/docs/BROWSERS.md(https://github.com/ipfs/js-ipfs/blob/master/docs/BROWSERS.md)
- js-ipfs/docs/CONFIG.md(https://github.com/ipfs/js-ipfs/blob/master/docs/CONFIG.md)
- js-ipfs/docs/core-api(https://github.com/ipfs/js-ipfs/tree/master/docs/core-api)
- js-ipfs/examples/circuit-relaying(https://github.com/ipfs/js-ipfs/tree/master/examples/circuit-relaying)
- js-libp2p-webrtc-star(https://github.com/libp2p/js-libp2p-webrtc-star)
Bitcoin Price Consolidates Below Resistance, Are Dips Still Supported?
Bitcoin Price Consolidates Below Resistance, Are Dips Still Supported?
XRP, Solana, Cardano, Shiba Inu Making Up for Lost Time as Big Whale Transaction Spikes Pop Up
XRP, Solana, Cardano, Shiba Inu Making Up for Lost Time as Big Whale Transaction Spikes Pop Up
Justin Sun suspected to have purchased $160m in Ethereum
Justin Sun suspected to have purchased $160m in Ethereum