This living document specifies current set of conventions for the IPFS community, and requests discussion and suggestions for improvements via PR.
For immutable content use an IPFS URI (ipfs://{cid}
).
ipfs://bafkreigh2akiscaildcqabsyg3dfr6chu3fgpregiymsck7e7aqa4s52zy
For mutable content use an IPNS DNSLink URI (ipns://{dnslink}
) or a cryptographic IPNS URI (ipns://{libp2p-key}
).
ipns://cid.ipfs.io
ipns://k51qzi5uqu5dgutdk6i1ynyzgkqngpha5xpgia3a5qqp4jsh0u4csozksxel2r
For web browsers and other tools that do not yet recognise the ipfs://
and ipns://
schemes, additionally provide an HTTP-to-IPFS gateway URL.
- https://dweb.link/ipfs/bafkreigh2akiscaildcqabsyg3dfr6chu3fgpregiymsck7e7aqa4s52zy
- https://dweb.link/ipns/cid.ipfs.io
IPFS protocol handler implementations should opportunistically upgrade gateway urls. In web browser contexts where a local IPFS node is present, use subdomain gateway at localhost
. If not, use public one such as dweb.link
.
In either case, leverage IPFS path support at a subdomain gateway. This will ensure gateway takes care of CID normalization into a DNS-safe form (docs):
IPFS URI | HTTP Gateway | Internal normalization done by HTTP Gateway |
---|---|---|
ipfs://{cid} |
https://dweb.link/ipfs/{cid} |
HTTP301 → https://{dns-safe-cid}.ipfs.dweb.link |
ipns://{libp2p-key} |
https://dweb.link/ipns/{libp2p-key} |
HTTP301 → https://{dns-safe-key}.ipns.dweb.link |
ipns://{dnslink} |
https://dweb.link/ipns/{dnslink} |
HTTP301 → https://{dns-safe-dnslink}.ipns.dweb.link |
With native protocol handlers, apply below normalization:
ipfs://{cidv1base32}
ipfs://{cidv0} → redirect → ipfs://{cidv1base32} # CIDv0 is case-sensitive Base58, does not work as Origin authority
ipns://{libp2p-key-in-cidv1base36}
ipns://{libp2p-key-in-base58} → redirect → ipns://{libp2p-key-in-cidv1} # Base58, does not work as Origin authority
ipns://{dnslink}
ipfs://{dnslink} → redirect → ipns://{dnslink} # just to improve UX :-)
When origin-based security perimeter is needed, CIDv1 in Base32 (RFC4648, no padding) or Base36 (for libp2p-keys) should be used in subdomain:
https://{cid}.ipfs.{gateway-host}/path/to/resource
https://{libp2p-key-cid}.ipns.{gateway-host}/path/to/resource
Example:
https://bafybeiemxf5abjwjbikoz4mc3a3dla6ual3jsgpdr4cjr3oz3evfyavhwq.ipfs.dweb.link/wiki/
The subdomain gateway feature in go-ipfs takes care of necessary CID conversion when IPFS path is requested:
https://dweb.link/ipfs/QmT5NvUtoM5nWFfrQdVrFtvGfKFmG7AHE8P34isapyhCxX/wiki/Mars.html → HTTP 301
→ https://bafybeicgmdpvw4duutrmdxl4a7gc52sxyuk7nz5gby77afwdteh3jc5bqa.ipfs.dweb.link/wiki/Mars.html
Read more: notes on addressing with HTTP.
Outside of browser context, and in cases when site isolation does not matter (see security WARNING), a gateway can expose IPFS namespaces as regular URL paths under a single origin:
https://{gateway-host}/ipfs/{cid}/path/to/resource
https://{gateway-host}/ipns/{libp2p-key-or-dnslink}/path/to/resource
Examples:
https://dweb.link/ipfs/bafybeiemxf5abjwjbikoz4mc3a3dla6ual3jsgpdr4cjr3oz3evfyavhwq/wiki/Vincent_van_Gogh.html
https://dweb.link/ipfs/QmT5NvUtoM5nWFfrQdVrFtvGfKFmG7AHE8P34isapyhCxX/wiki/Mars.html
https://dweb.link/ipns/tr.wikipedia-on-ipfs.org/wiki/
Where possible, subdomain convention should be replaced with a protocol handler that provides the same origin-based guarantees:
ipfs://{cid}/path/to/resource
Example:
ipfs://bafybeiemxf5abjwjbikoz4mc3a3dla6ual3jsgpdr4cjr3oz3evfyavhwq/wiki/Vincent_van_Gogh.html
Read more: notes on addressing with ipfs://.
- The four stages of the upgrade path for path addressing
- CID as a Subdomain
- IPFS: Migration to CIDv1 (default base32)
- Support Custom Protocols in WebExtension
- mozilla/libdweb experiment: ipfs:// protocol handler
The first stage on the upgrade path are HTTP gateways.
Gateways are provided strictly for convenience to help tools that speak HTTP but do not speak distributed protocols such as IPFS. This approach has been working well since 2015 but comes with a significant set of limitations related to the centralized nature of HTTP and some of its semantics. Location-based addressing of a gateway depends on both DNS and HTTPS/TLS, which relies on the trust in Certificate Authorities and PKI. In the long term these issues SHOULD be mitigated by use of opportunistic protocol upgrade schemes.
Tools and browser extensions SHOULD detect valid IPFS paths and resolve them directly over IPFS protocol and use HTTP gateway ONLY as a fallback when no native implementation is available to ensure a smooth, backward-compatible transition.
In the most basic scheme an URL path used for content addressing is effectively a resource name without a canonical location. HTTP Gateway provides the location part, which makes it possible for browsers to interpret content path as relative to the current server and just work without a need for any conversion.
HTTP gateway SHOULD:
- Take advantage of existing caching primitives, namely:
- Set
Etag
HTTP header to the canonical CID of returned payload - Set
Cache-Control: public,max-age=29030400,immutable
if resource belongs to immutable namespace (eg./ipfs/*
)
- Set
- set
Suborigin
header based on the hash of the root of current content tree - provide a meaningful directory index for root resources representing file system trees
HTTP gateway MAY:
- Customize style of directory index.
- Return a custom payload along with error responses (HTTP 400 etc).
- Provide a writable (
POST
,PUT
) access to exposed namespaces.
Gateway operator MAY work around single Origin limitation by creating artificial
subdomains based on URL-safe version of root content identifier (eg.
{cidv1b32}.ipfs.foo.tld
). Each subdomain provides separate Origin and creates an
isolated security context at a cost of obfuscating path-based addressing.
Benefits of this approach:
- The ability to do proper security origins without introducing any changes to preeexisting HTTP stack.
- Root path of content-addressed namespace becomes the root of URL path, which
makes asset adressing compatible with existing web browsers:
<img src="/rootimg.jpg">
- Opens up the ability for HTTP Host header and TLS SNI parsing, which is a prerequisite for fully automated deployment of TLS via Let's Encrypt.
According to RFC 1035 subdomains (aka "labels", hostnames) are case-insensitive, which severly constraints the number of content addressing identifier types that can be used without need for an additional conversion step.
Due to this IPFS community decided to use lowercased base32 (RFC4648 - no padding - highest letter) as the default base encoding of CIDv1 (our binary identifiers).
Suborigins are a work-in-progress standard to provide a new mechanism for allowing sites to separate their content by creating synthetic origins while serving content from a single physical origin.
A suborigin
header
SHOULD be returned by HTTP gateway and contain a value
unique to the current content addressing root.
Unfortunately due to limited adoption suborigin has no practical use and is considered abandoned.
The ipfs://
protocol scheme follows the same requirement of CIDv1 in Base32 as subdomains.
It does not retain original path, but instead requires a conversion step to/from URI:
ipfs://{immutable-root}/path/to/resourceA
→/ipfs/{immutable-root}/path/to/resourceA
ipns://{mutable-root}/path/to/resourceB
→/ipns/{mutable-root}/path/to/resourceB
The first element after double slash is an opaque identifier representing the content root. It is interpreted as an authority component used for Origin calculation, which provides necessary isolation between security contexts of diferent content trees.
We explored the idea of a shared dweb
namespace to remove the complexity of adressing IPFS and other content-addressed protocols. More details can be found at:
- (A) the
dweb://
protocol handler (arewedistributedyet/issues/28) - (B) the
.dweb
special-use top-level domain name (arewedistributedyet/issues/34)
Unfortunately, a single scheme is not compatible with the security model on the web. Consider this highly experimentsl, do not use this in production.
If anyone wants to implement it in a safe way, it needs to return a redirect to ipfs://
or ipns://
.