CachyOS Unbound DNS & VM Bridge Configuration Guide (Step-by-Step)


1. Disable Unwanted DNS Services

a. Stop and Disable dnsmasq (if installed)

sudo systemctl stop dnsmasq
sudo systemctl disable dnsmasq

If not installed, skip this step.


b. Stop and Disable systemd-resolved

sudo systemctl stop systemd-resolved
sudo systemctl disable systemd-resolved

2. Configure /etc/systemd/resolved.conf

Edit the DNS resolver configuration file:

sudo nano /etc/systemd/resolved.conf

Add or modify the following lines:

[Resolve]
DNS=127.0.0.1
DNSSEC=yes
MulticastDNS=no
DNSOverTLS=no

Save and exit.


3. Backup /etc/resolv.conf

Since systemd-resolved is disabled, no symlink is needed. Back up the original file:

sudo mv /etc/resolv.conf /etc/resolv.conf.old

4. Set Up Unbound as a Local DNS Resolver (Required)

a. Create Docker Compose File

Create a docker-compose.yml file in your working directory:

services:
  unbound:
    container_name: unbound
    image: docker.io/mvance/unbound:latest
    restart: unless-stopped
    volumes:
      - ./unbound:/etc/unbound/unbound.conf
    ports:
      - "53:53/udp"

b. Create Unbound Configuration File

Create a directory for the config file and generate unbound.conf:

mkdir unbound
cd unbound
touch unbound.conf

Edit unbound.conf with the following content:

server:
  interface: 127.0.0.1
  access-control: 192.168.0.0/24 allow       # Replace with your local network (e.g., 192.168.1.0/24)
  do-ipv6: no
  do-udp4: yes
  do-tcp: yes

c. Start the Unbound Container

Run Docker Compose to start the container:

cd ..
docker-compose up -d unbound

5. Verify Unbound is Running

Check if the container is active:

docker ps | grep unbound

Confirm Unbound is listening on port 53:

ss -tulnp | grep :53

6. Configure the br0 Bridge with systemd-networkd

a. Create /etc/systemd/network/br0.netdev

[NetDev]
Name=br0
Kind=bridge

b. Create /etc/systemd/network/br0.network

[Match]
Name=br0

[Network]
DHCP=yes

c. Configure Physical Interface (e.g., eno1np0)

Create /etc/systemd/network/eno1np0.network:

[Match]
Name=eno1np0

[Network]
Bridge=br0

d. Restart systemd-networkd

sudo systemctl restart systemd-networkd

7. Configure Libvirtd to Avoid DNS Conflicts

a. Disable DNS in the Default Libvirtd Network

Edit the default libvirtd network configuration:

sudo virsh net-edit default

Add or modify the <dns> section to disable DNS:

<network>
  <name>default</name>
  <forward mode='nat'/>
  <bridge name='virbr0' stp='on' delay='0'/>
  <mac address='52:54:00:4f:5c:b3'/>
  <dns enable='no'/> <!-- Disable DNS to avoid conflicts -->
  <ip address='192.168.122.1' netmask='255.255.255.0'>
    <dhcp>
      <range start='192.168.122.2' end='192.168.122.254'/>
    </dhcp>
  </ip>
</network>

Save and exit the editor.


b. Create a New Libvirtd Network for br0

Create a new network configuration file (e.g., host-bridge-br0.xml) with the following content:

<network>
  <name>host-bridge-br0</name>
  <forward mode='bridge'/>
  <bridge name='br0'/> <!-- Use the existing bridge interface -->
</network>

Define the new network using virsh:

sudo virsh net-create host-bridge-br0.xml

Verify the new network is active:

sudo virsh net-list --all

c. Configure VMs to Use the New Network

When creating or editing a VM, specify the host-bridge-br0 network in its configuration file (e.g., /etc/libvirt/qemu/<vm-name>.xml):

<interface type='network'>
  <source network='host-bridge-br0'/>
</interface>

8. Final Steps

a. Restart Libvirtd

Ensure changes take effect:

sudo systemctl restart libvirtd

b. Verify Bridge and DNS Functionality

Check that br0 is up:

ip a show br0

Test DNS resolution through Unbound:

dig @127.0.0.1 yahoo.com

Summary of Key Files

File Purpose
/etc/systemd/resolved.conf DNS resolver configuration
/etc/systemd/network/br0.netdev Bridge device definition
/etc/systemd/network/br0.network Bridge IP/DHCP settings
./unbound/unbound.conf Unbound DNS server configuration
/etc/libvirt/qemu/<vm-name>.xml VM configuration referencing host-bridge-br0

Replace eno1np0 with your actual network interface name (e.g., eth0, enp3s0). Adjust the access control subnet in unbound.conf to match your local network. This setup ensures DNS resolution works through Unbound, and VMs use the br0 bridge for networking without conflicts.