Installing Debian 11 on a Protectli VP2410 (Part 1)

I've replaced the hydrus server, a PC Engines APU1D4, with a Protectli VP2410. Debian is the installed OS, as I was unable to find a wireless card with the required form factor that supported HOSTAP mode in FreeBSD. The install was therefore a learning experience.

Hardware

The VP2410 base:

The package includes a Universal Power Supply, VESA mount kit, Serial Console Cable, SATA data and power cables for internal SSD, Quick Start Guide

From Protectli, I also added 16GB memory and a wifi card (Protectli M.2 802.11ac WiFi Kit). The card supports IEEE 802.11ac/a/b/g/n (2T2R) Bluetooth v5.0, v4.2, v4.1, v4.0 LE, v3.0+HS, v2.1+EDR and is based on the Qualcomm QCA6174A-5 chipset.

The hard disk I bought separately; a Crucial BX500 1TB 3D NAND SATA 2.5 Inch Internal SSD. Fitting the drive was a little more difficult than I expected, since levering off the base plate (after the four holding screws had been removed) required some careful effort.

Once assembled, I installed Debian 11 off a USB drive using the following partition scheme:

  Filesystem      Size  Used Avail Use% Mounted on
  /dev/sda6        44G  8.1G   34G  20% /
  /dev/sda2        46G  2.9G   41G   7% /var
  /dev/sda3       9.1G  100K  8.6G   1% /tmp
  /dev/sda4        46G  5.8G   38G  14% /home
  /dev/sda5       229G   88G  130G  41% /rep
  /dev/sda1       1.9G  5.8M  1.9G   1% /boot/efi

About half of the disk is left unallocated. I'll think of something to do with it later.

The wifi card was recognised, but the firmware failed to load:

  root@ash:~/Desktop# dmesg|grep ath
  [ 4.961046] ath10k_pci 0000:08:00.0: enabling device (0000 -> 0002)
  [ 4.963358] ath10k_pci 0000:08:00.0: pci irq msi oper_irq_mode 2 irq_mode 0 reset_mode 0
  [ 5.255443] usbcore: registered new interface driver ath3k
  [ 5.271062] ath10k_pci 0000:08:00.0: firmware: failed to load ath10k/pre-cal-pci-0000:08:00.0.bin (-2)
  [ 5.271087] ath10k_pci 0000:08:00.0: firmware: failed to load ath10k/cal-pci-0000:08:00.0.bin (-2)
  [ 5.273616] ath10k_pci 0000:08:00.0: firmware: direct-loading firmware ath10k/QCA6174/hw3.0/firmware-6.bin
  [ 5.276890] ath10k_pci 0000:08:00.0: qca6174 hw3.0 target 0x05020000 chip_id 0x003409ff sub 168c:3361
  [ 5.276894] ath10k_pci 0000:08:00.0: kconfig debug 0 debugfs 0 tracing 0 dfs 0 testmode 0
  [ 5.280497] ath10k_pci 0000:08:00.0: firmware ver WLAN.RM.4.4.1-00157-QCARMSWPZ-1 api 6 features wowlan,ignore-otp,mfp crc32 90eebefb
  [ 5.346846] ath10k_pci 0000:08:00.0: firmware: direct-loading firmware ath10k/QCA6174/hw3.0/board-2.bin
  [ 5.351031] ath10k_pci 0000:08:00.0: board_file api 2 bmi_id N/A crc32 318825bf
  [ 12.618777] ath10k_pci 0000:08:00.0: wmi unified ready event not received
  [ 12.668878] ath10k_pci 0000:08:00.0: device has crashed during init
  [ 12.696823] ath10k_pci 0000:08:00.0: device has crashed during init
  [ 12.696831] ath10k_pci 0000:08:00.0: failed to wait for target init: -70
  [ 12.697882] ath10k_pci 0000:08:00.0: could not init core (-110)
  [ 12.697957] ath10k_pci 0000:08:00.0: could not probe fw (-110)

Protectli can provide some modified (downgraded?) firmware to replace a couple of the modules installed by the atheros-firmware package.

  sudo cp wifi-fix-standalone/vendor/{board-2.bin,firmware-6.bin} \
          /lib/firmware/ath10k/QCA6174/hw3.0

On reboot, the wireless card firmware was successfully loaded.

snd_hda_intel errors

These errors appeared on the console:

  snd_hda_intel: azx_get_response timeout, switching to polling mode:
    last cmd=0x12345678
  snd_hda_intel: azx_get_response timeout, switching to single_cmd mode:
    last cmd=0x12345678

The workaround (which seems to work) is to add an option to the Linux kernel boot, in /etc/default/grub:

  GRUB_CMDLINE_LINUX="snd_hda_intel.power_save_controller=0"

Setting up the wireless/wired bridge for access point

Install hostapd, bridge-utils, isc-dhcp-server.

Creating the bridge

The bridge is setup in /etc/network/interfaces:

  # This file describes the network interfaces available on your system
  # and how to activate them. For more information, see interfaces(5).

  source /etc/network/interfaces.d/*

  # The loopback network interface
  auto lo br0
  iface lo inet loopback

  # Set up interfaces manually, avoiding conflicts with, e.g., network
  # manager
  iface en01 inet manual
  iface enp2s0 inet manual
  iface enp3s0 inet manual
  iface enp6s0 inet manual
  iface wlp8s0 inet manual

  iface br0 inet static
    bridge_ports eno1 enp2s0 enp3s0 enp6s0 wlp8s0
    address 192.168.0.5
    broadcast 192.168.0.255
    netmask 255.255.255.0
    gateway 192.168.0.1

The wireless part of the bridge won't work properly until hostapd is configured.

Configuring hostapd

Configuration of hostapd is set in the file /etc/hostapd/hostapd.conf.

  interface=wlp8s0
  # this next is key; tells hostapd that the wifi interface is part of a
  # bridge (This has to be done via hostapd because wlps80 only becomes
  # bridgeable when it's actually switched to "access point" mode.)
  bridge=br0
  channel=6
  ieee80211n=1
  hw_mode=g
  ssid=SSID
  wpa=2
  wpa_passphrase=*redacted*
  wpa_key_mgmt=WPA-PSK
  rsn_pairwise=CCMP #TKIP ok as well?
  auth_algs=1

My reference for this is this post.

DHCP server

The initial configuration of isc-dhcp-server is reasonably straightforward:

  # option definitions common to all supported networks...
  option domain-name "hydrus.org";
  option domain-name-servers 192.168.0.5, 192.168.0.5;

  default-lease-time 7200;
  max-lease-time 28800;

  ddns-update-style none;

  # If this DHCP server is the official DHCP server for the local
  # network, the authoritative directive should be uncommented.
  authoritative;

  shared-network "hydrus.org.uk" {
      subnet 192.168.0.0 netmask 255.255.255.0 {
          interface br0;
          option routers 192.168.0.1;
          range 192.168.0.20 192.168.0.99;
          option subnet-mask 255.255.255.0;
          option broadcast-address 192.168.0.255;
      }
  }

To prevent the dhcpv6 version running, update the variable INTERFACESv4 in /etc/default/isc-dhcp-server:

  INTERFACESv4="br0"

The configuration of dhcpd gets more interesting when we setup dynamic DNS in BIND9.

BIND9 name server

I could copy across the basic configuration files for BIND from my FreeBSD box, so I won't document them here. The ad blacklist file, downloaded from Peter Lowe's site had to be edited to point the zone files to /etc/bin/db.blacklist.

To enable dynamic DHCP, I had to setup an rdnc key, shared with dhcpd. The method I used in FreeBSD, that is setting the IP addresses of valid updaters, I could not get to work in Debian.

rdnc-confgen will generate configuration stanzas, which can then be included in the appropriate configuration files. Sample output looks like this:

  # Start of rndc.conf
  key "rndc-key" {
          algorithm hmac-sha256;
          secret "random string";
  };

  options {
          default-key "rndc-key";
          default-server 127.0.0.1;
          default-port 953;
  };
  # End of rndc.conf

  # Use with the following in named.conf, adjusting the allow list as needed:
  # key "rndc-key" {
  #       algorithm hmac-sha256;
  #       secret "random string";
  # };
  #
  # controls {
  #       inet 127.0.0.1 port 953
  #               allow { 127.0.0.1; } keys { "rndc-key"; };
  # };
# End of named.conf

The first section was placed in /etc/bind/rdnc.conf. This is for the benefit of rndc. The second section, sans comment characters, was copied into /etc/bind/rndc-keys/rndc.key and included at the head of /etc/bind/named.conf.local file with:

  include "/etc/bind/rndc-keys/rndc.key";

NOTE: The rndc-keys directory avoids a warning from rndc when rndc.conf and rndc.key exist in the /etc/bind directory. See here.

For DDNS to work, the zone files must live in /var/lib/bind so that the /.jnl files are updatable via dhcpd. The allow-udpate section sets the permitted rndc key. For example:

  zone "hydrus.org.uk" in {
          type master;
          file "/var/lib/bind/db.hydrus.org.uk";
          allow-update { key rndc-key; };
  };

  zone "0.168.192.in-addr.arpa" in {
          type master;
          file "/var/lib/bind/db.192.168.0";
          allow-update { key rndc-key; };
  };

Finally, dhcpd has to know the rndc key, so that it is allowed to update DNS. Copy the key stanza (only) from rndc.conf to a file only accessible by dhcpd, e.g. /etc/dhcpd/rndc-keys/rndc.key. Then enable DDNS in /etc/dhcp/dhcpd.conf:

  ddns-updates on;
  ddns-update-style standard;
  ddns-rev-domainname "in-addr.arpa.";
  deny client-updates;
  do-forward-updates on;
  update-optimization off;
  update-conflict-detection off;
  include "/etc/dhcp/rndc-keys/rndc.key";

Restart named and isc-dhcp-server via systemctl and check it works.