The goal is to have our local dns resolution resolves to localhost any host name ended by certain tld (top level domain), e.g. if we want to use *.loc as tld, then example.loc should resolve to localhost, as well as any hostname ending by .loc.
This is very convenient for local development, having the chance to use different host names resolving localhost without the need of setting them up individually.
Ubuntu, as of version 20.04, uses systemd-resolved as name resolution service, and NetworkManager to handle pretty much everything related to connectivity. NetworkManager includes dnsmasq which in the past used to be enabled by default, but as now name resolution is handled by systemd-resolved, is disabled by default.
So, in order to achieve our goal, we'll enabled dnsmasq on NetworkManager and tell systemd-resolved to used it as local dns. The idea is to have systemd-resolved still handling name resolution, so everything just work as it was meant to.
To enable dnsmasq we'll have to bind it to a different IP to avoid conflicts on port 53 with systemd.
In this file, add dns=dnsmasq at the end of [main] section. This will enable dnsmasq in NetworkManager.
[main]
plugins=ifupdown,keyfile
dns=dnsmasq
[ifupdown]
managed=false
[device]
wifi.scan-rand-mac-address=noThis file shouldn't exist so we'll need to create it.
listen-address=127.0.0.2
bind-interfaces
This way will listen on 53 but binded to a 127.0.0.2, avoiding conflict with systemd.
This could be in the same previous file, but is better organized this way if want to add different rules in the future.
address=/loc/127.0.0.1
All host names ended by .loc resolves 127.0.0.1
Finally there is another file that I'm not totally sure that's needed, you could try skip this step, and instead just do it only if there is any trouble or missbehavior. This is to avoid dnsmasq overwriting /etc/resolv.conf (or reading it, not sure) and prevent it from conflicting with systemd-resolved wich is the one that manages it.
IGNORE_RESOLVCONF=yes
To tell systemd-resolved to use other dns, we have to edit next file.
Uncomment those lines
# This file is part of systemd.
#
# systemd is free software; you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
# Entries in this file show the compile time defaults.
# You can change settings by editing this file.
# Defaults can be restored by simply deleting this file.
#
# See resolved.conf(5) for details
[Resolve]
DNS=127.0.0.2
#FallbackDNS=
Domains=~loc
#LLMNR=no
#MulticastDNS=no
#DNSSEC=no
#DNSOverTLS=no
#Cache=no-negative
#DNSStubListener=yes
#ReadEtcHosts=yesIt's important to note that here, in Domains we must use the same tld that we setup previously, in this case loc. The ~loc means "everything that ends with loc. This way systemd-resolved will use that dns when resolving hostname that matches.
Once everything is done, we should restart both services.
user@computer:/$ systemctl restart NetworkManager.service
user@computer:/$ systemctl restart systemd-resolved.service
Now every .loc host name should resolve to 127.0.0.1, you can check it:
user@computer:/$ nslookup example.loc
Server: 127.0.0.53
Address: 127.0.0.53#53
Non-authoritative answer:
Name: example.loc
Address: 127.0.0.1