Unixery & daemon worship 🔥


It's a Unix system! I know this!

Homserver Schnellanleitung

Ich schreibe mir hier nur ein paar Notizen für die Installation eines Homeservers mit FreeBSD auf. Ohne Anspruch auf Vollständigkeit. Als Hardware kann z.B. ein Fujitsu TX1320 M3 dienen: https://watchmysys.com/blog/2023/03/fujitsu-tx1320-m3/

Installation

Zunächst einmal muss FreeBSD vom USB-Stick oder remote per KVM installiert werden.

SSH

Um SSH rudimentär abzusichern, wird die Datei /etc/ssh/sshd_config_custom erstellt, um ein paar SSH-Einstellungen zu ändern:

PermitRootLogin prohibit-password
PubkeyAuthentication yes
KexAlgorithms sntrup761x25519-sha512@openssh.com,curve25519-sha256,curve25519-sha256@libssh.org
PasswordAuthentication no
KbdInteractiveAuthentication no
UseBlacklist yes

Include /etc/ssh/sshd_config

Und folgenden Befehl ausführen, um die Custom-Config zu nutzen:

sysrc sshd_flags="-f /etc/ssh/sshd_config_custom"

E-Mailversand

Damit der Server Mails versenden kann, muss ein Smarthost (Relay) konfiguriert werden. Für den E-Mailversand empfehle ich den Dragonfly Mail Agent. Er ist bei FreeBSD im Basissystem. In der Datei /etc/dma/dma.conf zum Beispiel eintragen:

# Your smarthost (also called relayhost).
SMARTHOST mail.example.com
PORT 587

# SMTP authentication
AUTHPATH /etc/dma/auth.conf

# Uncomment if yout want TLS/SSL support and STARTTLS support
SECURETRANSFER
STARTTLS

# Masquerade envelope from addresses with this address/hostname.
MASQUERADE no-reply@example.com

Außerdem die Zugangsdaten in /etc/dma/auth.conf in folgender Form ablegen:

no-reply@example.com|mail.example.com:password

Und mit chmod 640 /etc/dma/auth.conf passende Zugriffsberechtigungen setzen.

Zuletzt in /etc/mail/mailer.conf (bei FreeBSD 14.2 schon voreingestellt):

# mailer.conf for use with dma(8)

sendmail    /usr/libexec/dma
mailq       /usr/libexec/dma
newaliases  /usr/libexec/dma

Auch nicht vergessen, in /etc/aliases die gewünschten Mail-Aliases zu setzen!

Hardware

CPU checken

Der verwendete CPU kann mit folgendem Befehl angezeigt werden:

sysctl hw.model hw.machine hw.ncpu

IPMI

Um IPMI zu nutzen, muss das Kernelmodul geladen und die Tools installiert werden:

kldload ipmi
sysrc kld_list+=ipmi
pkg install ipmitools

Dann können z.B. die Sensoren über IPMI abgefragt werden:

ipmitool sensor | cut -f1-4 -d '|'

Stromverbrauch senken

ASPM im BIOS aktivieren und prüfen, ob es von den PCIe-Geräten genutzt wird:

pciconf -lcv | grep ASPM

In die rc.conf eintragen:

performance_cx_lowest="Cmax"
economy_cx_lowest="Cmax"

Und prüfen, welche C-States tatsächlich genutzt werden:

sysctl dev.cpu | grep cx

USV

Auch für den Homeserver kann man sich eine kleine USV gönnen, z.B. eine günstige Eaton Ellipse ECO. Die verbrät selbst nicht sonderlich viel Strom, lässt sich per USB anschließen und erfüllt ihren Job.

pkg install nut
rm /usr/local/etc/nut/ups.conf
printf "# Set maxretry to 3 by default, this should mitigate race with slow devices:\nmaxretry = 3\n\n" > /usr/local/etc/nut/ups.conf
nut-scanner -U >> /usr/local/etc/nut/ups.conf

Dann die /usr/local/etc/nut/ups.conf kontrollieren, bzw. editieren. Ich ändere z.B. den Namen der USV schlicht in “ups”.

Es stellt sich die Frage: Soll nur dieser Server heruntergefahren werden (MODE=standalone) oder sollen sich auch andere Server verbinden können, um bei Stromausfall sicher herunterzufahren (MODE=netserver). Das muss dann in /usr/local/etc/nut/nut.conf eingetragen werden:

rm /usr/local/etc/nut/nut.conf
printf "MODE=netserver\n" > /usr/local/etc/nut/nut.conf
rm /usr/local/etc/nut/upsd.conf
printf "LISTEN 127.0.0.1 3493\nLISTEN 10.0.0.10 3493" > /usr/local/etc/nut/upsd.conf
chmod 640 /usr/local/etc/nut/upsd.conf

Jetzt die Monitoring-User mit Passwörtern festlegen:

rm /usr/local/etc/nut/upsd.users
cat << EOF > /usr/local/etc/nut/upsd.users
[admin]
	password = mypass
	actions = SET
	instcmds = ALL

[monuser]
	password  = pass
	upsmon primary

[monclients]
	password  = pass
	upsmon secondary
EOF
chown nut:nut /usr/local/etc/nut/upsd.users
chmod 640 /usr/local/etc/nut/upsd.users

Und schließlich noch das Monitoring einrichten:

sed -i '' '/^#/d; /^$/d' /usr/local/etc/nut/upsmon.conf
printf "MONITOR ups@localhost 1 monuser pass primary\n" >> /usr/local/etc/nut/upsmon.conf

Auf das USV-USB-Gerät müssen die richtigen Berechtigungen gesetzt werden (Schreibzugriff für nut User). Das nut Paket bringt entsprechende Einstellungen für devfs mit, deshalb am besten neustarten:

sysrc nut_enable="YES"
reboot

Nach dem Reboot die Berechtigungen prüfen und die USV abfragen:

ls -l /dev/usb/
upsc ups

Standardtools

Ein paar Standardtools für den täglichen Gebrauch installieren:

pkg install nano micro freecolor tmux fish curl git bat zoxide

ZFS und Fileserver

Festplatten

Festplatten sollten mit den smartmontools, bzw. smartd überwacht werden:

pkg install smartmontools

Fehlerbehandlung und Benachrichtigung

Den zfsd aktivieren, der einige ZFS-Fehler automatisch behandeln kann, vor allem, wenn man ein Hot-Spare einsetzt:

sysrc zfsd_enable="YES"

ZFS Tuning

Ein paar Infos über ZFS-Tuning finden sich in diesem Tuning-Guide:

ashift      12      4KiB block size
atime       off     Do not update atime on file read
recordsize  64KiB   Smaller record sizes for databases (match the database block size)
recordsize  128Kib  Standard usage (mixture of file sizes)
recordsize  1Mb     Recommended for large files
compression lz4     Set compression to use the lz4 algorithm

Pool erstellen

Einen Pool auf sechs SATA SSDs erstellen. Das dazugehörige Dataset soll nicht gemountet werden:

zpool create -o ashift=12 -O canmount=off -m none ozzy raidz2 ada0 ada1 ada2 ada3 ada4 ada5

Verschlüsseltes Dataset erstellen

Prinzipiell sollten alle Daten verschlüsselt werden, dann muss man sich bei Verkauf der Festplatten keine Gedanken machen. Dazu in der Keydatei das Passwort speichern und ein verschlüsseltes Dataset erstellen:

mkdir /root/keys
chmod 700 /root/keys
echo "mypassword" > /root/keys/ozzy_encrypted.key
chmod 600 /root/keys/ozzy_encrypted.key
zfs create -o encryption=aes-256-gcm -o keyformat=passphrase -o keylocation=file:///root/keys/ozzy_encrypted.key -o mountpoint=none -o canmount=off ozzy/encrypted

Alle anderen Datasets können dann darunter erstellt werden und sind automatisch verschlüsselt.

Beim Systemstart sollen die Keys automatisch geladen werden:

sysrc zfskeys_enable="YES"

Datasets für Shares erstellen

Für Datasets kann die Recordsize angepasst werden. Dabei ist 128K die Standardgröße, für Datasets mit großen Dateien bietet sich eine größere Recordsize an. Software, die in festen Datensatzgrößen schreibt (z.B. Datenbanken), profitiert von der Verwendung einer passenden Datensatzgröße, z.B. 16K.

  • Für mittelgroße Dateien (1-50 MiB): 512K
  • Für große Dateien (> 100 MiB): 1M
  • Für Disk-Images von Virtuellen Maschinen: 64K
zfs create -o recordsize=128K -o mountpoint=/mnt/dokumente ozzy/encrypted/dokumente
zfs create -o recordsize=512K -o mountpoint=/mnt/fotos ozzy/encrypted/fotos
zfs create -o recordsize=512K -o mountpoint=/mnt/musik ozzy/encrypted/musik
zfs create -o recordsize=1M -o mountpoint=/mnt/videos ozzy/encrypted/videos

Daten migrieren

Daten lassen sich mit syncoid sehr einfach von einem Server auf den anderen migrieren. syncoid ist Bestandteil von sanoid:

pkg install sanoid

Auf dem alten Server z.B. ausführen:

syncoid --no-sync-snap --delete-target-snapshots --recvoptions="o recordsize=512K" ozzy/musik root@newserver:ozzy/encrypted/musik

Samba

Der Homeserver soll natürlich auch als Fileserver dienen. Dazu wird Samba benutzt:

pkg install samba419
  • Die Samba-Konfigurationsdatei: /usr/local/etc/smb4.conf
  • Alle Samba-Datenbanken liegen in: /var/db/samba4
  • Alle Logs sind in: /var/log/samba4

Eine einfache /usr/local/etc/smb4.conf für den Heimgebrauch erstellen:

[global]
workgroup = WORKGROUP
netbios name = MYSERVER
unix extensions = yes
security = user
encrypt passwords = yes
passdb backend = tdbsam
server signing = mandatory

# Login-Versuche loggen
# log level = 1 auth:3

vfs objects = fruit streams_xattr zfsacl
access based share enum = yes

# DOS attribute stuff
store dos attributes = yes
map hidden = no
map system = no
map archive = no
map readonly = no

# macOS optimization: https://wiki.samba.org/index.php/Configure_Samba_to_Work_Better_with_Mac_OS_X
fruit:metadata = stream
fruit:model = MacSamba
fruit:posix_rename = yes
fruit:veto_appledouble = no
fruit:nfs_aces = no
fruit:wipe_intentionally_left_blank_rfork = yes
fruit:delete_empty_adfiles = yes

[homes]
comment = User %u's Data Share
path = /mnt/homes/%S
browseable = no
valid users = %S
writable = yes
hide unreadable = no

[fotos]
comment = Foto Share
path = /mnt/fotos
writable = yes
hide unreadable = no

[musik]
comment = Musik Share
path = /mnt/musik
writable = yes
hide unreadable = no

[public]
comment = Public Share
path = /mnt/pub
writable = yes
hide unreadable = no

Benutzer erstellen, die Zugriff auf den Samba-Server erhalten sollen:

pw user add -s /usr/sbin/nologin -n usera
pw user add -s /usr/sbin/nologin -n userb
pw user add -s /usr/sbin/nologin -n userc
pw user add -s /usr/sbin/nologin -n userd

Passwörter für Samba erstellen:

smbpasswd -a usera
smbpasswd -a userb
smbpasswd -a userc
smbpasswd -a userd

Samba-Service aktivieren:

sysrc samba_server_enable="YES"
service samba_server start

NFSv4

NFS verwende ich nur, um Ordner mit “öffentlichen” Daten in VMs zu mounten, z.B. die Musiksammlung im Lyrion-Mediaserver. Dazu NFSv4 aktivieren:

sysrc nfs_server_enable="YES"
sysrc nfsv4_server_enable="YES"
sysrc nfsv4_server_only="YES"
sysrc mountd_enable="YES"

Ein ZFS-Dataset readonly freigeben:

zfs set sharenfs=ro ozzy/encrypted/musik

Und eine /etc/exports erstellen:

# Set nfs sharing in the datasets, e.g. "zfs set sharenfs=ro tank/data"
#
# NFSv4 root filesystem, make sure there are only ZFS datasets mounted below this dir!
V4: /mnt -network 10.0.0.0 -mask 255.255.255.0

Nach dem editieren der /etc/exports muss mountd die Datei neu einlesen: service mountd reload

Backup

Backups lassen sich mit restic erstellen und auf einen externen Server übertragen:

pkg install restic

Siehe dazu https://github.com/thenktor/restic-dataset-backup

Virtualisierung

Auf dem Server sollen die eigentlichen Services in VMs oder Jails ausgeführt werden. Dazu Tools für Virtuelle Maschinen und Jails installieren:

pkg install vm-bhyve bhyve-firmware grub2-bhyve qemu-tools bastille

Netzwerk

Für VMs und Jails ist eine Netzwerkbridge nötig. Die Bridge wird manuell erstellt, damit die Tools das nicht jeweils selbst versuchen:

sysrc cloned_interfaces="bridge0"
sysrc ifconfig_bridge0="inet 10.0.0.10 netmask 255.255.255.0 addm igb0 up"
sysrc ifconfig_igb0="up"
sysrc defaultrouter="10.0.0.1"

VMs mit vm-bhyve

VMs lassen sich mit vm-bhyve verwalten. Als erstes ein Dataset erstellen, in dem die VMs liegen sollen:

zfs create -o recordsize=64K -o mountpoint=/mnt/vm ozzy/encrypted/vm

vm-bhyve aktivieren und das VM-Dataset festlegen:

sysrc vm_enable="YES"
sysrc vm_dir="zfs:ozzy/encrypted/vm"

Die Kosnolenausgabe der VMs soll in tmux erfolgen:

vm set console=tmux

Bridge konfigurieren:

vm switch create -t manual -b bridge0 public

VM Templates kopieren und bearbeiten

cp /usr/local/share/examples/vm-bhyve/* /mnt/vm/.templates

Die Templates kann man dann dort bearbeiten, z.B. die /mnt/vm/.templates/debian.conf:

loader="grub"
cpu=2
memory=4096M
network0_type="virtio-net"
network0_switch="public"
disk0_type="nvme"
disk0_name="disk0.img"
grub_run_partition="1"
grub_run_dir="/boot/grub"

VM aus img installieren

Um eine VM aus einem vorgefertigten img (Cloud-Images) zu installieren:

vm img https://cloud.debian.org/images/cloud/bookworm/latest/debian-12-nocloud-amd64.raw
vm create -t debian -i debian-12-nocloud-amd64.raw -s 16G debianvm
vm start debianvm
vm console debianvm

Die Cloud-Images haben eine vorgegebene Partitionierung. Um die root-Partition (Partition 1) auf maximale Größe des Geräts (/dev/nvme0n1) zu erweitern, macht man in Debian:

apt install cloud-guest-utils
growpart /dev/nvme0n1 1

Hinweis: Die Debian “nocloud” Images haben cloud-init nicht installiert, stattdessen erlauben sie root-Login ohne Passwort. Passwort nach dem Login (vm console) setzen!

VM von iso installieren

vm iso https://cdimage.debian.org/debian-cd/current/amd64/iso-cd/debian-12.9.0-amd64-netinst.iso
vm create -t debian -s 16G debianvm
vm install debianvm debian-12.9.0-amd64-netinst.iso
vm console debianvm

Jails mit Bastille

Für die Verwaltung der Jails bietet sich das Tool bastille an, das in Shell geschrieben ist und keine weiteren Abhängigkeiten benötigt. Die Konfiguration liegt in /usr/local/etc/bastille/bastille.conf und kann mit dem Tool sysrc einfach verwaltet werden.

ZFS aktivieren, den Pool und das Dataset festlegen, das für Bastille genutzt werden soll. Das Dataset wird unter /usr/local/bastille gemountet:

sysrc -f /usr/local/etc/bastille/bastille.conf bastille_zfs_enable="YES"
sysrc -f /usr/local/etc/bastille/bastille.conf bastille_zfs_zpool="ozzy"
sysrc -f /usr/local/etc/bastille/bastille.conf bastille_zfs_prefix="encrypted/bastille"

Limitierungen

Um Jails zu limitieren, z.B. bei der Speichernutzung, muss RACCT/RCTL im Kernel aktiviert werden. Danach neustarten:

echo "kern.racct.enable=1" > /boot/loader.conf.d/racct.conf
reboot

Image herunterladen

Das aktuellste Jail-Image für das System runterladen:

bastille bootstrap 14.2-RELEASE update

Oder automatisch das aktuellste für das laufende System in der Fish-Shell:

bastille bootstrap (string split -f1 -- '-p' (uname -r)) update

Eine jail erstellen

Eine Jail lässt sich dann folgendermaßen erstellen:

bastille create --bridge myjailname 14.2-RELEASE 10.0.0.123/24 bridge0

Oder mit dem gleichen Image wie das laufende System in der Fish-Shell:

bastille create --bridge myjailname (string split -f1 -- '-p' (uname -r)) 10.0.0.123/24 bridge0