DNSLink on pkarr

Posted on by Chris Warburton

A previous post explained how to integrate pkarr into our system’s name resolver. In this post we’ll use DNSLink to integrate it with IPFS.

DNSLink allows a DNS record to reference an arbitrary identifier for content outside the domain name system. Since pkarr uses DNS records, we can use DNSLink with pkarr too.

A DNSLink record is simply a TXT record with a value like dnslink=/foo/bar (it could just as well have been a new record type; but using TXT is easier).

The /foo/bar part is a multiformat, with a “namespace” and identifier. By convention, namespaces come from the multicodec table.

For this example we’ll use the ipfs namespace and a CID as identifier.

Git in IPFS

As I showed in my Git in Nix via IPFS post, we can use IPFS to store Git data; so that’s what I’ll be using in this example:

$ mkdir example-repo
$ cd example-repo
$ git init -q
$ echo "Hello world" > README
$ git add README
$ git commit -m "Initial commit"
[master (root-commit) 51cfe18] Initial commit
 1 file changed, 1 insertion(+)
 create mode 100644 README
$ git2ipfs master
baf4bcfcrz7qytrzujpbtb4ucscqij23bqivplqq
baf4bcfca3ppvlx6uazkcerrmy5fjjesuv35jolq
baf4bcfeafgjmiiqn4gnja5t7gaakpgrrxggq35y

That git2ipfs tool comes from my git-on-ipfs repo: it puts a git object, and everything it references, into a local Kubo node. In this case it printed out three CIDs: one for the commit object, one for its tree and one for the README blob.

We can resolve and traverse this data using Kubo’s ipfs commands, e.g.

$ ipfs dag get /ipfs/baf4bcfcrz7qytrzujpbtb4ucscqij23bqivplqq/tree | jq .
{
  "README": {
    "hash": {
      "/": "baf4bcfeafgjmiiqn4gnja5t7gaakpgrrxggq35y"
    },
    "mode": "100644"
  }
}

For this example we’ll put the commit’s CID in our DNSLink record, so its value will be dnslink=/ipfs/baf4bcfcrz7qytrzujpbtb4ucscqij23bqivplqq.

Now we need to construct a pkarr record and publish it to the Mainline DHT. First, our record will look like this:

$TTL 60

_dnslink   IN    TXT    dnslink=/ipfs/baf4bcfcrz7qytrzujpbtb4ucscqij23bqivplqq

By convention, our DNSLink TXT record lives on a _dnslink subdomain. We’ll write this to a file called example.zone.

Next, we’ll use the pkdns-cli command (provided by pkdns) to create a fresh pkarr address and publish this record to it:

$ pkdns-cli generate > seed
$ pkdns-cli publickey seed
rthyxssxwcwnpkfnfq17woucenizkc868gt9ea6jdzufpyygpnuo
$ pkdns-cli publish seed example.zone
Packet rthyxssxwcwnpkfnfq17woucenizkc868gt9ea6jdzufpyygpnuo
Name TTL Type Data
_dnslink             60      TXT    dnslink=/ipfs/baf4bcfcrz7qytrzujpbtb4ucscqij23bqivplqq

2026-05-08 01:21:40 UTC Successfully announced.

Now we should be able to resolve this pkarr record directly from the Mainline DHT:

$ pkdns-cli resolve rthyxssxwcwnpkfnfq17woucenizkc868gt9ea6jdzufpyygpnuo
Resolve dns records of pk:rthyxssxwcwnpkfnfq17woucenizkc868gt9ea6jdzufpyygpnuo
Packet rthyxssxwcwnpkfnfq17woucenizkc868gt9ea6jdzufpyygpnuo
Name TTL Type Data
_dnslink             60      TXT    dnslink=/ipfs/baf4bcfcrz7qytrzujpbtb4ucscqij23bqivplqq

Last updated at: 2026-05-08 01:21:40 UTC

Great! Also, since the previous post configured our system to resolve pkarr addresses via pkdns, we can look up these records using ordinary DNS too:

$ dig +short TXT _dnslink.rthyxssxwcwnpkfnfq17woucenizkc868gt9ea6jdzufpyygpnuo
"dnslink=/ipfs/baf4bcfcrz7qytrzujpbtb4ucscqij23bqivplqq"

Finally, we can use Kubo to look up these records, then look up the DNSLink identifer, then traverse its contents:

$ ipfs dag get /ipns/rthyxssxwcwnpkfnfq17woucenizkc868gt9ea6jdzufpyygpnuo/tree | jq .
{
  "README": {
    "hash": {
      "/": "baf4bcfeafgjmiiqn4gnja5t7gaakpgrrxggq35y"
    },
    "mode": "100644"
  }
}

What’s going on here is the following:

Note that the ipns namespace was originally used for IPNS, which is IPFS’s own DHT-based name system. I tried to use IPNS a decade ago but I’ve always found it quite unreliable; hence my more recent use of pkarr instead. At the very least, I like how pkarr is a small, standalone piece of technology which accomplishes one task and inter-operates with existing systems; unlike IPNS, which tends to be strongly-coupled to Kubo, for implementation; key management; etc.

In any case, it seems like DNSLink was created as a compatability shim for using IPFS content on DNS Web sites; and was shoehorned into the ipns namespace since that was already “resolving names”. That makes even less sense in my setup since I’m not using the usual DNS database. Subsequent work has resulted in more-precise approaches, like multiaddr, which also generalise to more protocols; so perhaps one day we can use a pk namespace/multiaddr instead of the decreasingly-relevant ipns?