Skip to content

Check it works

There are four checks, from easiest to most precise. Do at least one of the first two after every setup. A mistyped profile id is refused rather than answered unfiltered (see Your endpoints), but only the log proves the device is using the profile you meant, under the device name you meant.

Open opdns.io/check on the device, or look at the Is this device using opdns? panel under Check your setup on your profile’s Setup page in the dashboard. Both give one of these answers within a few seconds:

Answer Means
Yes the device’s DNS goes through opdns and is identified as a profile; the answer shows which server answered, the profile and device name, how the query was identified and over which transport
Another profile (Setup panel only) the device uses opdns, but with another profile than the one on the page; the panel shows its id
Not filtered the device reaches opdns but is not identified, so no profile applies: plain IPv4 DNS from a network that is not linked, or the public DoH address. Use the profile’s own address
No the device’s DNS does not go through opdns, or nothing answered within 3 seconds

The public page works for anyone, with no account; the Setup panel also compares the answer with the profile you are looking at. Check again runs it anew, for example after changing a setting.

The page makes up a random name under check.opdns.io and fetches https://<that name>/ from your browser:

  1. To connect, the browser must first look the name up, through the device’s DNS (or the browser’s own secure DNS setting, if it has one). Only opdns resolvers answer names under check.opdns.io; everywhere else the name does not exist, so the fetch fails and the answer is No.
  2. The opdns server that answers the lookup notes what it saw (the PoP, the profile, how the query was identified, the transport and the device name) under that random name, in memory, for 60 seconds. The lookup is never logged, never counted in your analytics and never charged to rate limits.
  3. The HTTPS request then reaches an opdns PoP, which returns those facts for that random name (JSON, no cookies). A fresh random name every time means a cached answer can never pass for a new one, and only someone who knows the name can read the facts. The name is not secret from your network, though: like any host name it is visible in the HTTPS connection, so someone watching your traffic during those 60 seconds could read the same facts, your profile id and device name included.

Nothing else is sent: no account, no cookie, no analytics. The dashboard panel runs the same check from your browser; it makes no API call.

For this to work, the check name must never exist in public DNS: if it did, a device on any other resolver would reach it too, and every answer would be yes. The production name check.opdns.io is planned. Today the Setup panel runs the check by itself when the page opens.

  • It checks the browser, not the whole device. A browser with its own secure DNS setting (Firefox, Chrome, Edge, Brave) is checked through that setting; other apps on the same device may use the system’s DNS, or their own. Check each browser or app you set up separately, or use the log (check 2).
  • One lookup, one moment. It does not prove that every query goes to opdns: a device with a second DNS server configured, or a network that hands out another resolver over IPv6, may still send some queries elsewhere.
  • Sometimes only “yes”. When the lookup and the HTTPS request land on different opdns servers, the answer is yes, through opdns without the profile or transport. Check again.
  • Behind a self-hosted node, the node answers the lookup itself, but the HTTPS request then goes to the node, which has no certificate for the check name, so the page cannot complete. Use the command line below, or the node’s own log.

The same name answers a TXT query with the facts, on any transport:

Terminal window
dig check.opdns.io TXT +short
kdig +https=/<profile-id>/cli-test @dns.opdns.net check.opdns.io TXT +short
"pop=ams"
"profile=abc123"
"ident=doh-path"
"transport=doh2"
"ecs=off"
"device=cli-test"

profile=none means the query was not identified; ecs says whether the profile forwards EDNS Client Subnet. A self-hosted node adds node=<name>. A and AAAA queries for the name return an opdns address, and every answer has a TTL of 0 so nothing caches it.

  1. In the dashboard, open your profile’s Logs page. It shows the most recent queries first.
  2. On the device, open any website.
  3. The queries appear within a few seconds, with the device name you chose in the Device column (empty for plain DNS, which has no device name).

If nothing appears: the device is not using the profile, or the profile’s logs are off, or its log destination is none.

  1. Add blocked.example.com to the profile’s Denylist.
  2. On the device, open http://blocked.example.com. The browser should say the site cannot be found.
  3. Remove the rule afterwards, or keep it for the next device.

Blocked answers carry an Extended DNS Error with the reason, which command-line tools print. With the denylist rule from check 3 in place:

Terminal window
kdig +https=/<profile-id>/cli-test @dns.opdns.net blocked.example.com

A block shows as NXDOMAIN (or the answer your block mode sets) with a line like:

; EDE: 17 (Filtered): (denylist: blocked.example.com)

17 Filtered means your profile blocked it. 15 Blocked means an operator-level block, which is not a setting of yours. The exact extra text depends on the list or rule that matched.

Every opdns server answers the standard identity queries, which tell you which PoP and node you reached:

Terminal window
dig @dns.opdns.net id.server TXT CH +short
dig @dns.opdns.net version.bind TXT CH +short

It also returns the node’s identity in the EDNS NSID option when asked (dig +nsid).