Simple Home DNS using dnscrypt-proxy
Making your hosts easily accessible on your home network is a something that can be tackled in a variety of ways. Each of these solutions come with their pros and cons regarding ease of use, adaptability and requirements for the devices on your network.
Let’s take mDNS for example: it’s easy to set up and works mostly fine with Linux hosts. However, even Android devices pose a problem, as they don’t support it. That means you can’t use it to resolve hosts on your phone or tablet.
Another approach is probably NetBIOS / winbind. I did not explore this as I’m happy when I can avoid Samba.
Nevertheless, these two come with a significant downside: lack of certificates. One might try to set up their own Certificate Authority, but then these would need to be deployed on devices that often aren’t managed at the required level (like phones without a Enterprise Mobility Management solution). So I went for a in my opinion easy approach: a local DNS cache that allows easy definition of my own domains.
The complete setup also consists of TLS with ACME and an nginx reverse proxy. These parts are synergetic with DNS, but not required. You can just use the parts of this guide to e.g. ssh into your local machine using “hostname.internal.network.tld” and call it a day. However, in my opinion, it only gets interesting and useful when the components work all together, but this would be too long for this post. As such, see the examples as teasers for more possibilities that this setup enables.
This is not a “definite guide” or anything, but rather a bit of documentation of how I tackled the problem and hopefully basis for a discussion. Feel free to comment on where I post this!
Requirements
For this to work, you need a domain name of your own that you control. Get one from a provider with API access as this is required for wildcard certificates.
This post does not go into how to set up ACME on NixOS.
Enter dnscrypt-proxy
dnscrpyt-proxy is
A flexible DNS proxy, with support for modern encrypted DNS protocols such as DNSCrypt v2, DNS-over-HTTPS, Anonymized DNSCrypt and ODoH (Oblivious DoH).
While these are nice features to get domain names from an upstream, we’re looking for what this service calls Cloaking. This allows to override specific domains with our own destinations, like
a HOSTS (or /etc/hosts) file on steroids
So really simple stuff, if you know how those files look.
Obviously, for this to work, you need to ensure that your devices always get the same IP on your home network. My router has an option to always assign the same address to a device for IPv4. For IPv6, I use Unique Local Addresses (ULAs).
An example NixOS configuration module
To enable this service with reasonable defaults on a device and open the firewall ports, this is sufficient:
1 _:
2
3{
4 services.dnscrypt-proxy2 = {
5 enable = true;
6 settings = {
7 cloaking_rules = ./cloaking-rules.txt;
8 listen_addresses = [
9 "192.168.178.10:53"
10 "127.0.0.1:53"
11 "[::1]:53"
12 "[fdaa:66e:6af0:0:443a:53ff:fecb:99e5]:53"
13 ];
14 };
15 };
16 networking.firewall.allowedTCPPorts = [ 53 ];
17 networking.firewall.allowedUDPPorts = [ 53 ];
18}
These are the loopback addresses and the LAN addresses for the device. Since I’m managing those from my router, I can’t refer to config values here.
The cloaking rules file could look like this:
1powerbox.internal.pc-hass.de 192.168.178.72
2powerbox.internal.pc-hass.de fdaa:66e:6af0:0:3071:91ff:fed1:9e26
3
4odroid.internal.pc-hass.de 192.168.178.12
5odroid.internal.pc-hass.de fdaa:66e:6af0:0:21e:6ff:fe45:59e3
6
7internal.pc-hass.de 192.168.178.10
8internal.pc-hass.de fdaa:66e:6af0:0:443a:53ff:fecb:99e5
9idm.pc-hass.de 192.168.178.10
10idm.pc-hass.de fdaa:66e:6af0:0:443a:53ff:fecb:99e5
11
12fritz.box 192.168.178.1
13fritz.box fdaa:66e:6af0::de39:6fff:fe6f:6046
This registers the addresses for my Odroid and Workstation hosts, both for IPv4 and IPv6. The lines starting with internal
in my case refer to this device itself. You can’t use loopback addresses here for obvious reasons.
Anyhow, the way dnscrypt-proxy works is that it will resolve the same address for all subdomains if it matches a domain in this list.
That means some-service.internal.pc-hass.de
will resolve to 192.168.178.10.
I use this mechanism to reverse proxy most services through Renegade.
Identity Management (IDM) is a topic for a future post, but just to see that it’s working:

An example of a service only reachable on the local network with a valid TLS certificate
Tying it all together
To finish it all off, we make the router announce our newly setup DNS. Obviously, this depends on your device, so I’ll just post examples here:
Let’s verify that this does what we want with a dumb device, in this case, an Android phone that simply uses DHCP and has no special network configuration whatsoever:
Nice.
Additional considerations
Having a local DNS means also that additional care needs to be taken. For example, if your DNS goes down, internet access is also restricted to IP addresses for all devices not explicitly configured to use a different DNS. Also, when using ACME with DNS challenge for your home network, a different DNS server needs to be chosen because the ACME daemon will not register that the required DNS challenge has completed as dnscrypt-proxy will not relay that information, probably because that’s cloaked.
Possible changes
Since we’re using nix, we could make the cloaking rules file a nix module, where the hostname gets filled in according to something like config.networking.domain
or whatever.
However, I feel like this shouldn’t really change, especially when using an IDM.
So this is currently static.
Summary
We set up a very simple DNS server, created some rules for our home network and had the DNS propagate through our consumer grade router. This is not a solution for bigger networks, but something that works reasonably well for me. In the end, the amount of required Nix configuration was minimal, but this is also due to already having done the ACME part somewhere else. Another topic for another day. I wanted to get this out first because I think the other topics have been explored elsewhere already.