Docs · Gateway mirror
An ordinary-browser address for a name ordinary browsers can't open.
A Handshake name resolves in Wildroot and in anything else
running a Handshake resolver. In Chrome it does not exist. The mirror
gives your name a second address — <name>.hns.one —
served under a certificate issued for that exact hostname, so you can
send a link to somebody who has never heard of any of this.
What it is, precisely
The mirror is a compatibility shim. It is not a second copy of your site and it is not a proxy to a server of yours.
What it does: takes a request for <name>.hns.one,
reads the content pointer in the zone for that name — a
TXT record of the form ipfs=<cid> or
ar=<txid> — fetches those bytes from IPFS or Arweave,
and serves them. Every response carries
X-HNS-Gateway: passthrough; content addressed on
ipfs/arweave.
Because the pointer names a hash, the bytes we serve are the bytes you published, and anyone can check that independently. That is the part of the mirror that does not require trusting us.
That is inherent to any gateway: we hold the private key for
<name>.hns.one, and a visitor's browser is trusting
us not to change what it gets. The content addressing makes tampering
detectable by someone who checks — it does not make it
impossible, and the browser is not checking it for them.
The native path — opening https://yourname/ in a client
that resolves Handshake — is the trustworthy one. Wildroot always
prefers it and never routes through the mirror. Treat the mirror as
what it is: the address you give to people who are not running that
client yet.
The two modes
The distinction that matters is who answers DNS for your name.
- HNS.ONE-hostedYou delegated the name to
ns1.hns.one/ns2.hns.one. We hold the zone, so the content pointer, the gateway address record and the DANE pin are all things you edit in the panel. This is the path everything else on this site assumes. See Delegate. - PassthroughYour DNS stays exactly where it is; we touch
none of it, and you prove control with a
TXTrecord instead. In return you get the mirror hostname and its certificate.
Passthrough registration issues the DNS record and the exact
certificate, and that pipeline works. But the gateway has no code
that fetches from an origin server of yours. It serves
content-addressed bytes named by a pointer record in a zone we hold,
and nothing else — so a name whose DNS we do not serve currently
resolves to a mirror host that answers 404 Not hosted
here.
In other words: today the mirror can give you the hostname and the certificate, but it cannot serve your existing self-hosted site through them. If that is what you need, say so — it is a known gap with no code behind it yet, not a configuration you are missing.
Why the certificate has to be exact
A TLS wildcard matches exactly one label. *.hns.one covers
yourname.hns.one but cannot cover
blog.yourname.hns.one — so multi-label mirrors are
impossible without a certificate per hostname.
The second reason is blast radius: a gateway holding a broad wildcard
can impersonate every name beneath it. One certificate, one hostname,
one -d flag, issued over HTTP-01 against the exact host we
are about to serve.
# check what your mirror is actually presenting
openssl s_client -connect hns.one:443 -servername blog.10103.hns.one </dev/null \
| openssl x509 -noout -subject -ext subjectAltName
On a correctly issued mirror that prints one subject and one SAN, both your hostname.
The edge's default server block still serves a multi-SAN
*.hns.one certificate for hosts that have no per-name
block. Retiring it is the last step of the migration and is
deliberately last, because removing it first would take working names
offline. So "HNS.ONE holds no wildcard for your name" is not something
we can honestly say today.
Getting one
Start the claim
At https://app.hns.one/names/verify/. You get a token, good for 24 hours.
Publish the proof
A TXT record
at _hnsone.<name> with the value
verification=<token>. For a TLD you own, delegating
to our nameservers is accepted instead — only the holder can set NS
on-chain, so it proves the same thing.
We verify and provision
Within about five
minutes: the exact A record, a wait for it to propagate,
then certificate issuance, then the route. In that order, always —
the certificate is never requested for a name that has not just been
proved.
A label under a TLD we already operate takes a different route: the database row is the record, there is no second registry to check against, and it inherits its parent zone's wiring rather than getting a certificate of its own.
# the record you publish
_hnsone.yourname. TXT "verification=<token from the panel>"
# check it the way we will
dig +short TXT _hnsone.yourname @ns1.hns.one
Ownership monitoring and suspension
Proving control once is not enough — names change hands. Once a day we
re-check the proof for names verified by TXT:
not merely that a record exists, but that it still carries the
exact token that was consumed for that claim, compared in constant
time.
If the proof is gone, the route is suspended: the per-name server block is removed and the mirror stops being served. DNS and the certificate are deliberately left in place, so re-enabling costs no new issuance.
If the check cannot get an answer at all — a resolver blip — nothing is suspended. Unknown is not the same as absent, and a DNS hiccup must not take a working site down.
Labels issued under a TLD we operate are exempt by design — our database is the record, so there is nothing external to re-check.
Suspension removes the per-name route. Where a zone also has per-zone wildcard wiring, another server block may still match the hostname, so a suspended mirror is not guaranteed to be fully dark. We have not tested that case end to end.
And the honest scope: the one mirror live today is a label under one of our own TLDs, which is out of scope for the daily re-check. The monitoring code and its schedule are real and running; it has not yet had a third-party name to act on.
Limits
| Limit | Value | Why |
|---|---|---|
| Object size served | 25 MB | Hard cap in the gateway; larger objects return 502 |
| Content cache | 300 s | In-process, plus Cache-Control: public, max-age=300
on responses |
| Certificates per week | 50 | Let's Encrypt per registered domain — the ceiling on new mirrors per week, unless names are batched into shared certificates |
| Identical name set | 5 per week | Let's Encrypt duplicate-certificate limit, no override |
| Provisioning queue | every 5 min, 20 per run | The worker runs on the operator machine, not the edge |
| Request rate limiting | none | Specified, not deployed. Do not assume the gateway throttles anything |
Provisioning runs from the operator's machine because creating the public DNS record needs registrar credentials, which are deliberately not on the public edge. The tenant plane records the intent; home reaches out. Nothing reaches in.
Unregistered names
A hostname under hns.one that we do not serve returns
HTTP 404, "Not hosted here". It never falls back to some other
name's content, and a name whose owner has opted out of the gateway stops
resolving in the gateway form entirely rather than returning a page that
would confirm the name exists.
Our design notes say unregistered gateway names should return
NXDOMAIN, and per-name records are created with no wildcard precisely
so that becomes possible. But a *.hns.one wildcard
A record is still published today, and a DNS wildcard
answers at any depth beneath it. So anything.hns.one
currently resolves to our edge and gets a 404 from the gateway.
Retiring that wildcard is the same migration step as retiring the wildcard certificate, and it has not happened.