Install homes - step 2

Time to carry on with the changes to set up the machine correctly. Here is a TLDR of this entry

  • Setup a bridge device - no problems
  • Setup time synchronisation - no problems
  • Setup kvm - a bit of back and forth about a installing the monolithic daemon vs using separate daemons, but then deciding to go with the monolith. Also learned that I need to install dmidecode and dnsmasq as well so that the monolithic daemon is not complaining.
  • Setup dnsmasq and NAT on the host - learned that masquerading is only needed on the outgoing interface only.

Setup an ethernet bridge for Virtual Machines

[matelakat@homes ~]$ sudo tee -a /etc/systemd/network/pubbr.netdev << EOF 
[NetDev]
Name=pubbr
Kind=bridge
EOF
[matelakat@homes ~]$ sudo tee /etc/systemd/network/pubbr.network << EOF 
[Match]
Name=pubbr

[Network]
Address=192.168.115.1/24
ConfigureWithoutCarrier=yes
EOF

Reloading Configuration and getting a status

[root@homes ~]# networkctl reload
[root@homes ~]# networkctl
IDX LINK   TYPE     OPERATIONAL SETUP     
  1 lo     loopback carrier     unmanaged
  2 wired0 ether    routable    configured
  3 pubbr  bridge   no-carrier  configured

3 links listed.

Setup Time Synchronisation on the Host

First is to check the situation:

[root@homes ~]# timedatectl show --all
Timezone=Europe/Budapest
LocalRTC=no
CanNTP=yes
NTP=no
NTPSynchronized=no
TimeUSec=Sat 2026-01-17 10:51:58 CET
RTCTimeUSec=Sat 2026-01-17 10:51:58 CET

Configure NTP

[matelakat@homes ~]$ sudo tee /etc/systemd/timesyncd.conf << EOF
[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
EOF

Then start and enable it:

[matelakat@homes ~]$ sudo systemctl enable --now systemd-timesyncd

Check

[matelakat@homes ~]$ timedatectl show --all
Timezone=Europe/Budapest
LocalRTC=no
CanNTP=yes
NTP=yes
NTPSynchronized=yes
TimeUSec=Sat 2026-01-17 11:09:58 CET
RTCTimeUSec=Sat 2026-01-17 11:09:58 CET

Setup kvm

[matelakat@homes ~]$ sudo pacman -S libvirt qemu-full openbsd-netcat

I picked the default option for audio provider, jack2

Adding myself to the group and enabling KVM:

[matelakat@homes ~]$ sudo gpasswd --add matelakat libvirt
[matelakat@homes ~]$ sudo systemctl enable --now libvirtd.service

# sudo gpasswd --add matelakat libvirt
# sudo systemctl enable --now libvirtd.service

Output was something along the lines of:

Created symlink '/etc/systemd/system/multi-user.target.wants/libvirtd.service' → '/usr/lib/systemd/system/libvirtd.service'.
Created symlink '/etc/systemd/system/sockets.target.wants/virtlockd.socket' → '/usr/lib/systemd/system/virtlockd.socket'.
Created symlink '/etc/systemd/system/sockets.target.wants/virtlogd.socket' → '/usr/lib/systemd/system/virtlogd.socket'.
Created symlink '/etc/systemd/system/sockets.target.wants/libvirtd.socket' → '/usr/lib/systemd/system/libvirtd.socket'.
Created symlink '/etc/systemd/system/sockets.target.wants/libvirtd-ro.socket' → '/usr/lib/systemd/system/libvirtd-ro.socket'.
Created symlink '/etc/systemd/system/sockets.target.wants/libvirtd-admin.socket' → '/usr/lib/systemd/system/libvirtd-admin.socket'.
Created symlink '/etc/systemd/system/sockets.target.wants/virtlockd-admin.socket' → '/usr/lib/systemd/system/virtlockd-admin.socket'.
Created symlink '/etc/systemd/system/sockets.target.wants/virtlogd-admin.socket' → '/usr/lib/systemd/system/virtlogd-admin.socket'.

I am seeing interesting messages:

[matelakat@homes ~]$ systemctl status libvirtd
● libvirtd.service - libvirt legacy monolithic daemon
     Loaded: loaded (/u
sr/lib/systemd/system/libvirtd.service; enabled; preset: 
disabled)
     Active: active (running) since Sat 2026-01-17 11:18:09 CET; 1min
 36s ago
 Invocation: d1347c8d619a486a8b5322c96c14e33c
TriggeredBy: ● libvirtd.socket
             ● libvirtd-admin.socket
             ● libvirtd-ro.socket
       Docs: man:libvirtd(8)
             https://libvirt.org/
   Main PID: 2415 (libvirtd)
      Tasks: 21 (limit: 32768)
     Memory: 31.7M (peak: 31.8M)
        CPU: 180ms
     CGroup: /system.slice/libvirtd.service
             └─2415 /usr/bin/libvirtd --timeout 120

Jan 17 11:18:09 homes systemd[1]: Starting libvirt legacy monolithic daemon...
Jan 17 11:18:09 homes systemd[1]: Started libvirt legacy monolithic daemon.
Jan 17 11:18:09 homes libvirtd[2415]: libvirt version: 12.0.0
Jan 17 11:18:09 homes libvirtd[2415]: hostname: homes
Jan 17 11:18:09 homes libvirtd[2415]: Unable to find 'dn
smasq' binary in $PATH: No such file or directory
Jan 17 11:18:09 homes libvirtd[2415]: Cannot find 'dmide
code' in path: No such file or directory
Jan 17 11:18:09 homes libvirtd[2415]: Cannot find 'dmide
code' in path: No such file or directory

What I am worried about is that this is called "legacy" and also the non-found pieces. So let me learn something new.

Ok, so it seems I do not need to enable the one big monolithic process anymore, so disabling that:

[matelakat@homes ~]$ sudo systemctl stop libvirtd.service
Stopping 'libvirtd.service', but its triggering units are still active:
libvirtd.socket, libvirtd-admin.socket, libvirtd-ro.socket
[matelakat@homes ~]$ sudo systemctl disable libvirtd.service
Removed '/etc/systemd/system/multi-user.target.wants/libvirtd.service'.
Removed '/etc/systemd/system/sockets.target.wants/virtlockd-admin.socket'.
Removed '/etc/systemd/system/sockets.target.wants/virtlogd-admin.socket'.
Removed '/etc/systemd/system/sockets.target.wants/libvirtd-ro.socket'.
Removed '/etc/systemd/system/sockets.target.wants/virtlogd.socket'.
Removed '/etc/systemd/system/sockets.target.wants/virtlockd.socket'.
Removed '/etc/systemd/system/sockets.target.wants/libvirtd.socket'.
Removed '/etc/systemd/system/sockets.target.wants/libvirtd-admin.socket'.
Disabling 'libvirtd.service', but its triggering units are still active:
libvirtd.socket, libvirtd-admin.socket, libvirtd-ro.socket

I wonder what it means. It means that though I disabled a service, it still can be activated and thus brought up by other services.

So to completely disable that I would need to disable the triggering ones as well.

Did this:

[matelakat@homes ~]$ sudo systemctl disable --now \
  libvirtd.service \
  libvirtd.socket \
  libvirtd-admin.socket \
  libvirtd-ro.socket

And that was still printing out the same story, but running it the second time it didn't. I guess when it was disabling libvirtd.service, the other sockets were still active.

Ok, so how do I do the modern approach, where I do not need to run anything that is legacy?

Ok, I decided to ignore this monolithic nature of the hypervisor, and instead I will just simply use the monolithic approach for now:

[matelakat@homes ~]$ sudo systemctl start libvirtd.service
[matelakat@homes ~]$ sudo systemctl start virtlogd.service
[matelakat@homes ~]$ sudo systemctl enable libvirtd.service
Created symlink '/etc/systemd/system/multi-user.target.wants/libvirtd.service' → '/usr/lib/systemd/system/libvirtd.service'.
Created symlink '/etc/systemd/system/sockets.target.wants/virtlockd.socket' → '/usr/lib/systemd/system/virtlockd.socket'.
Created symlink '/etc/systemd/system/sockets.target.wants/virtlogd.socket' → '/usr/lib/systemd/system/virtlogd.socket'.
Created symlink '/etc/systemd/system/sockets.target.wants/libvirtd.socket' → '/usr/lib/systemd/system/libvirtd.socket'.
Created symlink '/etc/systemd/system/sockets.target.wants/libvirtd-ro.socket' → '/usr/lib/systemd/system/libvirtd-ro.socket'.
Created symlink '/etc/systemd/system/sockets.target.wants/libvirtd-admin.socket' → '/usr/lib/systemd/system/libvirtd-admin.socket'.
Created symlink '/etc/systemd/system/sockets.target.wants/virtlockd-admin.socket' → '/usr/lib/systemd/system/virtlockd-admin.socket'.
Created symlink '/etc/systemd/system/sockets.target.wants/virtlogd-admin.socket' → '/usr/lib/systemd/system/virtlogd-admin.socket'.

Okay, let's see what I have now.

[matelakat@homes ~]$ virsh list --all
 Id   Name   State
--------------------

That is nice. Now let me see if I can connect to it remotely with virt-manager.

It failed. The message is as follows:

Unable to connect to libvirt qemu+ssh://matelakat@homes/system.

Configure SSH key access for the remote host, or install an SSH askpass package locally.

Libvirt URI is: qemu+ssh://matelakat@homes/system

Traceback (most recent call last):
  File "/usr/share/virt-manager/virtManager/connection.py", line 940, in _do_open
    self._backend.open(cb, data)
    ~~~~~~~~~~~~~~~~~~^^^^^^^^^^
  File "/usr/share/virt-manager/virtinst/connection.py", line 173, in open
    conn = libvirt.openAuth(self._open_uri, [valid_auth_options, authcb, cbdata], open_flags)
  File "/usr/lib/python3.14/site-packages/libvirt.py", line 147, in openAuth
    raise libvirtError('virConnectOpenAuth() failed')
libvirt.libvirtError: Cannot recv data: ssh_askpass: exec(/usr/lib/ssh/ssh-askpass): No such file or directory
Permission denied, please try again.
ssh_askpass: exec(/usr/lib/ssh/ssh-askpass): No such file or directory
Permission denied, please try again.
ssh_askpass: exec(/usr/lib/ssh/ssh-askpass): No such file or directory
matelakat@homes: Permission denied (publickey,password).: Connection reset by peer

The problem was that my key is not on the default location, so ssh was not able to find it and authenticate to the remote system. To avoid the problem, I created a separate entry in ssh config:

host homeshypervisor
    User matelakat
    ForwardAgent no
    HostName homes
    IdentityFile <key location here>
    IdentitiesOnly yes

The IdentitiesOnly was something I learned today. It will make sure that for the connection only the explicitely specified identities are used.

Now all I need to do is to set up a dhcp server and confiure nat so I can launch a vm.

One more thing that bothers me is the libvirt daemon's message about the missing tool, dmidecode

[matelakat@homes ~]$ sudo pacman -S dmidecode

Setup dnsmasq and NAT on the host

First Install DNSMASQ

[matelakat@homes ~]$ sudo pacman -S dnsmasq

Change config, but to do that I need an editor.

[matelakat@homes ~]$ sudo pacman -S vim bash-completion

Adjust configuration file so I have these entries:

bind-interfaces
interface=pubbr
dhcp-range=192.168.115.50,192.168.115.150,12h

Then enable/start it:

[matelakat@homes ~]$ sudo systemctl enable --now dnsmasq.service

Installing the firewall:

[matelakat@homes ~]$ sudo pacman -S firewalld
[matelakat@homes ~]$ sudo systemctl enable --now firewalld.service

Looking at default config:

[matelakat@homes ~]$ sudo firewall-cmd --list-all
public (default, active)
  target: default
  ingress-priority: 0
  egress-priority: 0
  icmp-block-inversion: no
  interfaces: 
  sources: 
  services: dhcpv6-client ssh
  ports: 
  protocols: 
  forward: yes
  masquerade: no
  forward-ports: 
  source-ports: 
  icmp-blocks: 
  rich rules: 

Adding interface to the public zone, configuring masquerade and dropping non-recognised things:

[matelakat@homes ~]$ sudo firewall-cmd --zone=public --add-interface=wired0 --permanent
success
[matelakat@homes ~]$ sudo firewall-cmd --zone=public --add-masquerade --permanent
success
[matelakat@homes ~]$ sudo firewall-cmd --zone=public --set-target=DROP --permanent
success
[matelakat@homes ~]$ sudo firewall-cmd --reload
success

Adding a new Zone:

[matelakat@homes ~]$ sudo firewall-cmd --permanent --new-zone=pubbr
success
[matelakat@homes ~]$ sudo firewall-cmd --zone=pubbr --add-interface=pubbr --permanent
success
[matelakat@homes ~]$ sudo firewall-cmd --zone=pubbr --add-source=192.168.115.0/24 --permanent
success
[matelakat@homes ~]$ sudo firewall-cmd --zone=pubbr --add-service={dhcp,dns} --permanent
success
[matelakat@homes ~]$ sudo firewall-cmd --zone=pubbr --add-masquerade --permanent
success
[matelakat@homes ~]$ sudo firewall-cmd --reload
success

I am a bit uncertain if I need to add masquerade at both places. I would believe only the public one would need it. But I would need some VM to test it, so launching one.

With the above configuration, I was not able to ping outside servers. So something is definitely missing.

Adding it:

[matelakat@homes ~]$ sudo firewall-cmd --new-policy NAT_pubbr_to_ext --permanent
success
[matelakat@homes ~]$ sudo firewall-cmd --permanent --policy NAT_pubbr_to_ext --add-ingress-zone pubbr
success
[matelakat@homes ~]$ sudo firewall-cmd --permanent --policy NAT_pubbr_to_ext --add-egress-zone public
success
[matelakat@homes ~]$ sudo firewall-cmd --permanent --policy NAT_pubbr_to_ext --set-target ACCEPT
success
[matelakat@homes ~]$ sudo firewall-cmd --reload
success

Adjusting masquerade, removing it from pubbr:

[matelakat@homes ~]$ sudo firewall-cmd --zone=public --query-masquerade
yes
[matelakat@homes ~]$ sudo firewall-cmd --zone=pubbr --query-masquerade
yes
[matelakat@homes ~]$ sudo firewall-cmd --permanent --zone=pubbr --remove-masquerade
success
[matelakat@homes ~]$ sudo firewall-cmd --reload
success
[matelakat@homes ~]$ sudo firewall-cmd --zone=public --query-masquerade
yes
[matelakat@homes ~]$ sudo firewall-cmd --zone=pubbr --query-masquerade
no

Rebooting hypervisor to make sure everything is fine.

Ok, so "script" to set up the firewall are:

firewall-cmd --permanent --zone=public --add-interface=wired0
firewall-cmd --permanent --zone=public --add-masquerade
firewall-cmd --permanent --zone=public --set-target=DROP
firewall-cmd --permanent --new-zone=pubbr
firewall-cmd --permanent --zone=pubbr --add-interface=pubbr
firewall-cmd --permanent --zone=pubbr --add-source=192.168.115.0/24
firewall-cmd --permanent --zone=pubbr --add-service={dhcp,dns}
firewall-cmd --permanent --new-policy NAT_pubbr_to_ext
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
firewall-cmd --reload