Tamper-proof domains
The nicest part of custom domains on Portrait was that they were not just a settings field in a database. The link between a domain and a Portrait could be reconstructed from public DNS plus an Ethereum signature.
The code called the field tld, but what we were really storing was the full root domain, like ryanshahine.me. The proof was simple: if you wanted a domain to resolve to a Portrait, you had to control the DNS for that domain and the wallet that owned the Portrait ID.
Sign the root domain
The frontend parsed the user input, reduced it to the root domain, and asked the wallet to sign one compact message: {rootDomain}={portraitId}.
That made the proof legible and portable. You could recover the signer from a normal Ethereum signed message and compare it to the owner of the Portrait ID onchain. No server secret was needed, and no private backend state was part of the proof.
const rootDomain = getRootDomain(domain)
const message = `${rootDomain}=${portraitId}`
signMessage({ message })Publish the proof in DNS
After signing, the frontend showed the user DNS instructions. Point the domain at the Portrait proxy IP with an A record and publish a TXT record containing the portraitId and the signature.
The proof was not hidden inside Portrait. It lived in public DNS, where anyone could query it.
A @ 18.214.196.199
TXT @ "portraitId=47 signature=0xabc..."Verification was public
Before persisting a domain, the backend verified the wallet signature against the exact message ${tld}=${portraitId}, confirmed the A record pointed at the proxy, and confirmed the TXT record contained the matching portraitId and signature. It also rejected domains already claimed by another Portrait.
But the backend was not the source of truth. Every piece of the proof — the wallet signature, the DNS records, the Portrait ID owner onchain — was independently inspectable. The database just cached the result after the public checks passed.
The proxy served the domain
The last mile lived in portrait-proxy-domain-service. A small proxy on a static IP terminated TLS with Let's Encrypt, read the incoming host header, resolved the domain to a Portrait, and served the right page. It also normalised www. so the root domain stayed canonical.
That is the full loop. The wallet proved ownership, DNS published the binding, the backend checked both, and the proxy made the domain live.
Why call it tamper-proof
It is not tamper-proof in the sense that nothing can ever go wrong. DNS can still be hijacked and registrars can still be compromised.
What this model gives you is tamper-evidence and independent verification. Portrait could not silently bind a domain to the wrong profile without the wallet signature and the DNS record matching. The proof was public, inspectable, and re-runnable by anyone.