Intro
Lab environments are essential for students and professionals alike. There are powerful tools available to create and configure home network environments. This post will focus on how to set up a Debian Linux server to act as a router for a home lab environment.
This setup will use systemd-networkd instead of the Debian default ifupdown network configuration tool. ifupdown uses the file /etc/network/interfaces for its main network configuration. systemd-networkd uses files under /etc/systemd/network/
Set up the Server
It is recommended to perform a minimal install of Debian. As of this writing, the next release of Debian, version 13 codenamed Trixie is getting closer to being released. I decided to use it for this router setup.
I used the debian-testing-amd64-netinst.iso daily build from cdimage.debian.org. I installed it as a virtual machine under VMware vSphere. You can install it bare-metal, under a VMware hypervisor, Hyper-V, KVM, or anywhere else you like. You will need to be able to attach/create an interface for each network you want the server to act as a router for.
Network Considerations
Under VMware vSphere I created a Distributed Port Group (DPG) on a Virtual Distributed Switch (VDS) for each network that needs to be routed, in addition to the default VM Network DPG which connects to my home network.
To start out, only attach the default VM Network DPG to the router machine which will enable connectivity to our home network. Later on, new network interfaces will be added to the router VM for each lab network. Each of these interfaces is connected to an assigned DPG for each lab network that will be routed.
Debian Setup
Install Debian using whatever ISO image you choose. I always prefer the non-graphical installation. It’s easiest to accept the defaults for everything. For disk setup it’s easiest to choose ‘everything on one partition’ and just accept the defaults.
For software packages to install uncheck everything in order to make this installation as minimal as possible.
Once installation is finished I like to do the following:
apt purge vim-tiny vim-common nano apt --no-install-recommends install vim sudo rsync nftables systemd-resolved openssh-server openssh-client cd /etc/vim head -n -4 vimrc > vimrc.local
Then edit vimrc.local and at a minimum:
Uncomment these lines:
let g:skip_defaults_vim = 1
syntax on
set background=dark
au BufReadPost * if line("'\"") > 1 && line("'\"") <= line("$") | exe "normal! g'\"" | endif
filetype plugin indent on
And change:set mouse=a " Enable mouse usage (all modes)
To:set mouse-=a " Disable mouse usage (all modes)
Finally, you can add your user to some groups:usermod -aG adm, staff, sudo, systemd-network, systemd-journal <user>
Switch to systemd-networkd
# get the name of the network adapter ip l # create systemd .network file # this example uses 'ens33' as the network adapter vi /etc/systemd/network/external.network
Example contents of external.network, assuming the interface is named ‘ens33’:
[Match] Name = ens33 [Network] DHCP = yes #Address = 192.168.0.5/24 #Gateway = 192.168.0.1 DNS = 1.1.1.1 DNS = 1.0.0.1 DNS = 2606:4700:4700::1111 DNS = 2606:4700:4700::1001 Domains = home.example.org
On my home network I assigned a static IPv4 IP address for this machine on my home router. Another alternative would be to assign a static IP IPv4 address here instead of using DHCP. If you still want an IPv6 DHCP address (recommended), then change DHCP = yes above to DHCP = ipv6 and uncomment and edit the Address = and Gateway = lines.
Set the correct perms on external.network:
chown root:systemd-network /etc/systemd/network/external.network
Now make the switch from ifupdown to systemd-networkd:
systemctl enable systemd-networkd systemctl enable systemd-resolved apt purge ifupdown systemctl start systemd-networkd systemctl start systemd-resolved
After this, check /etc/resolv.conf and make sure it is now a symlink to ../run/systemd/resolve/stub-resolv.conf
ls -l /etc/resolv.conf
Add Interfaces
Create a standard DPG for each lab network you want to use. There do not need to be any special settings, the defaults should be fine.
Edit the VM settings and add a new virtual network adapter for each lab network. Note that under vSphere you do not actually need to power down the VM in order to add new network adapters. Make sure each network is associated with the DPG for the correct lab network that will be routed through that adapter.
I recommend adding the interfaces one at a time. After each one is added check with ip l to see the assigned name of the new adapter, and set up the systemd .network file for it, as described below.
For example, let’s say you want to have the following lab networks:
net1
net2
net3
in addition to your home network. Let’s assume your standard home network is 192.168.0.0/24. For our lab networks we will use networks in the 10.0.0.0 range. 10.0.0.0 is normally a /8 subnet but in this case we will use /24 subnets:
net1: 10.0.1.0/24 net2: 10.0.2.0/24 net3: 10.2.0.0/24
We need to configure a new network interface in systemd-networkd that will act as the default gateway for each lab network:
NET IP RANGE GW net1 10.0.1.0/24 10.0.1.1 net2 10.0.2.0/24 10.0.2.1 net3 10.2.0.0/24 10.2.0.1
After adding a network adapter for each lab network then create a .network file for it. Use ip l to get the name of the new network interface. Here’s an example which assumes the new network adapter is named ens66:
/etc/systemd/network/net1.network:
[Match] Name = ens66 [Network] DHCP = no Address = 10.0.1.1/24
Repeat this process for every other network you want to add. Don’t forget to set the correct ownership on each file with chown root:systemd-network
Set up NAT
Now to set up Network Address Translation, or NAT, which is what enables the computer to act as a router.
First create /etc/sysctl.d/nat.conf with the following contents:
net.ipv4.ip_forward = 1 net.ipv6.conf.all.forwarding = 1
Apply the rules with:
sudo sysctl net.ipv4.ip_forward="1" sudo sysctl net.ipv6.conf.all.forwarding="1"
Then edit /etc/nftables.conf and add rules for NAT at the end of the file. EXT_IF should be the name of the external interface:
# NAT configuration
define EXT_IF = ens33
table ip nat {
chain postrouting {
type nat hook postrouting priority srcnat; policy accept;
# NAT for net1 subnet
ip saddr 10.0.1.0/24 oifname $EXT_IF masquerade
# NAT for net2 subnet
ip saddr 10.0.2.0/24 oifname $EXT_IF masquerade
# NAT for learn-research subnet
ip saddr 10.2.0.0/24 oifname $EXT_IF masquerade
}
}
Apply the config with systemctl reload nftables
Verify the rules with sudo nft list ruleset
IPv6
At this point if you’re smart you may have picked up that we created interfaces in networkd and set up NAT rules for IPv4 addresses only, yet we also enabled forwarding for IPv6 with sysctl.
Your home router should assign a SLAAC IPv6 address to each interface on our machine and we can use these SLAAC addresses to serve as the default IPv6 gateway for each network they are associated with.
if you want to go through the trouble of assigning your own IPv6 address to each interface you can but it’s not necessary.
Using the Router
Now we can actually use our router. What we need from the router in order to assign networking to guests on each lab network is the following:
- The IPv4 network address. For example for net1 it is 10.0.1.0/24
- The IPv4 gateway address. For net1 that is the 10.0.1.1 interface on the router.
- The IPv6 gateway address. An easy way to find this is:
# get the name of the correct adapter grep Name /etc/systemd/network/net1.network # get the IPv6 SLAAC addres for the adapter # this example uses 'ens33' ip -6 a s scope global ens33
The address is the string after ‘inet6’. That string has the prefix length appended at the end (usually it is /64) which can be disregarded. You should end up with an address like: 2600:612:8300:2a70:710:29ef:bcfd:42ac as the IPv6 gateway address.
Once you have assigned the IPv4 and IPv6 gateway to the client machines on your lab networks, they should be able to ping their respective gateways, as well as each and also outside hosts.
Incoming Traffic
To be able to route traffic in to your lab networks, you have to create network routes on the client machine(s) on your home network. For example on a Windows machine you can create routes:
# createLabRoutes.ps1
#
# PowerShell script to create routes to lab networks
#
$networks = @(
'10.0.1.0/24'
'10.0.2.0/24'
'10.2.0.0/24'
)
$external = '192.168.0.5'
$ifaceIndex = '16'
foreach ( $net in $networks )
{
New-NetRoute -DestinationPrefix $net -NextHop $external -InterfaceIndex $iface
Index
}
Use Get-NetAdapter to get the interface index of the interface connected to your home network (usually the Wifi or ethernet adapter). Assign $external to the router’s static IPv4 address for the external network.