Da Debian von Haus aus ext4 als Dateisystem benutzt, muss man bei einer Installation noch einiges manuell erledigen um btrfs zu nutzen.

Die grundlegende Konfiguration habe ich aus zwei Tutorials zusammengebaut (beide auf englisch)

Da dies primär eine Orientierung für mich selbst ist, empfiehlt es sich die beiden Artikel durchzulesen um gegebenenfalls eigene Anpassungen vorzunehmen!

Da chattr aus irgend einem Grund in der Konsole der Installation bei Debian nicht verfügbar ist, muss man erstens eine Live-Version von Debian benutzen und zweitens den Installtaionsprozess zweimal starten!
Es empfiehlt sich ein Live-Version ohne Desktopumgebung zu benutzen da diese schneller lädt!

Installation / Partitionierung

Für die Installation wähle ich Advanced Install Options, Text installer... und dann Expert install.
Danach konfiguriere ich mal alles entsprechend meinen Bedürftnissen bis ich zur Partitionierung komme.

Falls man einen Desktop PC aufsetzt der auch Winterschlaf halten können soll, muss man bereits beim Starten des Installationsprozesses ein bisschen wie folgt herumfummeln:

Beim Eintrag, mit dem man die Installation starten will, drück man e und fügt dann folgendes hinter linux /install.amd/vmlinuz mit einem Abstand ein:

partman-auto/cap-ram=n

oder

partman-auto/cap-ram=(value in MB z.b. 1024 für 1GB)

Anschliessend startet man mit ctrl + x oder F10 die Installation
(gefunden hier)

  • Choose Language: Deutsch - Schweiz - Schweiz
  • Tastatur konfigurieren: Schweizerdeutsch
  • Installationsmedium erkennen und einbinden
  • Installer-Komponenten vom Installationsmedium laden
  • Netzwerkhardware erkennen
  • Netzwerk einrichten: da ich das System als Server nutze konfiguriere ich hier eine statische IP
  • Benutzer und Passwörter einrichten:
    • root anmelden: ja
    • Benutzerkonto erstellen: nein
  • Uhr einstellen
  • Festplatte erkennen
  • Festplatte partitionieren

Da wähle ich die automatische Konfiguration der gesamten Platte.
Ich benötige nur 1GB für swap da ich später zram für das swapping verwenden werde.

Die grösste Partition für das root-Verzeichnis / ändere ich dann noch von ext4 auf btrfs!

Dann schliesse ich die Partitionierung ab.

BtrFS

Bevor man nun das Basissystem installiert, muss man noch einiges über die Konsole konfigurieren damit dann auch Snapshots funktionieren.

Um in die Konsole zu gelangen drückt man ctrl + alt + f2
(Um wieder zur Installation zurückzukehren benutzt man ctrl + alt + f1)

In der Konsole benutze ich erstmal df um zu sehen was alles gemounted ist.
Dabei merke ich mir gleich noch die Partition die auf /target gemounted ist; in meinem Fall ist das /dev/sda2

Für mich wichtig ist /target und /target/boot/efi.
Die muss ich jetzt erstmal alle unmounten und zwar in dieser Reihenfolge:

umount /target/boot/efi/
umount /target/

Nun mounte ich meine /dev/sda2 auf /mnt

mount /dev/sda2 /mnt

Wenn ich nun in das Verzeichnis /mnt wechsle und ls eingebe, dann sehe ich da ein @rootfs.
Dies ist für Snapper ungünstig weshalb ich das auf @ ändere

mv @rootfs/ @

Subvolumes

Nun erstelle ich die Subvolumes nach Vorlage von OpenSUSE.
Weshalb OpenSUSE?
OpenSUSE nutzt BtrFS seit einigen Jahren als default Dateisystem und hat deshalb Erfahrung mit der Struktur und Konfiguration des Layouts.

btrfs subvolume create /mnt/@/.snapshots
mkdir /mnt/@/.snapshots/1
btrfs subvolume create /mnt/@/.snapshots/1/snapshot
mkdir -p /mnt/@/boot/grub2/
btrfs subvolume create /mnt/@/boot/grub2/i386-pc
btrfs subvolume create /mnt/@/boot/grub2/x86_64-efi
btrfs subvolume create /mnt/@/home
btrfs subvolume create /mnt/@/opt
btrfs subvoulme create /mnt/@/root
btrfs subvolume create /mnt/@/srv
btrfs subvolume create /mnt/@/tmp
mkdir /mnt/@/usr/
btrfs subvolume create /mnt/@/usr/local
btrfs subvolume create /mnt/@/var

Nun erstelle ich die benötigten Verzeichnisse

mkdir /mnt/.snapshots
mkdir -p /mnt/boot/grub2/i386-pc
mkdir -p /mnt/boot/grub2/x86_64-efi
mkdir /mnt/home
mkdir /mnt/opt
mkdir /mnt/root
mkdir /mnt/srv
mkdir /mnt/tmp
mkdir -p /mnt/usr/local
mkdir /mnt/var

Danach kann ich die Konsole mit exit wieder verlassen.

Chattr

Wie oben bereits erwähnt ist in der Installationskonsole von Debian kein chattr verfügbar.
Dies wird aber benötigt um Copy-on-Write (CoW) für /var zu deaktivieren.
Da in diesem Verzeichnis die Logs, Datenbanken und sonstige Dateien liegen welche häufig geschrieben/geändert werden bzw. sehr gross sein können, wird durch CoW das Dateisystem stark fragmentiert, was selbst auf SSD/Nvme irgendwann zu Performanceeinbussen führen kann.

Da die Festplatte bereits vorbereitet ist, breche ich die Installation hier ab und boote in das Live-System.

Hier mounte ich die Festplatte und deaktiviere anschliessend CoW für /var.

Anmerkung: auf einem amerikanischen Keyboard liegt @ auf shift + 2, / auf - und + auf ^.

sudo mount /dev/sda2 /mnt
sudo chattr +C /mnt/@/var

Nun reboote ich die Maschine und starte anschliessend die Installation erneut

sudo reboot

Installation (2. Durchlauf)

Nun konfiguriere ich wieder alles wie oben bis und mit "Festplatte erkennen".
Obwohl die Festplatte eigentlich vorbereitet ist, muss ich die Partitionierung trotzdem noch einmal durchlaufen und auf der Partition sda2 den Einhängepunkt auf / setzen.
Dies ist nötig damit der Installer eine fstab anlegt die ich anschliessend noch benötige.
Vorsicht: doppelt checken dass auf der sda2 KEINE daten gelöscht werden bzw. die Partition NICHT formatiert wird. Sonst wäre die ganze vorherige Arbeit wieder verloren!

Nun gehe ich mit ctrl + alt + f2 wieder in die Konsole und unmounte die beiden Einhängepunkte der sda2 wieder

umount /target/boot/efi/
umount /target/

Durch das erneute Partitionieren wird erneut ein subvolume @rootfs erstellt welches ich noch löschen muss.

mount /dev/sda2 /mnt
btrfs subvolume delete /mnt/@rootfs
umount /mnt

Anschliessend wird alles wieder auf /target gemountet um das Betriebssystem zu installieren.
Anmerkung: Ich benutze die Kompression zstd:3 weil ich das Betriebssystem auf eine mechanische HDD installiere und eine gute CPU habe.

mount -o noatime,space_cache=v2,compress-force=zstd:3,discard=async,subvol=@ /dev/sda2 /target
mount -o noatime,space_cache=v2,compress-force=zstd:3,discard=async,subvol=@/.snapshots /dev/sda2 /target/.snapshots
mount -o noatime,space_cache=v2,compress-force=zstd:3,discard=async,subvol=@/boot/grub2/i386-pc /dev/sda2 /target/boot/grub2/i386-pc
mount -o noatime,space_cache=v2,compress-force=zstd:3,discard=async,subvol=@/boot/grub2/x86_64-efi /dev/sda2 /target/boot/grub2/x86_64-efi
mount -o noatime,space_cache=v2,compress-force=zstd:3,discard=async,subvol=@/home /dev/sda2 /target/home
mount -o noatime,space_cache=v2,compress-force=zstd:3,discard=async,subvol=@/opt /dev/sda2 /target/opt
mount -o noatime,space_cache=v2,compress-force=zstd:3,discard=async,subvol=@/root /dev/sda2 /target/root
mount -o noatime,space_cache=v2,compress-force=zstd:3,discard=async,subvol=@/srv /dev/sda2 /target/srv
mount -o noatime,space_cache=v2,compress-force=zstd:3,discard=async,subvol=@/tmp /dev/sda2 /target/tmp
mount -o noatime,space_cache=v2,compress-force=zstd:3,discard=async,subvol=@/usr/local /dev/sda2 /target/usr/local
mount -o noatime,space_cache=v2,compress-force=zstd:3,discard=async,subvol=@/var /dev/sda2 /target/var
mount /dev/sda1 /target/boot/efi

fstab

Damit die BtrFS subvolumes nach der Installation auch richtig eingebunden werden muss ich noch die /target/etc/fstab anpassen.

nano /target/etc/fstab

Ich orientiere mich an der ursprünglichen ersten Zeile (vorallem die UUID)

UUID={meine UUID der disk} /                       btrfs   noatime,space_cache=v2,compress-force=zstd:3,discard=async,subvol=@                        0  0
UUID={meine UUID der disk} /.snapshots             btrfs   noatime,space_cache=v2,compress-force=zstd:3,discard=async,subvol=@/.snapshots             0  0
UUID={meine UUID der disk} /boot/grub2/i386-pc     btrfs   noatime,space_cache=v2,compress-force=zstd:3,discard=async,subvol=@/boot/grub2/i386-pc     0  0
UUID={meine UUID der disk} /boot/grub2/x86_64-efi  btrfs   noatime,space_cache=v2,compress-force=zstd:3,discard=async,subvol=@/boot/grub2/x86_64-efi  0  0
UUID={meine UUID der disk} /home                   btrfs   noatime,space_cache=v2,compress-force=zstd:3,discard=async,subvol=@/home                   0  0
UUID={meine UUID der disk} /opt                    btrfs   noatime,space_cache=v2,compress-force=zstd:3,discard=async,subvol=@/opt                    0  0
UUID={meine UUID der disk} /root                   btrfs   noatime,space_cache=v2,compress-force=zstd:3,discard=async,subvol=@/root                   0  0
UUID={meine UUID der disk} /srv                    btrfs   noatime,space_cache=v2,compress-force=zstd:3,discard=async,subvol=@/srv                    0  0
UUID={meine UUID der disk} /tmp                    btrfs   noatime,space_cache=v2,compress-force=zstd:3,discard=async,subvol=@/tmp                    0  0
UUID={meine UUID der disk} /usr/local              btrfs   noatime,space_cache=v2,compress-force=zstd:3,discard=async,subvol=@/usr/local              0  0
UUID={meine UUID der disk} /var                    btrfs   noatime,space_cache=v2,compress-force=zstd:3,discard=async,subvol=@/var                    0  0

Danach kann ich die Konsole mit exit wieder verlassen.

Nun sollte dei Festplatte bereit für die Installation sein und ich kann mit ctrl + alt + f1 wieder zurück in die grafische Oberfläche und das Basissystem installieren.

  • Art der Installation: normal
  • zu installierender Kernel: linux-image-amd64
  • Treiber: generisch
  • Paketmanager konfiguriere:
    • ein weiteres Installationsmedium einbinden: nein
    • Mirror verwenden: ja, http
    • Nicht-freie-Firmware: ja
    • Nicht-freie-Software (Non-OSS): ja
    • Paketdepots (Source): ja
    • Sicherheitsaktualisierung, Release Updates und Backport aktivieren
  • Software auswählen und installieren: keine automatischen Updates
    da ich einen Server aufsetze wähle ich nur
    • SSH Server
    • Standard Systemwerkzeuge
  • GRUB Bootloader installieren
    • Bootloader auf EFI erzwingen: nein
    • NVRAM aktualisieren: ja
    • OS Probe: nur bei Dual-Boot sinnvoll
  • Installation abschliessen
    • System auf UTC: nein

Nun ist das System installiert.
Jetzt müssen noch ein paar weitere Anpassungen vorgenommen werden.

Snapshots

Als erstes muss Snapper installiert und eine config erstellt werden.
Dazu muss ich auch das .snapshot Subvolume wieder löschen weil es von Snapper automatisch erstellt wird.

apt install snapper
btrfs subvolume delete /.snapshots
snapper -c root create-config /

Falls das Kommando btrfs nicht gefunden wurde, muss man noch btrfs-progs installieren

apt install btrfs-progs

GRUB-Btrfs

Da grub-btrfs nicht in den Debian Repositories ist, muss ich es manuell installieren.
grub-btrfs wird benötigt um direkt in snapshots booten zu können.

apt install git make inotify-tools
cd
git clone https://github.com/Antynea/grub-btrfs.git
cd grub-btrfs
make install
systemctl enable grub-btrfsd
systemctl start grub-btrfsd

Nun muss man noch ein paar Anpassungen machen, z.B. das Erstellen von Snapshots beim Booten deaktivieren

systemctl disable snapper-boot.timer

Man kann dann noch weitere Dinge anpassen auf die ich hier nicht näher eingehen werde.
Das oben verlinkte Tutorial bietet eine gute Grundlage und Erklärungen dazu.

Dann erstelle ich meinen ersten Snapshot mit

snapper -c root create --description "default fresh install"

zram

zram ist auf Debian einfach zu installieren; man muss es eigentlich nur installieren und aktivieren

apt install zram-tools
systemctl enable --now zramswap

Da zram standardmässig mit nur 256MB started, passe ich die Konfiguration an und gebe zram 50% des Arbeitsspeichers

nano /etc/default/zramswap
# Compression algorithm selection
# speed: lz4 > zstd > lzo
# compression: zstd > lzo > lz4
# This is not inclusive of all that is available in latest kernels
# See /sys/block/zram0/comp_algorithm (when zram module is loaded) to see
# what is currently set and available for your kernel[1]
# [1]  https://github.com/torvalds/linux/blob/master/Documentation/blockdev/zram.txt#L86
#ALGO=lz4

# Specifies the amount of RAM that should be used for zram
# based on a percentage the total amount of available memory
# This takes precedence and overrides SIZE below
PERCENT=50

# Specifies a static amount of RAM that should be used for
# the ZRAM devices, this is in MiB
#SIZE=256

# Specifies the priority for the swap devices, see swapon(2)
# for more details. Higher number = higher priority
# This should probably be higher than hdd/ssd swaps.
#PRIORITY=100

Anschliessend zram neustarten damit die Änderungen übernommen werden

zramswap restart

Server

Da ich die Kiste als Server mit Virtualmin, Docker, Postgresql, diversen PHP-Versionen und elasticsearch nutzen will, muss ich noch ein paar zusätzliche Repositories hinzufügen und Pakete installieren.

Ich werde den Vorgang nur rudimentär beschreiben, also ohne zusätzlich auf Konfigurationen einzugehen.

Als erstes installiere ich Virtualmin da damit schon sehr viele Dinge automatisch installiert und konfiguriert werden.

apt install curl apt-transport-https lsb-release ca-certificates
sh -c "$(curl -fsSL https://software.virtualmin.com/gpl/scripts/virtualmin-install.sh)" -- --bundle LAMP

Dieser Vorgang kann einige Zeit dauern.
Bei meiner VM mit 4 vCores (AMD Ryzen 7 3700X) und 16GB vRam dauerte es ungefähr 15-20 Minuten.

Zuerst installiere ich mal Alles das ich zusätzlich benötige und nicht standardmässig installiert ist

apt install postgresql redis nginx python3-dev python-is-python3 amavisd-new libmagickcore-6.q16-6-extra ghostscript

Anmerkung: ich benutze zwar Apache2 als Standard-Webserver, allerdings hat sich gezeigt dass für das Proxying einiger föderierter Server die Konfiguration über Nginx einfacher ist (Apache -> Nginx -> Server).

Dann werden die zusätzlichen Repositories hinzugefügt

Repositories

Ich benötige diverse Versionen von PHP (Debian 12 Standard ist 8.2), Docker und Elasticsearch.
Je nach dem ob man Elasticsearch 7 (z.b. für Adobe Commerce) oder 8 installieren will muss man die URL und Source-List entsprechend von 8.x auf 7.x anpassen

curl -sSL -o /etc/apt/trusted.gpg.d/php.gpg https://packages.sury.org/php/apt.gpg
sh -c 'echo "deb https://packages.sury.org/php/ $(lsb_release -sc) main" > /etc/apt/sources.list.d/sury-debian-php-$(lsb_release -sc).list'
install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/debian/gpg -o /etc/apt/keyrings/docker.asc
chmod a+r /etc/apt/keyrings/docker.asc
echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/debian \
  $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
  tee /etc/apt/sources.list.d/docker.list > /dev/null
wget -qO - https://artifacts.elastic.co/GPG-KEY-elasticsearch | gpg --dearmor -o /usr/share/keyrings/elasticsearch-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/elasticsearch-keyring.gpg] https://artifacts.elastic.co/packages/8.x/apt stable main" | tee /etc/apt/sources.list.d/elastic-8.x.list
apt update
apt install php{5.6,7.4,8.2,8.3}-{apcu,bcmath,cgi,cli,curl,fpm,gd,gmp,igbinary,imagick,imap,intl,mbstring,mysql,opcache,pdo,redis,soap,xml,zip} docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin elasticsearch smartmontools
a2enmod headers
a2enmod remoteip