绑定 IPNS 内容到传统域名 blog.v2ex.com

Jan 16, 2023 at 11:44:48 AM

现在大家可以通过这个传统域名访问到这个博客了:

https://blog.v2ex.com/

这样的将 IPFS/IPNS 内容绑定到传统域名的方案已经存在很多年了。但是,其中的一个关键部分,之前的主要提供者是 Cloudflare 的 IPFS Gateway。不知为何,这个 Gateway 在过去一年的时间里,大部分时候都是非常不可用的状态,即使是在 Cloudflare 将这个 Web3 Gateway 以付费服务的方式提供之后。

而 ENS 之外的生态系统里,目前又暂时不存在像 ETH.LIMO 这样的高可用的项目。所以,目前大概只能自建了。不过也不复杂,如果你之前有 Linux 和 NGINX 的使用经验,那个原理和过程还挺简单的。大概就是以下 3 个步骤:

  1. 为域名增加 DNSLink 记录。
  2. 在 Linux 服务器上安装 Kubo 并进行一些必要的设置。
  3. 为域名搭建一个源站给 CDN。

为域名增加 DNSLink 记录

以本博客为例,第一步是从 Planet 里 Copy IPNS 获得这样的一个 k51 开头的字符串:

Copy IPNS
k51qzi5uqu5dkczezx3wje1dizdk7rta8uc50a5o9ix4wmzqniacrdbfapt8cf

假设我们要绑定到 blog.v2ex.com 这个域名,那么我们需要为 _dnslink.blog.v2ex.com 增加这样一条 TXT 类型的 DNS 记录:

dnslink=/ipns/k51qzi5uqu5dkczezx3wje1dizdk7rta8uc50a5o9ix4wmzqniacrdbfapt8cf

在完成这步之后,其实所有的公网上的 IPFS Gateway 就已经可以找到这个博客了,比如:

或者在 Brave 浏览器里直接用 ipns://blog.v2ex.com 也可以打开。

Brave IPNS

这种在浏览器地址栏里看到新协议的感觉。😊

我们的目标是让这个 IPNS 通过传统域名和传统浏览器也可以访问,所以我们还需要继续为它搭建一个源站。

在 Linux 服务器上安装 Kubo 并进行一些必要的设置

Kubo,也就是 Go 版本的 IPFS 实现的最新版本,可以从这里下载:

https://github.com/ipfs/kubo/releases

第一次运行前,需要初始化,我们选择以 server 配置进行初始化:

ipfs init --profile=server

然后就可以启动了,这里我们打开了和 PubSub 有关的两个试验选项。推荐用 supervisor 或者 systemd 做成常驻服务。

ipfs daemon --enable-pubsub-experiment --enable-namesys-pubsub

为域名搭建一个源站给 CDN

Kubo 启动之后,在 localhost 上就会多一个神奇的 8080 端口。这个端口是可以响应 HTTP 的 Host header 的,也就是说,如果你运行下面的这条指令,就可以拿到这个博客的首页:

curl -H "Host: blog.v2ex.com" http://127.0.0.1:8080/

所以,借助 Kubo 对虚拟主机头的支持,我们可以这样配置一个 NGINX 源站:

upstream ipfs_backend {
    server 127.0.0.1:8080;
    keepalive 4;
}

server {
    listen 80;
    listen [::]:80;
    listen 443 ssl http2;
    listen [::]:443 ssl http2;

    # SSL
    include /etc/nginx/ssl/v2ex.com.conf;

    server_name blog.v2ex.com;
    access_log /var/log/nginx/blog.v2ex.com.log;

    location / {
        proxy_cache awesome;
        proxy_pass_header Server;
        proxy_http_version 1.1;
        proxy_set_header Host "blog.v2ex.com";
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Scheme $scheme;
        proxy_set_header Via "Planetable";
        proxy_cache_use_stale error timeout invalid_header updating http_500 http_502 http_503 http_504 http_403 http_404;
        proxy_cache_valid 200 60s;
        proxy_pass http://ipfs_backend;
    }
}

在根目录的 nginx.conf 的 http {} 段落中加入缓存目录的配置:

proxy_cache_path /data/s levels=1:2 keys_zone=awesome:1024m max_size=8g inactive=28d;
proxy_temp_path /data/t 1 2;

这样我们就获得了一个可以给 CDN,比如 Cloudflare 使用的,能够响应 blog.v2ex.com 请求的 http/https 源站。


如果你能够读到这里,那你肯定是对这个话题相当感兴趣了。那我们再把这件事情继续扩展一下:假设你做了一个类似 ENS 的区块链域名项目,你想提供一个类似 ETH.LIMO 那样的 dWeb 网关,那么会还需要什么?这里是一个大致的 To Do 清单。

DNS-over-HTTPS 服务器

你需要为你的区块链域名项目实现一个 DoH 服务器,也就是通过 HTTP 协议提供的 DNS 查询服务。比如这是 ETH.LIMO 项目为 ENS 实现的:

https://dns.eth.limo/dns-query

然后你可以这样来发起查询:

curl --http2 -H "accept: application/dns-json" "https://dns.eth.limo/dns-query?name=vitalik.eth"

会拿到一个这样的结果:

{
  "Status": "0",
  "RD": false,
  "RA": false,
  "AD": false,
  "CD": false,
  "TC": false,
  "Question": [
    {
      "type": 16,
      "name": "vitalik.eth"
    }
  ],
  "Answer": [
    {
      "type": 16,
      "name": "vitalik.eth",
      "data": "dnslink=/ipfs/QmWxRwMg3bHyJxfAuPnUky2yNgNt51qmZqC99Ffenjxa94/",
      "ttl": 600
    }
  ]
}

实际上就是这个 DoH 服务器把 ENS 设定里的 content hash,当作一条 DNSLink 的 TXT 记录返回了。

有了这样的一个 DoH 服务器之后,Kubo 在配置中支持你把指定的域名后缀用定制的 DoH 服务器解析。

如果你打算写代码来实现这个 DoH 服务,那么并不需要支持所有类型的 DNS 查询,只要能用 TXT 类型返回 DNSLink 记录就可以了。

相关文档:

https://github.com/ipfs/kubo/blob/master/docs/config.md#dns

假设你的区块链域名项目的后缀叫做 .ape,支持用户设定类似 EIP-1577 那样的 content hash,在 https://dns.example.com/dns-query 上运行了一个能够解析 .ape 的 DoH 服务器,那么你就可以把这样的配置加入到 Kubo 的 config 中:

{
  "DNS": {
    "Resolvers": {
      "ape.": "https://dns.example.com/dns-query"
    }
  }
}

然后,只要对之前提到的那个 NGINX 配置文件稍作改造,用 Lua 模块获得用户请求的 .ape 域名,然后加上正确的 proxy_set_header Host 发向配置好了 DoH 服务器的 Kubo upstream,那么一个类似 ETH.LIMO 的 dWeb Gateway 就这样初步搭建好了。

下面这个是一个用 Python Flask 框架写的可以解析 .bit 区块链域名的 DoH 服务器:

https://github.com/v2ex/dweb-dns