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.
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.
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"
Install hostapd, bridge-utils, isc-dhcp-server.
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.
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.
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.
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.