How to setup networking on Debian 9 Stretch with systemd

Debian 9 uses systemd by default to manage its network interfaces.

We are going to configure the public network interface and a private network interface. We also are going to add some additional ip addresses in alias mode to the public interface. Alias mode allows us to use multiple ip addresses for a single network interface.

Private network configuration

First, lets find the MAC address for each network interface.

~# ip address
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1
 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
 inet 127.0.0.1/8 scope host lo
 valid_lft forever preferred_lft forever
 inet6 ::1/128 scope host
 valid_lft forever preferred_lft forever
2: bond0: <BROADCAST,MULTICAST,MASTER> mtu 1500 qdisc noop state DOWN group default qlen 1000
 link/ether 26:c1:29:65:b1:c0 brd ff:ff:ff:ff:ff:ff
3: dummy0: <BROADCAST,NOARP> mtu 1500 qdisc noop state DOWN group default qlen 1000
 link/ether 62:76:42:35:5d:e9 brd ff:ff:ff:ff:ff:ff
4: ifb0: <BROADCAST,NOARP> mtu 1500 qdisc noop state DOWN group default qlen 32
 link/ether 5e:6c:0c:62:0d:e2 brd ff:ff:ff:ff:ff:ff
5: ifb1: <BROADCAST,NOARP> mtu 1500 qdisc noop state DOWN group default qlen 32
 link/ether 5a:41:08:e6:1a:ba brd ff:ff:ff:ff:ff:ff
6: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
 link/ether a4:bf:01:25:75:36 brd ff:ff:ff:ff:ff:ff
 inet 54.37.87.106/24 brd 54.37.87.255 scope global eth0
 valid_lft forever preferred_lft forever
 inet6 2001:41d0:303:4f6a::/64 scope global
 valid_lft forever preferred_lft forever
 inet6 fe80::a6bf:1ff:fe25:7536/64 scope link
 valid_lft forever preferred_lft forever
7: eno2: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
 link/ether a4:bf:01:25:75:37 brd ff:ff:ff:ff:ff:ff
8: teql0: <NOARP> mtu 1500 qdisc noop state DOWN group default qlen 100
 link/void
9: tunl0@NONE: <NOARP> mtu 1480 qdisc noop state DOWN group default qlen 1
 link/ipip 0.0.0.0 brd 0.0.0.0
10: gre0@NONE: <NOARP> mtu 1476 qdisc noop state DOWN group default qlen 1
 link/gre 0.0.0.0 brd 0.0.0.0
11: gretap0@NONE: <BROADCAST,MULTICAST> mtu 1462 qdisc noop state DOWN group default qlen 1000
 link/ether 00:00:00:00:00:00 brd ff:ff:ff:ff:ff:ff
12: sit0@NONE: <NOARP> mtu 1480 qdisc noop state DOWN group default qlen 1
 link/sit 0.0.0.0 brd 0.0.0.0
13: ip6tnl0@NONE: <NOARP> mtu 1452 qdisc noop state DOWN group default qlen 1
 link/tunnel6 :: brd ::

Here we can identify the two main network interfaces:

  • the public network interface eth0 with MAC address a4:bf:01:25:75:36 is assigned the ip address 54.37.87.106 and is currently up
  • the additional network interface eno2 with MAC address a4:bf:01:25:75:37 is currently down with no ip address assigned yet. This interface will be used as a private network interface

We can take a look at the primary network interface configuration in /etc/systemd/network folder. This folder contains 2 configuration files to setup the public interface. This configuration is already in place when you order a dedicated server provided by OVH.

~# ls /etc/systemd/network
50-default.network 50-public-interface.link
~# cat /etc/systemd/network/50-default.network
# This file sets the IP configuration of the primary (public) network device.
# You can also see this as "OSI Layer 3" config.
# It was created by the OVH installer, please be careful with modifications.
# Documentation: man systemd.network or https://www.freedesktop.org/software/systemd/man/systemd.network.html

[Match]
MACAddress=a4:bf:01:25:75:36

[Network]
Description=network interface on public network, with default route
DHCP=no
Address=54.37.87.106/24
Gateway=54.37.87.254
#IPv6AcceptRA=false
NTP=ntp.ovh.net
DNS=127.0.0.1
DNS=213.186.33.99
DNS=2001:41d0:3:163::1
Gateway=2001:41d0:0303:4fff:ff:ff:ff:ff

[Address]
Address=2001:41d0:0303:4f6a::/64

[Route]
Destination=2001:41d0:0303:4fff:ff:ff:ff:ff
Scope=link
~# cat /etc/systemd/network/50-public-interface.link
# This file configures the relation between network device and device name.
# You can also see this as "OSI Layer 2" config.
# It was created by the OVH installer, please be careful with modifications.
# Documentation: man systemd.link or https://www.freedesktop.org/software/systemd/man/systemd.link.html

[Match]
MACAddress=a4:bf:01:25:75:36

[Link]
Description=network interface on public network, with default route
MACAddressPolicy=persistent
NamePolicy=kernel database onboard slot path mac
#Name=eth0 # name under which this interface is known under OVH rescue system
#Name=eno1 # name under which this interface is probably known by systemd

We will take inspiration from these files to configure the private network interface by creating 2 new files /etc/systemd/network/50-private.network and /etc/systemd/network/50-private-interface.link:

~# vim /etc/systemd/network/50-private.network
[Match]
# The MAC address we noted earlier for the private interface
MACAddress=a4:bf:01:25:75:37
 
[Network]
Description=network interface on private network
DHCP=no
# The ip address we want to assign to this machine on the private network
Address=192.168.0.20/16
~# vim /etc/systemd/network/50-private-interface.link
[Match]
# The MAC address we noted earlier for the private interface
MACAddress=a4:bf:01:25:75:37

[Link]
Description=network interface on private network
MACAddressPolicy=persistent
# The interface name will be defined automatically by the system
NamePolicy=kernel database onboard slot path mac

Finally, we just have to tell systemd to load the new configuration:

~# systemctl restart systemd-networkd

We can now verify that everything is ok:

~# ip address
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1
 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
 inet 127.0.0.1/8 scope host lo
 valid_lft forever preferred_lft forever
 inet6 ::1/128 scope host
 valid_lft forever preferred_lft forever
2: bond0: <BROADCAST,MULTICAST,MASTER> mtu 1500 qdisc noop state DOWN group default qlen 1000
 link/ether 26:c1:29:65:b1:c0 brd ff:ff:ff:ff:ff:ff
3: dummy0: <BROADCAST,NOARP> mtu 1500 qdisc noop state DOWN group default qlen 1000
 link/ether 62:76:42:35:5d:e9 brd ff:ff:ff:ff:ff:ff
4: ifb0: <BROADCAST,NOARP> mtu 1500 qdisc noop state DOWN group default qlen 32
 link/ether 5e:6c:0c:62:0d:e2 brd ff:ff:ff:ff:ff:ff
5: ifb1: <BROADCAST,NOARP> mtu 1500 qdisc noop state DOWN group default qlen 32
 link/ether 5a:41:08:e6:1a:ba brd ff:ff:ff:ff:ff:ff
6: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
 link/ether a4:bf:01:25:75:36 brd ff:ff:ff:ff:ff:ff
 inet 54.37.87.106/24 brd 54.37.87.255 scope global eth0
 valid_lft forever preferred_lft forever
 inet6 2001:41d0:303:4f6a::/64 scope global
 valid_lft forever preferred_lft forever
 inet6 fe80::a6bf:1ff:fe25:7536/64 scope link
 valid_lft forever preferred_lft forever
7: eno2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
 link/ether a4:bf:01:25:75:37 brd ff:ff:ff:ff:ff:ff
 inet 192.168.0.20/16 brd 192.168.255.255 scope global eno2
 valid_lft forever preferred_lft forever
 inet6 fe80::a6bf:1ff:fe25:7537/64 scope link
 valid_lft forever preferred_lft forever
8: teql0: <NOARP> mtu 1500 qdisc noop state DOWN group default qlen 100
 link/void
9: tunl0@NONE: <NOARP> mtu 1480 qdisc noop state DOWN group default qlen 1
 link/ipip 0.0.0.0 brd 0.0.0.0
10: gre0@NONE: <NOARP> mtu 1476 qdisc noop state DOWN group default qlen 1
 link/gre 0.0.0.0 brd 0.0.0.0
11: gretap0@NONE: <BROADCAST,MULTICAST> mtu 1462 qdisc noop state DOWN group default qlen 1000
 link/ether 00:00:00:00:00:00 brd ff:ff:ff:ff:ff:ff
12: sit0@NONE: <NOARP> mtu 1480 qdisc noop state DOWN group default qlen 1
 link/sit 0.0.0.0 brd 0.0.0.0
13: ip6tnl0@NONE: <NOARP> mtu 1452 qdisc noop state DOWN group default qlen 1
 link/tunnel6 :: brd ::

The interface eno2 is up with the ip address 192.168.0.20 assigned to it.

We can now ping another server that is a member of the private network at the address 192.168.0.21:

~# ping 192.168.0.21
PING 192.168.0.21 (192.168.0.21) 56(84) bytes of data.
64 bytes from 192.168.0.21: icmp_seq=1 ttl=64 time=0.435 ms
64 bytes from 192.168.0.21: icmp_seq=2 ttl=64 time=0.235 ms
64 bytes from 192.168.0.21: icmp_seq=3 ttl=64 time=0.236 ms
64 bytes from 192.168.0.21: icmp_seq=4 ttl=64 time=0.233 ms
64 bytes from 192.168.0.21: icmp_seq=5 ttl=64 time=0.236 ms
64 bytes from 192.168.0.21: icmp_seq=6 ttl=64 time=0.237 ms
64 bytes from 192.168.0.21: icmp_seq=7 ttl=64 time=0.203 ms
^C
--- 192.168.0.21 ping statistics ---
7 packets transmitted, 7 received, 0% packet loss, time 6126ms
rtt min/avg/max/mdev = 0.203/0.259/0.435/0.073 ms

Additional ip address on the public interface

To add an aliased ip address to the public interface, we have to edit the public interface configuration file and add one line for the additional ip address:

~# vim /etc/systemd/network/50-default.network
# This file sets the IP configuration of the primary (public) network device.
# You can also see this as "OSI Layer 3" config.
# It was created by the OVH installer, please be careful with modifications.
# Documentation: man systemd.network or https://www.freedesktop.org/software/systemd/man/systemd.network.html

[Match]
MACAddress=a4:bf:01:25:75:36

[Network]
Description=network interface on public network, with default route
DHCP=no
Address=54.37.87.106/24
# Here we add the additional ip address
Address=178.33.18.200
Gateway=54.37.87.254
#IPv6AcceptRA=false
NTP=ntp.ovh.net
DNS=127.0.0.1
DNS=213.186.33.99
DNS=2001:41d0:3:163::1
Gateway=2001:41d0:0303:4fff:ff:ff:ff:ff

[Address]
Address=2001:41d0:0303:4f6a::/64

[Route]
Destination=2001:41d0:0303:4fff:ff:ff:ff:ff
Scope=link

We reload the network configuration:

~# systemctl restart systemd-networkd

We check whether or not the configuration has been applied:

~# ip address
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1
 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
 inet 127.0.0.1/8 scope host lo
 valid_lft forever preferred_lft forever
 inet6 ::1/128 scope host
 valid_lft forever preferred_lft forever
2: bond0: <BROADCAST,MULTICAST,MASTER> mtu 1500 qdisc noop state DOWN group default qlen 1000
 link/ether 02:01:de:2a:c5:58 brd ff:ff:ff:ff:ff:ff
3: dummy0: <BROADCAST,NOARP> mtu 1500 qdisc noop state DOWN group default qlen 1000
 link/ether ce:30:48:31:20:46 brd ff:ff:ff:ff:ff:ff
4: ifb0: <BROADCAST,NOARP> mtu 1500 qdisc noop state DOWN group default qlen 32
 link/ether 2e:09:09:4b:90:0a brd ff:ff:ff:ff:ff:ff
5: ifb1: <BROADCAST,NOARP> mtu 1500 qdisc noop state DOWN group default qlen 32
 link/ether ee:bd:5a:f9:ea:1e brd ff:ff:ff:ff:ff:ff
6: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
 link/ether a4:bf:01:25:75:36 brd ff:ff:ff:ff:ff:ff
 inet 54.37.87.106/24 brd 54.37.87.255 scope global eth0
 valid_lft forever preferred_lft forever
 inet 178.33.18.200/16 brd 178.33.255.255 scope global eth0
 valid_lft forever preferred_lft forever
 inet6 2001:41d0:303:4f6a::/64 scope global
 valid_lft forever preferred_lft forever
 inet6 fe80::a6bf:1ff:fe25:7536/64 scope link
 valid_lft forever preferred_lft forever
7: eno2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
 link/ether a4:bf:01:25:75:37 brd ff:ff:ff:ff:ff:ff
 inet 192.168.0.20/16 brd 192.168.255.255 scope global eno2
 valid_lft forever preferred_lft forever
 inet6 fe80::a6bf:1ff:fe25:7537/64 scope link
 valid_lft forever preferred_lft forever
8: teql0: <NOARP> mtu 1500 qdisc noop state DOWN group default qlen 100
 link/void
9: tunl0@NONE: <NOARP> mtu 1480 qdisc noop state DOWN group default qlen 1
 link/ipip 0.0.0.0 brd 0.0.0.0
10: gre0@NONE: <NOARP> mtu 1476 qdisc noop state DOWN group default qlen 1
 link/gre 0.0.0.0 brd 0.0.0.0
11: gretap0@NONE: <BROADCAST,MULTICAST> mtu 1462 qdisc noop state DOWN group default qlen 1000
 link/ether 00:00:00:00:00:00 brd ff:ff:ff:ff:ff:ff
12: sit0@NONE: <NOARP> mtu 1480 qdisc noop state DOWN group default qlen 1
 link/sit 0.0.0.0 brd 0.0.0.0
13: ip6tnl0@NONE: <NOARP> mtu 1452 qdisc noop state DOWN group default qlen 1
 link/tunnel6 :: brd ::

We verify that we can now use this ip address:

~# curl --head --interface 178.33.18.200 https://example.com
HTTP/2 200
accept-ranges: bytes
cache-control: max-age=604800
content-type: text/html
date: Mon, 30 Apr 2018 07:37:45 GMT
etag: "1541025663+ident"
expires: Mon, 07 May 2018 07:37:45 GMT
last-modified: Fri, 09 Aug 2013 23:54:35 GMT
server: ECS (dca/24C1)
x-cache: HIT
content-length: 1270
Leave a comment