Updated Setting up dnsmasq

This commit is contained in:
pboy 2026-05-12 08:39:17 +02:00
commit 6c5d6ca8f4
2 changed files with 122 additions and 88 deletions

Binary file not shown.

View file

@ -1,28 +1,63 @@
= Setting up dnsmasq - a lightweight DHCP and DNS server
Peter Boy; Emmmanuel Seyman
:page-authors: {author}, {author_2}
:revnumber: F35-F36
:revdate: 2022-09-23
:revnumber: F35-F44
:revdate: 2026-05-11
// :revremark: a new beginning
:page-aliases: sysadmin-dnsmasq.adoc
[abstract]
____
Fedora Server Edition recommends the lightweight dnsmasq program to provide DHCP, DDNS and DNS caching service for a server and a small to medium-sized local network. It works as a NetworkManager plugin to ensure a seamless interlocking of the components. It is the preconfigured default configuration and specifically supported.
____
The Fedora Server Edition recommends using the lightweight dnsmasq program to provide a server and a small to medium-sized local network with DHCP, DDNS and DNS caching services. Fedora Server has already preconfigured it as a NetworkManager plugin to ensure seamless integration of the components.
[NOTE]
====
**Status:** checked and ready for final review (2026-05-11)
====
== Introduction
A typical usage of dnsmasq is to provide a DHCP service for a private network. It is optionally supplemented by dynamic DNS, whereby a DHCP assigned IP address gets a temporary DNS entry with the hostname of the device. Additionally, it supports static hostnames, too. Another typical use case is to provide DHCP for a public subdomain, while an official public DNS server still provides the subdomain's name resolution. Of course, devices with such an address cannot be found via DNS. They are primarily used for the initial system installation, for network-supported booting (PXE), or dynamically assigning machines, identified by their MAC address, a specific IP address. And sometimes dnsmasq is used as a caching DNS proxy without any DHCP or DDNS functionality. But since release 33, Fedora uses systemd-resolved as DNS client which includes a versatile caching. Thus, dnsmasq is no longer needed for this use case.
By default, Fedora Server uses dnsmasq to provide local DNS and DHCP services for private or public subnets. It is preconfigured as a NetworkManager plug-in to ensure seamless integration of the components.
The dnsmasq DHCP and DNS is the default and recommend way to provide these services in Fedora Server Edition. Each of the components is optional. A system can use only the DHCP part without DNS, or only DNS without DHCP, or only DHCP caching, or any combination. Each component is configured separately. It is preconfigured as a NetworkManager plugin to ensure a seamless interlocking of the components.
The DHCP component provides dynamic DNS for a DHCP-assigned IP address, offering a temporary DNS entry for the device's hostname. It also supports static hostnames. Another common use case is to provide DHCP for a public subdomain, while an official public DNS server provides name resolution for the subdomain. Devices with such an address cannot, of course, be found via DNS. These addresses are primarily used for initial system installation, network-supported booting (PXE), and for dynamically assigning a specific IP address to machines identified by their MAC address. Another capability is providing a DNS caching service. However, since release 33, Fedora has used systemd-resolved as the DNS client, which includes versatile caching. Therefore, dnsmasq is no longer required for this purpose.
The target is a small to middle-sized subnet. Usually, a server performs this task as a “side job” so to speak, and the main tasks involve other services.
Each dnsmasq component is optional. A system can use the DHCP component alone, the DNS component alone, the DHCP caching component alone, or any combination of these. Each component is configured separately.
A general determination of the upper limit is practically impossible. But as a rule of thumb, dnsmasq can easily handle 100 or more machines. Significantly larger networks primarily require better management and structuring capabilities. The __ISC DHCP Server__ would then be a more suitable choice.
The target is a small to medium-sized subnet. Typically, a server performs this task as an additional responsibility, alongside its main duties. It is practically impossible to determine the upper limit with any degree of accuracy. However, as a rule of thumb, dnsmasq can handle over 100 machines with ease. Significantly larger networks require better management and structuring capabilities. In this case, the __ISC DHCP Server__ would be a more suitable choice.
For additional information, see the _Fedora Magazine_ article https://fedoramagazine.org/using-the-networkmanagers-dnsmasq-plugin/[Using the NetworkManagers DNSMasq plugin] (2019).
== Prerequisites
All the necessary interfaces have been installed and fully configured. This includes assigning the correct firewall zones.
[source,]
----
[…]# firewall-cmd --permanent --zone=<zone_name> --change-interface=<interface_name>
[…]# firewall-cmd --reload
----
The system should automatically forward between the interfaces. Check the forwarding status and adjust it if necessary.
[source,]
----
[…]# cat /proc/sys/net/ipv4/ip_forward
[…]# cat /proc/sys/net/ipv6/conf/default/forwarding
----
In both cases a value of 1 indicates an active forwarding.
Otherwise, enable it immediately and configure it permanently.
[source,]
----
[…]# echo 1 > /proc/sys/net/ipv4/ip_forward
[…]# echo 1 > /proc/sys/net/ipv6/conf/all/forwarding
[…]# vim /etc/sysctl.d/50-enable-forwarding.conf
# local customizations
#
# enable forwarding for dual stack
net.ipv4.ip_forward=1
net.ipv6.conf.all.forwarding=1
----
== Installation
The NetworkManager dnsmasq plugin included by default provides a basic configuration skeleton, but does not install the dnsmasq package. Thus, it avoids to uselessly occupy space and to introduce a superfluous and unused binary in case dnsmasq is not going to be in use on the particular server.
@ -42,14 +77,14 @@ Calling systemctl directly would be ineffective and would rather start yet anoth
== Basic configuration
NetworkManager takes care of the dnsmasq plugin operation. Configuration files in the `/etc/NetworkManager/dnsmasq.d` directory specify the custom configuration requirements, preferably one configuration file per task. The only exception in this example is the file containing the IP - hostname mapping of for static DNS names, `/etc/dnsmasq.hosts`.
NetworkManager takes care of the dnsmasq plugin operation. Configuration files in the `/etc/NetworkManager/dnsmasq.d` directory specify the custom configuration requirements, preferably one configuration file per task. The only exception in this example is the file containing the IP - hostname mapping of static DNS names, `/etc/dnsmasq.hosts`.
[TIP]
====
NetworkManager reads all files in that directory, independantly of the file extension. So you can't temporarily deactivate a configuration by renaming it.
====
The example here uses 2 interfaces, an external public interface enp1s0 (example.com) and an internal private interface enp2s0 (example.lan). You may add any number of additional interfaces by adding corresponding config files as in the examples here.
The example here uses 2 interfaces, an external public interface enp1s0 (public.tld) and an internal private interface enp2s0 (internal.lan). You may add any number of additional interfaces by adding corresponding config files as in the examples here.
1. Activate the dnsmasq NetworkManager plugin
@ -57,25 +92,24 @@ The example here uses 2 interfaces, an external public interface enp1s0 (example
[source,]
----
[…]# vim /etc/NetworkManager/conf.d/00-use-dnsmasq.conf
<i>
# /etc/NetworkManager/conf.d/00-use-dnsmasq.conf #
# This enabled the dnsmasq plugin.
# /etc/NetworkManager/conf.d/00-use-dnsmasq.conf
# This enables the dnsmasq plugin.
[main]
dns=dnsmasq
<esc><:wq>
----
2. Configuration of the name resolution (DNS) for the private network (example.lan)
2. Configuration of the name resolution (DNS) for the internal private network (internal.lan)
+
[source,]
----
[…]# vim /etc/NetworkManager/dnsmasq.d/01-DNS-example-lan.conf
<i>
# /etc/NetworkManager/dnsmasq.d/01-DNS-example-lan.conf
# This file sets up DNS for the private local net domain example.lan
local=/example.lan/
[…]# vim /etc/NetworkManager/dnsmasq.d/01-DNS-<INTERNAL>.conf
# /etc/NetworkManager/dnsmasq.d/01-DNS-<INTERNAL>.conf
# This file sets up DNS for the private local net domain '<INTERNAL>.lan'
local=/<INTERNAL>.lan/
# file where to find the list of IP - hostname mapping
addn-hosts=/etc/dnsmasq.hosts
addn-hosts=/etc/dnsmasq-<INTERNAL>.hosts
domain-needed
bogus-priv
@ -85,33 +119,36 @@ The example here uses 2 interfaces, an external public interface enp1s0 (example
# interfaces to listen on
interface=lo
interface=enp2s0
# in case of a bridge don't use the attached server virtual ethernet interface
# The below defines a Wildcard DNS Entry.
#address=/.localnet/10.10.10.zzz
interface=<ENPxyz>
# in case of a bridge don't use the attached server virtual ethernet interface here!
# Upstream public net DNS server (max.three)
no-poll
server=134.102.xx.yy
server=134.102.uu.vv
server=2001:638:xxx:yyy::zz
<esc><:wq>
server=<uuu.vv.xx.yy>
server=<www.vv.xx.zz>
server=<2001:www:xxx:yyy::zz>
----
3. Configuration of the DHCP service for the private network (example.lan)
+
Provide an empty host file
+
[source,]
----
[…]# vim /etc/NetworkManager/dnsmasq.d/02-DHCP-example-lan.conf
# etc/NetworkManager/dnsmasq.d/02-DHCP-example-lan.conf
# This file sets up DHCP for the private local net domain example.lan
[…]# touch dnsmasq-<INTERNAL>.hosts
----
3. Configuration of the DHCP service for the internal private network (<INTERNAL>.lan)
+
[source,]
----
[…]# vim /etc/NetworkManager/dnsmasq.d/02-DHCP-<INTERNAL>.conf
# etc/NetworkManager/dnsmasq.d/02-DHCP-<INTERNAL>.conf
# This file sets up DHCP for the private local net domain '<INTERNAL>.lan'
# The domain the DHCP part of dnsmasq is responsible for:
domain=example.lan,10.10.10.0/24,local
domain=<INTERNAL>.lan,<uuu.vv.xx.y/24>,local
# interfaces to listen on
interface=enp2s0
# interfaces to listen on (redundant, same as for DNS)
interface=<ENPxyz>
# general DHCP stuff (options, see RFC 2132)
# 1: subnet masq
@ -122,32 +159,32 @@ The example here uses 2 interfaces, an external public interface enp1s0 (example
# 28: broadcast address
dhcp-authoritative
dhcp-option=1,255.255.255.0
dhcp-option=3,10.10.10.10
dhcp-option=6,10.10.10.1
dhcp-option=1,<255.255.255.24>
dhcp-option=3,<www.xxx.yy.zz>
dhcp-option=6,<www.xx.yy.z>
# Assign fixed IP addresses based on MAC address
# dhcp-host=00:1a:64:ce:89:4a,NAME01,10.10.10.50,infinite
# dhcp-host=52:54:00:42:6a:43,NAME02,10.10.10.51,infinite
# dhcp-host=00:1a:64:ce:89:4a,NAME01,www.xx.yy.zz,infinite
# dhcp-host=52:54:00:42:6a:43,NAME02,www.xx.yy.zz,infinite
# Assign dynamically IP addresses to interface to listen on
# Range for distributed addresses, tagged <int> for further references dhcp-range=tag:enp2s0,10.10.10.150,10.10.10.200,24h
# Range for distributed addresses, tagged <int> for further references
dhcp-range=tag:<ENPxyz>,<vvv.ww.xx.y,vvv.ww.xx.z>,24h
----
4. Configuration of the DHCP service for the public network (example.com)
4. Configuration of the DHCP service for the public network (<PUBLIC.TLD>)
+
[source,]
----
[…]# vim /etc/NetworkManager/dnsmasq.d/03-DHCP-example-com.conf
# etc/NetworkManager/dnsmasq.d/03-DHCP-example-com.conf
# This file sets up DNCP for the public example.com domain interface
[…]# vim /etc/NetworkManager/dnsmasq.d/03-DHCP-<PUBLIC>.conf
# etc/NetworkManager/dnsmasq.d/03-DHCP-<PUBLIC>.conf
# This file sets up DNCP for the public '<PUBLIC.TLD>' domain interface
# The domain the DHCP part of dnsmasq is responsible for:
domain=example.com,134.102.xx.yy/27
domain=<PUBLIC.TLD>,<uuu.vv.ww.xx/24>
# interfaces to listen on
interface=enp1s0
# the public interfaces to listen on
interface=<ENPuvw>
# general DHCP stuff (options, see RFC 2132)
# 1: subnet masq
@ -159,65 +196,62 @@ The example here uses 2 interfaces, an external public interface enp1s0 (example
##dhcp-authoritative
## we just send the bare minimum, e.g. no DNS server
##dhcp-option=1,255.255.255.224
dhcp-option=tag:enp1s0,option=router,134.102.3.30
##dhcp-option=1,<255.255.255.0>
dhcp-option=tag:<ENPuvw>,option=router,<uuu.vv.ww.zz>
# Assign fixed IP addresses based on MAC address
# dhcp-host=00:1a:64:ce:89:4a,thootes,10.10.10.50,infinite
# dhcp-host=52:54:00:42:6a:43,apollon,10.10.10.51,infinite
# Assign dynamically IP addresses to interface to listen on
# Range for distributed addresses, tagged <int> for further references dhcp-range=tag:enp1s0,134.102.3.19,134.102.3.26,1h
# Range for distributed addresses, tagged <int> for further references dhcp-range=tag:<ENPuvw>,<uuu.vvv.w.x,uuu.vvv.w.y6,1h
----
+
There is no DNS configuration for the external interface following, assuming that a official public DNS server is used to resolve all public facing interfaces of the domain example.com.
There is no DNS configuration for the external interface following, assuming that a official public DNS server is used to resolve all public facing interfaces of the domain public.tld.
5. Adjusting the firewall
5. Test the dnsmasq configuration
+
[source,]
----
[…]# dnsmasq --test
----
6. Adjusting the firewall
+
Allow ports for DHCP and DNS (53) service on the public interface.
+
[source,]
----
[…]# firewall-cmd --get-services
[…]# firewall-cmd --zone=FedoraServer --permanent --add-service=dhcp
[…]# firewall-cmd --zone=FedoraServer --permanent --add-service=dns
[…]# firewall-cmd --zone=<YOUR_ZONE> --permanent --add-service=dhcp
[…]# firewall-cmd --zone=<YOUR_ZONE> --permanent --add-service=dns
[…]# firewall-cmd --reload
[…]# firewall-cmd --list-all
----
6. Disabling the systemd-resolved stub resolver
+
Inhibit the stub resolver and remove the symlink /etc/resolv.conf so that Network Manager will generate a new resolv.conf directing queries to dnsmasq. For more info, see the man page for "systemd-resolved" under the heading "/ETC/RESOLV.CONF".
6. Restart NetworkManager to start dnsmasq
+
[source,]
----
[…]# find /etc/resolv.conf -printf '%p -> %l\n'
/etc/resolv.conf -> ../run/systemd/resolve/stub-resolv.conf
[…]# rm -f /etc/resolv.conf
[…]# mkdir -p /etc/systemd/resolved.conf.d
[…]# echo -e "[Resolve]\nDNSStubListener=no" > /etc/systemd/resolved.conf.d/no-stub-listener.conf
[…]# systemctl restart NetworkManager
[…]# ps -ef | grep dnsmasq
----
+
NetworkManager should have started __dnsmasq__ shown by the '__ps__'
command above.
7. Restart systemd-resolved and restart NetworkManager to start dnsmasq
+
The first time we restart systemd-resolved, it will no longer be running the stub resolver. The second time, we are reloading the configuration to prompt systemd-resolved to re-assess the /etc/resolv.conf generated by NetworkManager, but systemd-resolved does not support the "reload" unit command.
8. Restart systemd-resolved
+
[source,]
----
[…]# systemctl restart systemd-resolved
[…]# systemctl restart NetworkManager
[…]# systemctl restart systemd-resolved
[…]# systemctl restart systemd-resolved
[…]# resolvectl status
----
+
NetworkManager adjusts now the nameserver entries in /etc/resolv. They are replaced by 127.0.0.1 and processed via dnsmasq.
The systemd-resolved should recognize the dnsmasq nameserver attached to interfaces as configured.
8. Test the installation
a. The dnsmasq internal self test
+
[source,]
----
[…]# dnsmasq --test
----
b. Test DHCP in the public using a machine without IP address
9. Test the installation
a. Test DHCP in the public using a machine without IP address
+
[source,]
----
@ -227,7 +261,7 @@ b. Test DHCP in the public using a machine without IP address
[…]# dhclient -4 -1 -r -v eth0 # expected: no IPv4 again
[…]# ip a # expect no IPv4 address associated with interface again
----
c. Try on an other server
b. Try on an other server
+
[source,]
----
@ -236,6 +270,7 @@ c. Try on an other server
[…]# dhclient -v -d -s 10.10.10.1 enp6s0
----
== Masquerading / NAT
If machines in the private network need access to the public network, add masquerading / NAT to the firewall.
@ -301,7 +336,7 @@ This method is much clearer, improves maintainability and reduces sources of pot
== Integrate libvirt's virtual interface
In case libvirt and virualization including a virtual network for the virtual machines, libvirt installs and configures its own dnsmasq instance. In most cases it is just convenient, instead of replacing the libvirt _default_ network to integrate it in NetworkManagers dnsmasq plugin. Thus, two instances of dnsmasq operate along each other.
In case libvirt and virtualization including a virtual network for the virtual machines, libvirt installs and configures its own dnsmasq instance. In most cases it is just convenient, instead of replacing the libvirt _default_ network to integrate it in NetworkManagers dnsmasq plugin. Thus, two instances of dnsmasq operate along each other.
To make it work, just add onother configuration file. The example uses libvirt.lan as the libvirt virtual network domain name. Adjust as appropriate.
@ -309,15 +344,14 @@ We just add the name resolution (DNS) for the libvirt virtual network (libvirt.l
[source,]
----
[…]# vim /etc/NetworkManager/dnsmasq.d/20-DNS-libvirt-lan.conf
<i>
# /etc/NetworkManager/dnsmasq.d/20-DNS-libvirt-lan.conf
[…]# vim /etc/NetworkManager/dnsmasq.d/30-DNS-libvirt.conf
# /etc/NetworkManager/dnsmasq.d/30-DNS-libvirt.conf
# This file directs dnsmasq to forward any request to resolve
# names under the .libvirt.lan domain to 192.168.122.1, the
# local libvirt DNS server default address.
server=/libvirt.lan/192.168.122.1
<esc><:><w><q>
----
== Managing static DNS Entries