I recently acquired a Lenovo L470 laptop for cheap, and I will be using it as a hypervisor to run my home automation VM on it.
Basically the benefit is that it consumes low power, has a built-in UPS, a built-in keyboard and screen.
First, I create a USB drive that will be used to boot arch install media.
Wrote the iso disk image to the drive following the arch wiki. Then I booted in, had to change the password so that I can log in through ssh.
Ran this script on the target machine
Then I booted up the new system, but network was not available.
First I thought that the driver was not loaded, but that wasn't the
case. It turned out that the install script was not configuring the
right interface. The install script was used originally for virtual
machines, and in those cases the name of the interface was enp1s0
but given that this was a physical machine, the assigned device name
was different.
this part of the script was not good
[Match]
Name=enp1s0
[Network]
DHCP=yes
So I have corrected it to wired0
:
$ cat /etc/systemd/network/20-wired.network
[Match]
Name=wired0
[Network]
DHCP=yes
And added an udev rule so that if a network device is seen with the
particular mac address, always the name wired0
will be assigned:
$ cat /etc/udev/rules.d/10-network.rules
SUBSYSTEM=="net", ACTION=="add", ATTR{address}=="XX:XX:XX:XX:XX:XX", NAME="wired0", ENV{NM_UNMANAGED}="1"
The last part, the ENV{NM_UNMANAGED}="1"
is there, so that network
manager should not manage it. It is really important in the case when
you have a graphical environment.
Also configured a bridge device, as that will be the network to which all my virtual machines will be connected.
# cat /etc/systemd/network/pubbr.netdev
[NetDev]
Name=pubbr
Kind=bridge
# cat /etc/systemd/network/pubbr.network
[Match]
Name=pubbr
[Network]
Address=192.168.114.1/24
ConfigureWithoutCarrier=yes
When doing networkctl
it was still showing as no-carrier
, but
this could be ignored. I believe once a device is added to the
bridge, it will become routable
$ networkctl
IDX LINK TYPE OPERATIONAL SETUP
1 lo loopback carrier unmanaged
2 pubbr bridge no-carrier configured
3 wired0 ether routable configured
4 wwp0s20f0u9i12 wwan off unmanaged
5 wlp5s0 wlan off unmanaged
Then I installed libvirt, an qemu-base
. Later it turned out that
one needs to install qemu-full
, and also when I tried to connect to
this machine remotely with a virt-manager, it turned out that I also need
openbsd-netcat
as well. So this is the final list of packages that need
to be installed in order to be able to run virtual machines:
pacman -S libvirt qemu-full openbsd-netcat
Making myself part of libvirt
and starting services:
# gpasswd --add matelakat libvirt
# systemctl enable libvirtd.service
# systemctl start libvirtd.service
# systemctl start virtlogd.service
For my virtual machines I also need a dns and a dhcp server, so I install
dnsmasq
pacman -S dnsmasq
I had to change the following bits:
bind-interfaces
interface pubbr
dhcp-range=192.168.114.50,192.168.114.150,12h
Then enable/start it:
systemctl start dnsmasq.service
systemctl enable dnsmasq.service
Bash completion is also a nice-to have thing
pacman -S bash-completion
Firewall. I decided I am not going to install shorewall this time, I will learn something that is more mainstream.
sudo pacman -S firewalld
sudo systemctl enable --now firewalld.service
Added wired0
to the public zone, and set it up so that it
does masquerading, and also by default it drops incoming connections.
firewall-cmd --zone=public --add-interface=wired0 --permanent
firewall-cmd --zone=public --add-masquerade --permanent
firewall-cmd --zone=public --set-target=DROP --permanent
Then created a new zone, named it pubbr
:
firewall-cmd --permanent --new-zone=pubbr
firewall-cmd --zone=pubbr --add-interface=pubbr --permanent
firewall-cmd --zone=pubbr --add-source=192.168.114.0/24 --permanent
firewall-cmd --zone=pubbr --add-service={dhcp,dns} --permanent
firewall-cmd --zone=pubbr --add-masquerade --permanent
And introduced a new policy that will enable the flow in between
pubbr
and public
firewall-cmd --new-policy NAT_pubbr_to_ext --permanent
firewall-cmd --permanent --policy NAT_pubbr_to_ext --add-ingress-zone pubbr
firewall-cmd --permanent --policy NAT_pubbr_to_ext --add-egress-zone public
firewall-cmd --permanent --policy NAT_pubbr_to_ext --set-target ACCEPT
Also given that this is a laptop, I wanted to disable the actions when the lid was closed, so the computer keeps running:
in /etc/systemd/logind.conf
do the following:
HandleLidSwitch=ignore
HandleLidSwitchExternalPower=ignore
And then
systemctl reload systemd-logind.service
This article was very useful to set up the firewall: - https://eldon.me/arch-linux-based-home-router-part-iii-firewalld-configuration/
Forward port
# firewall-cmd --permanent --add-rich-rule='rule family="ipv4" destination address="192.168.0.94" forward-port port="2222" protocol="tcp" to-port="22" to-addr="192.168.114.120"'
# firewall-cmd --reload
NTP Client
I will use the simple systemd based ntp client
First, let's check the status
$ timedatectl show --all
Timezone=Europe/Budapest
LocalRTC=no
CanNTP=yes
NTP=no
NTPSynchronized=no
TimeUSec=Sat 2024-12-14 06:59:06 CET
RTCTimeUSec=Sat 2024-12-14 06:59:29 CET
Edit /etc/systemd/timesyncd.conf
[Time]
NTP=0.hu.pool.ntp.org 1.hu.pool.ntp.org 2.hu.pool.ntp.org 3.hu.pool.ntp.org
FallbackNTP=0.hu.pool.ntp.org 1.hu.pool.ntp.org 2.hu.pool.ntp.org 3.hu.pool.ntp.org
Then start and enable it:
$ sudo systemctl enable --now systemd-timesyncd
Let's see it running
$ timedatectl show --all
Timezone=Europe/Budapest
LocalRTC=no
CanNTP=yes
NTP=yes
NTPSynchronized=yes
TimeUSec=Sat 2024-12-14 07:04:12 CET
RTCTimeUSec=Sat 2024-12-14 07:04:12 CET