Domain Verification
Verifying domain ownership with a DNS TXT record or well-known file
Before Perimeter enables continuous monitoring for a domain — including the TLS handshake that reads live cert expiry — you must prove you control it. Two verification methods are available: a DNS TXT record, or an HTTP file at a well-known path. Both are the same fundamental patterns used across the web by ACME (Let's Encrypt), Google Search Console, GitHub Pages, and dozens of other services.
Why domain verification exists
Perimeter's passive-only architecture means it reads only public data — Certificate Transparency
logs, public DNS, and RDAP. No active scanning or probing of hosts you don't own. But the one
exception — the TLS handshake to read a live cert's not_after field — does make
an outbound connection to a server. Before making that connection to any host, Perimeter must
confirm that the person requesting monitoring actually controls the domain.
Without verification, anyone could request monitoring of a domain they do not own, causing Perimeter to make TLS connections to servers they have no relationship with. Verification closes that gap: only a domain's legitimate owner can complete the challenge, because it requires writing to DNS or serving a file from the domain's web server.
Method 1: DNS TXT record (recommended)
Add a TXT record at a specific subdomain of your domain. Perimeter performs a single DNS
resolveTxt lookup to verify the token is present. No traffic is ever sent to
any IP address your domain resolves to.
The exact record to create
Name: _perimeter.yourapp.com
Type: TXT
Value: perimeter-verify=<token>
TTL: 300 (or your registrar's minimum)
Replace <token> with the value shown in your Perimeter dashboard after
adding the domain. The token is unique to your account. For example:
_perimeter.yourapp.com. 300 IN TXT "perimeter-verify=tk_a8f3d2c1e9b047..."
Where this pattern comes from
Using a dedicated underscore-prefixed subdomain (_perimeter.) follows the same
convention as DKIM (_domainkey.), DMARC (_dmarc.), and ACME's
DNS-01 challenge (_acme-challenge.). The underscore prefix signals that this is
a protocol label rather than a hostname — it will not be resolved as a web address, and it
cannot conflict with existing services running on your domain.
Google Search Console, for example, uses a similar approach: you add a TXT record to the root
of your domain with a value like google-site-verification=abc123.... The Perimeter
variant uses a dedicated subdomain to keep the root zone clean and to make it clear what the
record is for.
DNS propagation: what to expect
After adding or changing a DNS record, the change propagates through the DNS hierarchy before all resolvers worldwide see the new value. Here is what actually happens:
- You update your registrar or DNS provider's authoritative nameserver. This is instant from the provider's perspective — the new record is in their nameserver's zone file immediately.
- The TTL on the previous record (or NXDOMAIN) governs how long caches hold the old answer. If you set a TTL of 300 seconds (5 minutes) on the new TXT record, caches that already saw a NXDOMAIN (no record) response may hold that for up to 5 minutes. Most modern resolvers respect TTLs accurately.
- Perimeter queries a public recursive resolver. If that resolver has a cached NXDOMAIN, the lookup returns nothing until the cache expires. This is the most common reason a verification attempt immediately after adding the record fails.
Practical advice: wait 60 seconds after adding the TXT record before clicking Verify. If it fails, wait another 2-3 minutes and try again. You can check what a public resolver currently sees using:
dig TXT _perimeter.yourapp.com +short @1.1.1.1
dig TXT _perimeter.yourapp.com +short @8.8.8.8
If both return your token value, Perimeter's verification lookup should succeed. If one returns it and the other does not, give it another minute — the slower resolver's cache has not yet expired.
After verification
The TXT record does not need to remain in place permanently — verification is a one-time check. However, if you rotate your verification token (you can request a new one in the dashboard), you will need to update the record. You can also leave the record in place indefinitely; it is inert beyond its verification purpose.
Method 2: HTTP well-known file
Serve the token as a plain text file at a specific URL. Perimeter performs a single HTTPS GET to that URL and checks that the response body contains the token. This is the only time Perimeter makes an outbound HTTP request to a customer host — and it is explicitly authorized by the act of placing the file.
The exact file to create
URL: https://yourapp.com/.well-known/perimeter-challenge.txt
Content: perimeter-verify=<token>
(plain text, no trailing newline required)
Caddy configuration
If Caddy is already serving yourapp.com, you need to make
/.well-known/perimeter-challenge.txt accessible. The simplest approach is to
write the file into a directory that Caddy's file_server already serves, or to
add an explicit route:
yourapp.com {
# ... your existing config ...
# Serve the verification file explicitly
handle /.well-known/perimeter-challenge.txt {
respond "perimeter-verify=tk_a8f3d2c1e9b047..."
}
}
Alternatively, write the file to disk and ensure Caddy's file_server root covers
the .well-known directory:
# Create the directory and file
mkdir -p /var/www/yourapp/.well-known
echo -n "perimeter-verify=tk_a8f3d2c1e9b047..." > /var/www/yourapp/.well-known/perimeter-challenge.txt
Gotchas with the HTTP method
-
HTTPS redirect: Perimeter connects to
https://, nothttp://. If port 443 is not yet serving (e.g., the cert hasn't been provisioned yet), the method fails. Use the DNS TXT method if you are verifying before a cert exists. -
Content-type and encoding: serve the file as
text/plain. Some frameworks encode responses in ways that mangle plain text. If Perimeter reads something other than the raw token string, verification fails. -
Authentication walls: if your app requires login for all routes (even
/.well-known/), carve out an exception for that path. Public accessibility is required for the verification GET to succeed.
Comparing the two methods
| DNS TXT | HTTP file |
|---|---|
| Works before any server is running | Requires HTTPS already working |
| No server-side change needed | Requires a file or route in your app/server |
| Subject to DNS propagation delay (usually <5 min) | Effective immediately |
| Requires DNS provider access | Requires SSH / deployment access to the server |
| Recommended for most setups | Good fallback if DNS provider access is inconvenient |
The verification is passive and non-invasive
Both verification methods involve Perimeter reading data you have intentionally placed in a
public location — a DNS record or a file at a publicly-accessible URL. Neither method involves
any scan, probe, or connection to your application. For the DNS method, no network connection
to your server ever occurs. For the HTTP method, the single HTTPS GET to the
/.well-known/ path is the only outbound request Perimeter ever makes to a
customer host — and it carries no side effects beyond reading the token string.
After verification succeeds, all ongoing monitoring returns to passive-only mode: CT log reads from crt.sh, DNS resolution from public resolvers, and RDAP queries to the relevant registries. The TLS handshake to read live cert expiry is also enabled, but only for verified, actively monitored hostnames. See the How it works page for the full technical architecture.
Ready to start? Run a free one-shot report first to see your current public footprint — no verification or account needed. Verification is only required when you subscribe to continuous monitoring.
Frequently asked
Do I need to keep the DNS TXT record in place after verification?
No. Verification is a one-time check. After Perimeter confirms the TXT record is present, your domain is marked verified and monitoring begins. You can remove the record immediately afterward. The exception is if you request a new verification token later — you would need to update the record with the new token value.
The verification check keeps failing even though I added the TXT record. What should I check?
First, confirm the record exists in a public resolver: run dig TXT _perimeter.yourapp.com +short @1.1.1.1 and dig TXT _perimeter.yourapp.com +short @8.8.8.8. If both return your token, wait another 30 seconds and try verifying again in the dashboard. If only one returns it, wait for the other resolver's cache to expire (up to your TTL value). If neither returns it, the record was not saved correctly at your DNS provider — check the exact name and value again.
Can I verify a domain that I host with Cloudflare / Route 53 / another DNS provider?
Yes. The DNS TXT method works with any DNS provider that lets you add TXT records to a subdomain — which is all of them. Add a TXT record with Name _perimeter.yourapp.com (or just _perimeter if the interface prefills the apex) and Value perimeter-verify=<token>. The record propagates from your provider's nameservers to public resolvers, and Perimeter queries a public resolver to check it.
Why does Perimeter verify ownership before monitoring? I just want to see my own domain's data.
The free one-shot report requires no verification — it reads only public CT logs, DNS, and RDAP. Verification is required only for continuous monitoring and the TLS handshake that reads live cert expiry. The TLS handshake makes an actual network connection to a server; before making that connection, Perimeter confirms you control the domain so it does not make unsolicited connections to servers you have no relationship with.
What does the _perimeter subdomain prefix mean, and is it safe to add to my DNS?
The underscore prefix (_perimeter) is a standard DNS convention for service-specific labels defined in RFC 8553. It signals that this label is a protocol identifier rather than a hostname. Records with underscore prefixes are never resolved as web addresses and do not interfere with your web server, email, or any other DNS-dependent service. They are inert beyond the specific protocol lookup that uses them.
See what the internet already knows about your domain
Free one-shot report — no signup, no credit card. Built entirely on public data.
Run the free report