Programster's Blog

Tutorials focusing on Linux, programming, and open-source

Configure DHCP Server on Debian 12

About

This tutorial will show you how to configure your own DHCP server on a Debian 12 server. You may wish to do this in order to facilitate automation of your own infrastructure, as well as easily backup your network configuration through the dynamic updating and backing up of a config file or two.

In This Post

Steps

sudo apt install isc-dhcp-server

Configure Interfaces To Listen On

First we need to configure which interfaces our DHCP server should listen on:

sudo editor /etc/default/isc-dhcp-server

Specify the interfaces like so:

INTERFACESv4="enp1s0"
#INTERFACESv6="enp1s0"

Multiple Interfaces

You can specify multiple interfaces through the use of a space like so:

INTERFACESv4="eth0 eth1"

Configure DHCP Config File

Now we need to fill in the config file for DHCP:

sudo editor /etc/dhcp/dhcpd.conf

Start by setting the global settings for domain-name and domain-name-servers to be used for local clients (adjust accordingly to your network/setup):

option domain-name "programster.org";
option domain-name-servers 192.168.0.222, 192.168.0.223;

default-lease-time 600;
max-lease-time 7200;

# Uncomment the line below if we wish to show that we want to be the only DHCP server in this network:
#authoritative;

Now let's configure the DHCP range for handing out IP addresses to clients by appending the following to the file:

subnet 192.168.0.0 netmask 255.255.0.0 {
  range 192.168.2.0 192.168.2.255;
  option subnet-mask 255.255.0.0;
  option routers 192.168.0.1;
  option domain-name-servers 192.168.0.222;
}
  • The range option defines the IP range that the DHCP server should hand out to clients.
  • The subnet-mask option allows you to specify a different subnet mask for those clients being handed dynamic IPs.
  • The routers option specifies where the gateway is.
  • The domain-name-servers option specifies the DNS servers.

Set Fixed IPs

If you wish to manually specify fixed IP addresses for certain clients, then you can do so by adding configuration blocks like so:

host myHostNameHere {
  hardware ethernet 00:0D:87:B3:AE:A6;
  fixed-address 192.168.1.5;
}

Start The Service

Once you have finished performing your configurations, you can start the service by running:

sudo service isc-dhcp-server start

Likewise, if you ever wish to stop the service:

sudo service isc-dhcp-server stop

Debugging

Validate Configuration File

You can check that you have a valid dhcpd.conf file by running:

sudo dhcpd -t

If you wish to check a specific non-default config file path, then you can specify the filepath like so:

sudo dhcpd -t -cf /etc/dhcp/dhcpd.conf

LIst Leases

If you wish to see the DHCP leases that your server has handed out, run the following command:

sudo dhcp-lease-list

You should get some output similar to below:

To get manufacturer names please download http://standards-oui.ieee.org/oui.txt to /usr/local/etc/oui.txt
Reading leases from /var/lib/dhcp/dhcpd.leases
MAC                IP              hostname       valid until         manufacturer        
===============================================================================================
14:0a:c5:82:ce:62  192.168.2.254   amazon-4080a97 2023-07-24 17:47:34 -NA-                
52:44:c4:06:f6:62  192.168.2.227   Galaxy-Tab-A8  2023-07-24 17:50:13 -NA-                
52:54:00:2b:e3:fd  192.168.2.228   zabbix-nginx   2023-07-24 17:50:32 -NA-                
52:54:00:62:16:18  192.168.2.255   mysql-example  2023-07-24 17:49:15 -NA-                
52:54:00:b0:e6:ee  192.168.2.229   -NA-           2023-07-24 17:48:23 -NA-                     
68:57:2d:5d:04:fc  192.168.2.224   -NA-           2023-07-24 17:49:18 -NA-                
68:57:2d:5d:36:93  192.168.2.248   -NA-           2023-07-24 17:49:49 -NA-                
68:57:2d:6e:37:42  192.168.2.21    -NA-           2023-07-24 17:48:16 -NA-                
68:57:2d:72:b0:e4  192.168.2.225   -NA-           2023-07-24 17:51:25 -NA-                
68:57:2d:79:9d:f7  192.168.2.226   -NA-           2023-07-24 17:47:40 -NA-                
7c:d9:5c:0b:37:37  192.168.2.11    Google-Home-Mi 2023-07-24 17:48:11 -NA-                
98:f4:ab:b7:12:9d  192.168.2.17    ESP_B7129D     2023-07-24 17:47:52 -NA-                
bc:d7:d4:59:03:11  192.168.2.247   Roku4k         2023-07-24 17:48:45 -NA-                
bc:d7:d4:59:60:dc  192.168.2.251   RokuBedroom    2023-07-24 17:48:50 -NA-                
c2:14:73:9b:03:11  192.168.2.34    Galaxy-S9      2023-07-24 17:50:19 -NA-                
cc:50:e3:ef:5d:76  192.168.2.14    ESP_EF5D76     2023-07-24 17:54:56 -NA-                
ec:b5:fa:90:3c:1f  192.168.2.230   ecb5fa903c1f   2023-07-24 17:49:27 -NA-                
f0:ef:86:18:d1:fa  192.168.2.152   Google-Home-Mi 2023-07-24 17:52:21 -NA-

Appendix

Default DHCPD Config File

Below is the default /etc/dhcp/dhcpd.conf config file that comes with Debian 12 when you install the isc-dhcp-server package.

# dhcpd.conf
#
# Sample configuration file for ISC dhcpd
#

# option definitions common to all supported networks...
option domain-name "example.org";
option domain-name-servers ns1.example.org, ns2.example.org;

default-lease-time 600;
max-lease-time 7200;

# The ddns-updates-style parameter controls whether or not the server will
# attempt to do a DNS update when a lease is confirmed. We default to the
# behavior of the version 2 packages ('none', since DHCP v2 didn't
# have support for DDNS.)
ddns-update-style none;

# If this DHCP server is the official DHCP server for the local
# network, the authoritative directive should be uncommented.
#authoritative;

# Use this to send dhcp log messages to a different log file (you also
# have to hack syslog.conf to complete the redirection).
#log-facility local7;

# No service will be given on this subnet, but declaring it helps the 
# DHCP server to understand the network topology.

#subnet 10.152.187.0 netmask 255.255.255.0 {
#}

# This is a very basic subnet declaration.

#subnet 10.254.239.0 netmask 255.255.255.224 {
#  range 10.254.239.10 10.254.239.20;
#  option routers rtr-239-0-1.example.org, rtr-239-0-2.example.org;
#}

# This declaration allows BOOTP clients to get dynamic addresses,
# which we don't really recommend.

#subnet 10.254.239.32 netmask 255.255.255.224 {
#  range dynamic-bootp 10.254.239.40 10.254.239.60;
#  option broadcast-address 10.254.239.31;
#  option routers rtr-239-32-1.example.org;
#}

# A slightly different configuration for an internal subnet.
#subnet 10.5.5.0 netmask 255.255.255.224 {
#  range 10.5.5.26 10.5.5.30;
#  option domain-name-servers ns1.internal.example.org;
#  option domain-name "internal.example.org";
#  option routers 10.5.5.1;
#  option broadcast-address 10.5.5.31;
#  default-lease-time 600;
#  max-lease-time 7200;
#}

# Hosts which require special configuration options can be listed in
# host statements.   If no address is specified, the address will be
# allocated dynamically (if possible), but the host-specific information
# will still come from the host declaration.

#host passacaglia {
#  hardware ethernet 0:0:c0:5d:bd:95;
#  filename "vmunix.passacaglia";
#  server-name "toccata.example.com";
#}

# Fixed IP addresses can also be specified for hosts.   These addresses
# should not also be listed as being available for dynamic assignment.
# Hosts for which fixed IP addresses have been specified can boot using
# BOOTP or DHCP.   Hosts for which no fixed address is specified can only
# be booted with DHCP, unless there is an address range on the subnet
# to which a BOOTP client is connected which has the dynamic-bootp flag
# set.
#host fantasia {
#  hardware ethernet 08:00:07:26:c0:a5;
#  fixed-address fantasia.example.com;
#}

# You can declare a class of clients and then do address allocation
# based on that.   The example below shows a case where all clients
# in a certain class get addresses on the 10.17.224/24 subnet, and all
# other clients get addresses on the 10.0.29/24 subnet.

#class "foo" {
#  match if substring (option vendor-class-identifier, 0, 4) = "SUNW";
#}

#shared-network 224-29 {
#  subnet 10.17.224.0 netmask 255.255.255.0 {
#    option routers rtr-224.example.org;
#  }
#  subnet 10.0.29.0 netmask 255.255.255.0 {
#    option routers rtr-29.example.org;
#  }
#  pool {
#    allow members of "foo";
#    range 10.17.224.10 10.17.224.250;
#  }
#  pool {
#    deny members of "foo";
#    range 10.0.29.10 10.0.29.230;
#  }
#}

Default DHCPD6 Config File

Below is the default /etc/dhcp/dhcpd6.conf config file:

# Server configuration file example for DHCPv6
# From the file used for TAHI tests - addresses chosen
# to match TAHI rather than example block.

# IPv6 address valid lifetime
#  (at the end the address is no longer usable by the client)
#  (set to 30 days, the usual IPv6 default)
default-lease-time 2592000;

# IPv6 address preferred lifetime
#  (at the end the address is deprecated, i.e., the client should use
#   other addresses for new connections)
#  (set to 7 days, the  usual IPv6 default)
preferred-lifetime 604800;

# T1, the delay before Renew
#  (default is 1/2 preferred lifetime)
#  (set to 1 hour)
option dhcp-renewal-time 3600;

# T2, the delay before Rebind (if Renews failed)
#  (default is 3/4 preferred lifetime)
#  (set to 2 hours)
option dhcp-rebinding-time 7200;

# Enable RFC 5007 support (same than for DHCPv4)
allow leasequery;

# Global definitions for name server address(es) and domain search list
option dhcp6.name-servers 3ffe:501:ffff:100:200:ff:fe00:3f3e;
option dhcp6.domain-search "test.example.com","example.com";

# Set preference to 255 (maximum) in order to avoid waiting for
# additional servers when there is only one
##option dhcp6.preference 255;

# Server side command to enable rapid-commit (2 packet exchange)
##option dhcp6.rapid-commit;

# The delay before information-request refresh
#  (minimum is 10 minutes, maximum one day, default is to not refresh)
#  (set to 6 hours)
option dhcp6.info-refresh-time 21600;

# Static definition (must be global)
#host myclient {
#       # The entry is looked up by this
#       host-identifier option
#               dhcp6.client-id 00:01:00:01:00:04:93:e0:00:00:00:00:a2:a2;
#
#       # A fixed address
#       fixed-address6 3ffe:501:ffff:100::1234;
#
#       # A fixed prefix
#       fixed-prefix6 3ffe:501:ffff:101::/64;
#
#       # Override of the global definitions,
#       # works only when a resource (address or prefix) is assigned
#       option dhcp6.name-servers 3ffe:501:ffff:100:200:ff:fe00:4f4e;
#
#       # For debug (to see when the entry statements are executed)
#       #  (log "sol" when a matching Solicitation is received)
#       ##if packet(0,1) = 1 { log(debug,"sol"); }
#}
#
#host otherclient {
#        # This host entry is hopefully matched if the client supplies a DUID-LL
#        # or DUID-LLT containing this MAC address.
#        hardware ethernet 01:00:80:a2:55:67;
#
#        fixed-address6 3ffe:501:ffff:100::4321;
#}

# The subnet where the server is attached
#  (i.e., the server has an address in this subnet)
#subnet6 3ffe:501:ffff:100::/64 {
#       # Two addresses available to clients
#       #  (the third client should get NoAddrsAvail)
#       range6 3ffe:501:ffff:100::10 3ffe:501:ffff:100::11;
#
#       # Use the whole /64 prefix for temporary addresses
#       #  (i.e., direct application of RFC 4941)
#       range6 3ffe:501:ffff:100:: temporary;
#
#       # Some /64 prefixes available for Prefix Delegation (RFC 3633)
#       prefix6 3ffe:501:ffff:100:: 3ffe:501:ffff:111:: /64;
#}

# A second subnet behind a relay agent
#subnet6 3ffe:501:ffff:101::/64 {
#       range6 3ffe:501:ffff:101::10 3ffe:501:ffff:101::11;
#
#       # Override of the global definitions,
#       # works only when a resource (address or prefix) is assigned
#       option dhcp6.name-servers 3ffe:501:ffff:101:200:ff:fe00:3f3e;
#
#}

# A third subnet behind a relay agent chain
#subnet6 3ffe:501:ffff:102::/64 {
#       range6 3ffe:501:ffff:102::10 3ffe:501:ffff:102::11;
#}

References

Last updated: 21st March 2024
First published: 24th July 2023