Linux
- Linux - ZFS
- Apache Guacamole - Docker
- Fehler
- Festplatte mit 0 Bytes - Unsupported sector size 520
- Nextcloud - Terminal Updater - Fehler
- Unifi Controller startet nicht mehr
- Linux - Zeit setzen - timedatectl
- Postfix
- Webserver
- MariaDB
- UUID
- Links
- Geräte ohne Internetverbindung / Keine Updates
- Debian
- Syslog Server
- Netzwerk
- Internet teilen (NAT) und Loggen
- SMB
- Influx
- Vim
- Berechtigungen - chmod
- Bluetooth Autoconnect
- vnstat - Interface adden
- Nachricht an alle angemeldeten User senden
- Thunderbird
- RDP
- Linux - SSH
- Linux - Mounts (SMB, SSH....)
- Linux - Komprimierung
- Linux - GPG
- GPG - Yubikey "not found"
- GPG Keys exportieren
- GPG - Sicheren Schlüssel erstellen und Ordner verschlüsseln
- Linux - Server erstellen
- Linux - Nützliche Software
- Linux - Festplatten
- NVIDIA
- TMUX
- Datenspeicher
- Linux - SoCat
- Sudo deinstallieren
- Linux - MQTT
- Lenovo - Thinkpad
- Linux - Tmux
- Linux - Angemeldete User
- Linux - VNC/RDP
- Linux Server
- Linux - ZRAM
- WireGuard
- ATOM (Alter Code-Editor)
- Linux - Proxmox
- Proxmox VE 9 auf verschlüsseltem Debian 13 mit Dropbear-Remote-Unlock installieren
- Neue Seite
- Proxmox - VMs von einem ausgefallenen Proxmox-Host übernehmen
- Proxmox VE ohne Subscription: kostenlose Repositories nutzen und Subscription-Hinweis ausblenden
- Dienst installation
- AI
- Linux - Verschlüsselung
Linux - ZFS
Rollback
1 | Snapshots anzeigen
Ein Snapshot ist eine schreibgeschützte Momentaufnahme Ihres Dateisystems.
Liste aller vorhandenen Snapshots anzeigen:
zfs list -t snapshot
Beispielausgabe (mit ausgedachten Namen & Größen):
NAME USED AVAIL REFER MOUNTPOINT
poolalpha/data@2025-07-14_06-04-31 248M - 1.3T -
poolalpha/data@2025-07-16_00-39-41 253M - 1.4T -
tank/media@2025-07-02_23-13-47 25G - 13T -
tank/media@2025-07-16_00-39-40 1T - 19T -
2 | Rollback (zu einem Snapshot zurückkehren)
- Kopieren Sie den vollständigen Snapshot-Namen aus der Liste (
pool/dataset@datum_uhrzeit). - Führen Sie den Rollback-Befehl aus:
zfs rollback poolalpha/data@2025-07-14_06-04-31 - Tipp für Fortgeschrittene:
Mit-r(recursive) werden automatisch alle neueren Snapshots entfernt, bevor der Rollback ausgeführt wird.
zfs rollback -r poolalpha/data@2025-07-14_06-04-31
3 | Snapshot manuell erstellen (heutiges Datum)
Einfach im Terminal einen Einzeiler eingeben:
# Zeitstempel-Variable im Format YYYY-MM-DD_HH-MM-SS
TS=$(date +"%Y-%m-%d_%H-%M-%S")
# Snapshot für ein einzelnes Dataset
zfs snapshot poolalpha/data@$TS
# Rekursiv für einen gesamten Dataset-Baum
zfs snapshot -r tank@$TS
- 💾 Snapshots belegen nur den Platz für geänderte Datenblöcke.
4 | Häufige Fragen & praktische Tipps
Was passiert beim Rollback mit meinen neueren Daten ?
Alle Blöcke, die nach dem gewählten Snapshot erzeugt wurden, gehen verloren. Sichern Sie daher wichtige Dateien zuerst oder testen den Snapshot mit einem Clone:
zfs clone poolalpha/data@2025-07-14_06-04-31 poolalpha/data-test
Kann ich einen Snapshot gegen Löschen schützen ?
Ja – mit einem sogenannten Hold:
zfs hold keep poolalpha/data@2025-07-14_06-04-31
# Aufheben:
zfs release keep poolalpha/data@2025-07-14_06-04-31
Wie schiebe ich einen Snapshot auf einen Backup-Server ?
zfs send -vP poolalpha/data@$TS | \
ssh backuphost zfs recv -uF backuppool/data
ZFS modules cannot be auto-loaded
ZFS-DKMS – Schritt-für-Schritt-Anleitung für Debian 13 (Trixie)
Diese Anleitung fasst die notwendigen Schritte zusammen, um OpenZFS als DKMS-Modul auf Debian 13 zu installieren, nach Kernel-Updates neu zu bauen und typische Fehler zu beheben. Besonders wichtig ist der Fall, dass ZFS zwar erfolgreich für einen neuen Kernel gebaut wurde, das System aber noch mit einem alten Kernel läuft.
0 Wichtig: Laufender Kernel und DKMS-Modul müssen zusammenpassen
DKMS baut Kernelmodule immer für bestimmte Kernelversionen. modprobe lädt Module aber nur für den aktuell laufenden Kernel. Der aktuell laufende Kernel wird so angezeigt:
uname -r
Der DKMS-Status wird so angezeigt:
dkms status
uname -r einen anderen Kernel zeigt als dkms status, dann ist ZFS nicht für den aktuell laufenden Kernel installiert. In diesem Fall hilft oft kein weiterer Build, sondern ein Neustart in den Kernel, für den DKMS das Modul bereits gebaut hat.Beispiel:
uname -r
6.12.74+deb13+1-amd64
dkms status
zfs/2.3.2, 6.12.90+deb13.1-amd64, x86_64: installed
In diesem Beispiel läuft das System noch mit Kernel 6.12.74+deb13+1-amd64, ZFS wurde aber für 6.12.90+deb13.1-amd64 gebaut. modprobe zfs muss dann fehlschlagen, weil es im falschen Modulverzeichnis sucht.
1 Voraussetzungen
- Root-Zugriff, entweder direkt als
rootoder über eine Root-Shell. - Netzwerkzugang zu den Debian-Repositories.
- Aktiviertes
contrib-Repository, da ZFS in Debian dort liegt. - Optional bei Secure Boot: MOK-Schlüssel müssen importiert und bestätigt werden.
2 Repositories einrichten
ZFS liegt in Debian in contrib. Stelle daher sicher, dass contrib aktiv ist. Optional können non-free und non-free-firmware ergänzt werden, wenn das System entsprechende Firmware benötigt.
Beispiel für /etc/apt/sources.list oder eine passende Datei unter /etc/apt/sources.list.d/:
deb http://deb.debian.org/debian trixie main contrib non-free non-free-firmware
deb http://security.debian.org/debian-security trixie-security main contrib non-free non-free-firmware
deb http://deb.debian.org/debian trixie-updates main contrib non-free non-free-firmware
Optional für Backports:
deb http://deb.debian.org/debian trixie-backports main contrib non-free non-free-firmware
Danach die Paketlisten aktualisieren:
apt update
3 Benötigte Pakete installieren
Empfohlen ist die Installation der Kernel- und Header-Metapakete. Dadurch werden Kernel und Header gemeinsam aktuell gehalten, statt dass man irgendwann mit einem Kernel ohne passende Header herumsteht. Das ist ungefähr so sinnvoll wie ein Fahrrad ohne Vorderrad, nur mit mehr Fehlermeldungen.
apt install linux-image-amd64 linux-headers-amd64
Danach ZFS und die Build-Werkzeuge installieren:
apt install build-essential dkms zfs-dkms zfsutils-linux
Falls DKMS wegen pahole oder BTF-Erzeugung fehlschlägt:
apt install dwarves
/lib/modules/$(uname -r)/build und /lib/modules/$(uname -r)/source.4 Nach Kernel- oder Header-Update neu starten
Wenn ein neuer Kernel installiert wurde, läuft das System nicht automatisch mit diesem Kernel. Der neue Kernel wird erst nach einem Neustart verwendet.
Vor dem Neustart kann man prüfen, welche Kernelmodul-Verzeichnisse vorhanden sind:
ls /lib/modules
Außerdem den DKMS-Status prüfen:
dkms status
Wenn ZFS für einen neuen Kernel gebaut wurde, aber uname -r noch den alten Kernel zeigt:
reboot
Nach dem Neustart erneut prüfen:
uname -r
dkms status
Der laufende Kernel aus uname -r sollte jetzt zu einem ZFS-Eintrag aus dkms status passen.
5 ZFS-Modul laden und prüfen
Wenn der laufende Kernel und der DKMS-Eintrag zusammenpassen, kann das ZFS-Modul geladen werden:
modprobe zfs
Danach prüfen:
lsmod | sed -n '/^zfs/p'
zpool status -v
zpool status melden, dass keine Pools vorhanden sind. Das ist dann kein Fehler des Kernelmoduls.6 ZFS gezielt für den laufenden Kernel bauen
Diesen Schritt nur verwenden, wenn dkms status keinen installierten ZFS-Eintrag für den aktuell laufenden Kernel zeigt.
ZFS-Version aus dem installierten Paket ermitteln:
ZFS_VER="$(dpkg-query -W -f='${Version}\n' zfs-dkms | sed 's/-.*//')"
echo "$ZFS_VER"
ZFS für den aktuell laufenden Kernel bauen und installieren:
dkms install -m zfs -v "$ZFS_VER" -k "$(uname -r)"
Danach laden:
modprobe zfs
Wenn der Build fehlschlägt, das DKMS-Log ansehen:
less /var/lib/dkms/zfs/"$ZFS_VER"/build/make.log
7 Häufiger Fehler: Header für den aktuell laufenden Kernel fehlen
Typisches Fehlerbild:
apt install linux-headers-$(uname -r)
Fehler: Paket linux-headers-6.12.74+deb13+1-amd64 kann nicht gefunden werden.
Fehler: Mittels des Musters »linux-headers-6.12.74+deb13+1-amd64« konnte kein Paket gefunden werden.
Das bedeutet meistens: Der aktuell laufende Kernel ist nicht mehr der Kernel, für den die Repositories aktuell Header anbieten. Statt ewig nach alten Headern zu suchen, sollte man die Kernel- und Header-Metapakete installieren:
apt install linux-image-amd64 linux-headers-amd64
Wenn DKMS dabei ZFS erfolgreich für den neuen Kernel baut, danach neu starten:
reboot
Nach dem Neustart:
uname -r
dkms status
modprobe zfs
8 Backports nur bei Bedarf verwenden
Backports sind sinnvoll, wenn ein neuerer Kernel verwendet wird oder wenn die ZFS-Version aus Stable zu alt für den verwendeten Kernel ist.
ZFS aus Backports installieren:
apt install -t trixie-backports zfs-dkms zfsutils-linux
Wenn auch der Kernel aus Backports verwendet werden soll:
apt install -t trixie-backports linux-image-amd64 linux-headers-amd64
Danach neu starten:
reboot
Nach dem Neustart prüfen:
uname -r
dkms status
modprobe zfs
zpool status -v
9 Secure Boot prüfen
Wenn Secure Boot aktiv ist, können nicht korrekt signierte oder nicht akzeptierte Module blockiert werden.
Typische Fehlermeldungen:
modprobe: ERROR: could not insert 'zfs': Key was rejected by service
Required key not available
Secure-Boot-Status prüfen:
mokutil --sb-state
Wenn Secure Boot aktiv ist, gibt es zwei saubere Möglichkeiten:
- Secure Boot im UEFI deaktivieren.
- Den DKMS/MOK-Schlüssel importieren und beim nächsten Boot bestätigen.
Beim DKMS-Build sieht man häufig Hinweise wie:
Signing key: /var/lib/dkms/mok.key
Public certificate (MOK): /var/lib/dkms/mok.pub
Dann kann der öffentliche Schlüssel importiert werden:
mokutil --import /var/lib/dkms/mok.pub
Danach neu starten und im MOK-Menü bestätigen.
10 Alte Kernel nicht vorschnell entfernen
Alte Kernel sollten erst entfernt werden, wenn ZFS mit dem neuen Kernel erfolgreich geladen wurde.
uname -r
dkms status
modprobe zfs
zpool status -v
Wenn alles funktioniert, können alte nicht mehr benötigte Pakete später bereinigt werden:
apt autoremove
11 Problemlösung und häufige Stolperfallen
| Symptom | Wahrscheinliche Ursache | Lösung |
|---|---|---|
modprobe: FATAL: Module zfs not found in directory /lib/modules/<kernel> |
ZFS wurde nicht für den aktuell laufenden Kernel gebaut. | uname -r und dkms status vergleichen. |
linux-headers-$(uname -r) kann nicht gefunden werden. |
Der laufende Kernel ist älter oder stammt nicht mehr aus den aktuell verfügbaren Repositories. | linux-image-amd64 und linux-headers-amd64 installieren, danach neu starten. |
DKMS zeigt ZFS für einen neueren Kernel als uname -r. |
Der neue Kernel wurde installiert, aber noch nicht gebootet. | System neu starten und danach erneut prüfen. |
DKMS-Build schlägt wegen pahole fehl. |
Das Paket dwarves fehlt. |
apt install dwarves |
| Modul wird wegen Schlüssel abgelehnt. | Secure Boot blockiert das Modul. | Secure Boot deaktivieren oder MOK-Schlüssel enrollen. |
| Build bricht mit Kernel-API-Fehlern ab. | Die installierte ZFS-Version passt nicht zum verwendeten Kernel. | ZFS aus trixie-backports nutzen oder auf den Debian-Stable-Kernel wechseln. |
12 Schnellreferenz
Standardfall Debian 13 Stable
apt update
apt install linux-image-amd64 linux-headers-amd64
apt install build-essential dkms zfs-dkms zfsutils-linux
reboot
Nach dem Neustart:
uname -r
dkms status
modprobe zfs
zpool status -v
Wenn ZFS für den laufenden Kernel fehlt
ZFS_VER="$(dpkg-query -W -f='${Version}\n' zfs-dkms | sed 's/-.*//')"
dkms install -m zfs -v "$ZFS_VER" -k "$(uname -r)"
modprobe zfs
Wenn ein neuerer Backports-Kernel genutzt wird
apt install -t trixie-backports linux-image-amd64 linux-headers-amd64
apt install -t trixie-backports zfs-dkms zfsutils-linux
reboot
Danach:
uname -r
dkms status
modprobe zfs
zpool status -v
13 Praxisbeispiel: ZFS wurde gebaut, aber der alte Kernel läuft noch
Ausgangslage:
uname -r
6.12.74+deb13+1-amd64
Die Header für diesen Kernel sind nicht installierbar:
apt install linux-headers-6.12.74+deb13+1-amd64
Fehler: Paket linux-headers-6.12.74+deb13+1-amd64 kann nicht gefunden werden.
Fehler: Mittels des Musters »linux-headers-6.12.74+deb13+1-amd64« konnte kein Paket gefunden werden.
Danach werden die Metapakete installiert:
apt install linux-image-amd64 linux-headers-amd64
DKMS baut ZFS erfolgreich für den neuen Kernel:
Autoinstall of module zfs/2.3.2 for kernel 6.12.90+deb13.1-amd64 (x86_64)
Building module(s)................................................. done.
Installing /lib/modules/6.12.90+deb13.1-amd64/updates/dkms/zfs.ko.xz
Autoinstall on 6.12.90+deb13.1-amd64 succeeded for module(s) zfs.
Trotzdem schlägt modprobe zfs fehl:
modprobe: FATAL: Module zfs not found in directory /lib/modules/6.12.74+deb13+1-amd64
Der Grund ist simpel: Das System läuft noch mit 6.12.74+deb13+1-amd64. ZFS wurde aber für 6.12.90+deb13.1-amd64 gebaut. Der Build ist also erfolgreich, aber der falsche Kernel ist aktiv.
Korrekte Lösung:
reboot
Nach dem Neustart:
uname -r
dkms status
modprobe zfs
Wenn uname -r jetzt 6.12.90+deb13.1-amd64 oder einen anderen Kernel mit passendem ZFS-DKMS-Eintrag zeigt, sollte modprobe zfs funktionieren.
Apache Guacamole - Docker
Fehler
Festplatte mit 0 Bytes - Unsupported sector size 520
Ich hatte SAS Server Festplatten auf Ebay gekauft, diese hatten eine Sector Größe von 520 statt 512, damit konnte mein Linux Server nicht arbeiten.
Ausgabe von lsblk:
root@thinkstation-d30:/home/jj# lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
loop0 7:0 0 111,9M 1 loop /snap/lxd/24322
loop1 7:1 0 63,3M 1 loop /snap/core20/1822
loop2 7:2 0 49,8M 1 loop /snap/snapd/18357
sda 8:0 0 232,9G 0 disk
├─sda1 8:1 0 1G 0 part /boot/efi
└─sda2 8:2 0 231,8G 0 part /
sdb 8:80 1 0B 0 disk
sdc 8:80 1 0B 0 disk
Wenn man dann in /var/log/syslog guckt:
Mar 2 14:35:49 thinkstation-d30 kernel: [842811.011313] sd 6:0:21:0: [sdb] Unsupported sector size 520.
Mar 2 14:35:49 thinkstation-d30 kernel: [842811.011789] sd 6:0:21:0: [sdb] 0 512-byte logical blocks: (0 B/0 B)
Mar 2 14:35:49 thinkstation-d30 kernel: [842811.011793] sd 6:0:21:0: [sdb] 520-byte physical blocks
Mar 2 14:35:49 thinkstation-d30 kernel: [842811.012135] sd 6:0:21:0: [sdb] Test WP failed, assume Write Enabled
Mar 2 14:35:49 thinkstation-d30 kernel: [842811.012243] sd 6:0:21:0: [sdb] Asking for cache data failed
Mar 2 14:35:49 thinkstation-d30 kernel: [842811.012269] sd 6:0:21:0: [sdb] Assuming drive cache: write through
Mar 2 14:35:49 thinkstation-d30 kernel: [842811.015632] sd 6:0:21:0: [sdb] Spinning up disk...
Mar 2 14:35:49 thinkstation-d30 systemd-udevd[230768]: sdx: Process '/usr/bin/unshare -m /usr/bin/snap auto-import --mount=/dev/sdb' failed with exit code 1.
Mar 2 14:36:19 thinkstation-d30 kernel: [842840.707363] sd 6:0:21:0: [sdb] Unsupported sector size 520.
Mar 2 14:36:19 thinkstation-d30 kernel: [842840.708694] sd 6:0:21:0: [sdb] Write cache: disabled, read cache: enabled, supports DPO and FUA
Mar 2 14:36:19 thinkstation-d30 kernel: [842840.709171] sd 6:0:21:0: [sdb] Attached SCSI disk
Mar 2 14:37:08 thinkstation-d30 kernel: [842841.350666] ................................................
Mar 2 14:37:08 thinkstation-d30 kernel: [842889.668429] ata5: SATA link down (SStatus 0 SControl 300)
Mar 2 14:37:25 thinkstation-d30 kernel: [842890.498005] .................not responding...
Mar 2 14:37:25 thinkstation-d30 kernel: [842906.882025] sd 6:0:22:0: [sdb] Unsupported sector size 520.
Mar 2 14:37:25 thinkstation-d30 kernel: [842906.882508] sd 6:0:22:0: [sdb] 0 512-byte logical blocks: (0 B/0 B)
Mar 2 14:37:25 thinkstation-d30 kernel: [842906.882511] sd 6:0:22:0: [sdb] 520-byte physical blocks
Mar 2 14:37:25 thinkstation-d30 kernel: [842906.882865] sd 6:0:22:0: [sdb] Test WP failed, assume Write Enabled
Mar 2 14:37:25 thinkstation-d30 kernel: [842906.882975] sd 6:0:22:0: [sdb] Asking for cache data failed
Mar 2 14:37:25 thinkstation-d30 kernel: [842906.882998] sd 6:0:22:0: [sdb] Assuming drive cache: write through
Mar 2 14:37:25 thinkstation-d30 kernel: [842906.884748] sd 6:0:22:0: [sdb] Spinning up disk...
Mar 2 14:37:25 thinkstation-d30 systemd-udevd[234836]: sdb: Process '/usr/bin/unshare -m /usr/bin/snap auto-import --mount=/dev/sdb' failed with exit code 1.
Mar 2 14:37:34 thinkstation-d30 kernel: [842907.905767] .........ready
Mar 2 14:37:34 thinkstation-d30 kernel: [842916.098275] sd 6:0:22:0: [sdb] Unsupported sector size 520.
Mar 2 14:37:34 thinkstation-d30 kernel: [842916.099587] sd 6:0:22:0: [sdb] Write cache: disabled, read cache: enabled, supports DPO and FUA
Mar 2 14:37:34 thinkstation-d30 kernel: [842916.100070] sd 6:0:22:0: [sdb] Attached SCSI disk
Mar 2 14:38:39 thinkstation-d30 kernel: [842981.024812] sd 7:0:0:4: [sdj] Media removed, stopped polling
Mar 2 14:39:41 thinkstation-d30 kernel: [843042.682033] sd 6:0:22:0: device_block, handle(0x001b)
Mar 2 14:39:51 thinkstation-d30 kernel: [843052.431519] sd 6:0:22:0: device_unblock and setting to running, handle(0x001b)
Mar 2 14:39:51 thinkstation-d30 kernel: [843052.793769] mpt2sas_cm0: mpt3sas_transport_port_remove: removed: sas_addr(0x5000c5006338f78e)
Mar 2 14:39:51 thinkstation-d30 kernel: [843052.793778] mpt2sas_cm0: removing handle(0x001b), sas_addr(0x5000c5006338f78e)
Mar 2 14:39:51 thinkstation-d30 kernel: [843052.793781] mpt2sas_cm0: enclosure logical id(0x5d4ae524852be97e), slot(14)
Mar 2 14:41:03 thinkstation-d30 kernel: [843124.431788] mpt2sas_cm0: handle(0x1b) sas_address(0x5000c5006338f78e) port_type(0x1)
Mar 2 14:41:03 thinkstation-d30 kernel: [843124.493757] scsi 6:0:23:0: Direct-Access SEAGATE ST910006CLAR1000 AS0C PQ: 0 ANSI: 5
Mar 2 14:41:03 thinkstation-d30 kernel: [843124.493781] scsi 6:0:23:0: SSP: handle(0x001b), sas_addr(0x5000c5006338f78e), phy(14), device_name(0x00c500508ef73863)
Mar 2 14:41:03 thinkstation-d30 kernel: [843124.493784] scsi 6:0:23:0: enclosure logical id (0x5d4ae524852be97e), slot(14)
Mar 2 14:41:03 thinkstation-d30 kernel: [843124.493793] scsi 6:0:23:0: qdepth(254), tagged(1), scsi_level(6), cmd_que(1)
Mar 2 14:41:03 thinkstation-d30 kernel: [843124.493897] scsi 6:0:23:0: Power-on or device reset occurred
Mar 2 14:41:03 thinkstation-d30 kernel: [843124.495280] sd 6:0:23:0: [sdb] Spinning up disk...
Mar 2 14:41:03 thinkstation-d30 kernel: [843124.495417] sd 6:0:23:0: Attached scsi generic sg26 type 0
Mar 2 14:41:03 thinkstation-d30 kernel: [843124.495748] end_device-6:0:22: add: handle(0x001b), sas_addr(0x5000c5006338f78e)
Also passt hier die Sector Größe nicht, diese kann man aber mit den Befehl "sg_format" anpassen:
sg_format /dev/disk/by-id/scsi-SSEAGATE_ST910006CLAR1000_9XG86B5W_0000C526KTTB -v --format --size=512
Ich habe hier lieber by-id genutzt, da ich mir nicht sicher bin, wie gut sdb da funktioniert hätte und ich eh die Seriennummer auf der Festplatte lesen kann.
Je nach Größe dauert das schon seine paar Stunden, er fragt anfangs noch ein paar mal, ob die Festplatte wirklich gelöscht werden soll.
Wenn man nichts macht, führt er es einfach aus.
Am Ende kommt dann sowas:
Format unit in progress, 99.01% done
Format unit in progress, 99.20% done
Format unit in progress, 99.38% done
Format unit in progress, 99.56% done
Format unit in progress, 99.74% done
Format unit in progress, 99.92% done
FORMAT UNIT Complete
root@thinkstation-d30:/home/jj#
In lsblk:
root@thinkstation-d30:/home/jj# lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
loop0 7:0 0 111,9M 1 loop /snap/lxd/24322
loop1 7:1 0 63,3M 1 loop /snap/core20/1822
loop2 7:2 0 49,8M 1 loop /snap/snapd/18357
sda 8:0 0 232,9G 0 disk
├─sda1 8:1 0 1G 0 part /boot/efi
└─sda2 8:2 0 231,8G 0 part /
sdb 65:112 0 931,5G 0 disk
sdc 65:128 0 931,5G 0 disk
Danach kann die Festplatte ganz normal genutzt werden...
Nextcloud - Terminal Updater - Fehler
Fehler:
root@nextcloud:/var/www/html/nextcloud# sudo -u www-data php updater/updater.phar
Nextcloud Updater - version: v26.0.0beta2-9-g64e2e4c dirty
Current version is 27.1.1.
PHP Fatal error: Uncaught Error: Call to undefined function NC\Updater\curl_init() in phar:///var/www/html/nextcloud/updater/updater.phar/lib/Updater.php:468
Stack trace:
#0 phar:///var/www/html/nextcloud/updater/updater.phar/lib/Updater.php(132): NC\Updater\Updater->getUpdateServerResponse()
#1 phar:///var/www/html/nextcloud/updater/updater.phar/lib/UpdateCommand.php(155): NC\Updater\Updater->checkForUpdate()
#2 phar:///var/www/html/nextcloud/updater/updater.phar/vendor/symfony/console/Command/Command.php(255): NC\Updater\UpdateCommand->execute()
#3 phar:///var/www/html/nextcloud/updater/updater.phar/vendor/symfony/console/Application.php(1009): Symfony\Component\Console\Command\Command->run()
#4 phar:///var/www/html/nextcloud/updater/updater.phar/vendor/symfony/console/Application.php(273): Symfony\Component\Console\Application->doRunCommand()
#5 phar:///var/www/html/nextcloud/updater/updater.phar/vendor/symfony/console/Application.php(149): Symfony\Component\Console\Application->doRun()
#6 phar:///var/www/html/nextcloud/updater/updater.phar/updater.php(10): Symfony\Component\Console\Application->run()
#7 /var/www/html/nextcloud/updater/updater.phar(14): require('...')
#8 {main}
thrown in phar:///var/www/html/nextcloud/updater/updater.phar/lib/Updater.php on line 468
root@nextcloud:/var/www/html/nextcloud#
root@nextcloud:/var/www/html/nextcloud# sudo -u www-data php updater/updater.phar
Nextcloud Updater - version: v26.0.0beta2-9-g64e2e4c dirty
Current version is 27.1.1.
PHP Fatal error: Uncaught Error: Call to undefined function NC\Updater\simplexml_load_string() in phar:///var/www/html/nextcloud/updater/updater.phar/lib/Updater.php:495
Stack trace:
#0 phar:///var/www/html/nextcloud/updater/updater.phar/lib/Updater.php(132): NC\Updater\Updater->getUpdateServerResponse()
#1 phar:///var/www/html/nextcloud/updater/updater.phar/lib/UpdateCommand.php(155): NC\Updater\Updater->checkForUpdate()
#2 phar:///var/www/html/nextcloud/updater/updater.phar/vendor/symfony/console/Command/Command.php(255): NC\Updater\UpdateCommand->execute()
#3 phar:///var/www/html/nextcloud/updater/updater.phar/vendor/symfony/console/Application.php(1009): Symfony\Component\Console\Command\Command->run()
#4 phar:///var/www/html/nextcloud/updater/updater.phar/vendor/symfony/console/Application.php(273): Symfony\Component\Console\Application->doRunCommand()
#5 phar:///var/www/html/nextcloud/updater/updater.phar/vendor/symfony/console/Application.php(149): Symfony\Component\Console\Application->doRun()
#6 phar:///var/www/html/nextcloud/updater/updater.phar/updater.php(10): Symfony\Component\Console\Application->run()
#7 /var/www/html/nextcloud/updater/updater.phar(14): require('...')
#8 {main}
thrown in phar:///var/www/html/nextcloud/updater/updater.phar/lib/Updater.php on line 495
root@nextcloud:/var/www/html/nextcloud#
Bei mir fehlte php-curl und php-xml, also musste ich das nach installieren:
sudo apt-get install php-curl php-xml
Danach lief er bei mir:
root@nextcloud:/var/www/html/nextcloud# sudo -u www-data php updater/updater.phar
Nextcloud Updater - version: v26.0.0beta2-9-g64e2e4c dirty
Current version is 27.1.1.
Update to Nextcloud 27.1.7 available. (channel: "stable")
Following file will be downloaded automatically: https://download.nextcloud.com/server/releases/nextcloud-27.1.7.zip
Open changelog ↗
Steps that will be executed:
[ ] Check for expected files
[ ] Check for write permissions
[ ] Create backup
[ ] Downloading
[ ] Verify integrity
[ ] Extracting
[ ] Enable maintenance mode
[ ] Replace entry points
[ ] Delete old files
[ ] Move new files in place
[ ] Done
Start update? [y/N] Y
Info: Pressing Ctrl-C will finish the currently running step and then stops the updater.
[✔] Check for expected files
[✔] Check for write permissions
[ ] Create backup ...
Fehler zwei, es fehlte hier die Zip Erweiterung:
Info: Pressing Ctrl-C will finish the currently running step and then stops the updater.
[✔] Check for expected files
[✔] Check for write permissions
[✔] Create backup
[✔] Downloading
[✔] Verify integrity
[ ] Extracting ...PHP Fatal error: Uncaught Error: Class "ZipArchive" not found in phar:///var/www/html/nextcloud/updater/updater.phar/lib/Updater.php:693
Stack trace:
#0 phar:///var/www/html/nextcloud/updater/updater.phar/lib/UpdateCommand.php(383): NC\Updater\Updater->extractDownload()
#1 phar:///var/www/html/nextcloud/updater/updater.phar/lib/UpdateCommand.php(240): NC\Updater\UpdateCommand->executeStep()
#2 phar:///var/www/html/nextcloud/updater/updater.phar/vendor/symfony/console/Command/Command.php(255): NC\Updater\UpdateCommand->execute()
#3 phar:///var/www/html/nextcloud/updater/updater.phar/vendor/symfony/console/Application.php(1009): Symfony\Component\Console\Command\Command->run()
#4 phar:///var/www/html/nextcloud/updater/updater.phar/vendor/symfony/console/Application.php(273): Symfony\Component\Console\Application->doRunCommand()
#5 phar:///var/www/html/nextcloud/updater/updater.phar/vendor/symfony/console/Application.php(149): Symfony\Component\Console\Application->doRun()
#6 phar:///var/www/html/nextcloud/updater/updater.phar/updater.php(10): Symfony\Component\Console\Application->run()
#7 /var/www/html/nextcloud/updater/updater.phar(14): require('...')
#8 {main}
thrown in phar:///var/www/html/nextcloud/updater/updater.phar/lib/Updater.php on line 693
root@nextcloud:/var/www/html/nextcloud#
Also muss hier zip für php noch installiert werden:
sudo apt-get install php-zip
Unifi Controller startet nicht mehr
Fehler - /var/log/unifi/server.log :
[2024-03-07 03:17:19,025] <db-server> INFO db - Checking if database needs to be shut down
[2024-03-07 03:17:20,026] <db-server> INFO db - Database was not running
[2024-03-07 03:17:20,026] <db-server> INFO db - Database configuration, dir=/usr/lib/unifi/data/db, port=27117
[2024-03-07 03:17:20,114] <db-server> ERROR system - unable to exec
java.io.IOException: Cannot run program "bin/mongod" (in directory "/usr/lib/unifi"): error=0, Failed to exec spawn helper: pid: 755101, signal: 11
at java.base/java.lang.ProcessBuilder.start(ProcessBuilder.java:1143)
at java.base/java.lang.ProcessBuilder.start(ProcessBuilder.java:1073)
at com.ubnt.ace.B.Ôo0000(Unknown Source)
at com.ubnt.ace.B.Öô0000(Unknown Source)
at com.ubnt.ace.B.oÖ0000(Unknown Source)
at com.ubnt.service.system.z.Òô0000(Unknown Source)
at com.ubnt.service.system.z$1.run(Unknown Source)
at java.base/java.lang.Thread.run(Thread.java:833)
Caused by: java.io.IOException: error=0, Failed to exec spawn helper: pid: 755101, signal: 11
at java.base/java.lang.ProcessImpl.forkAndExec(Native Method)
at java.base/java.lang.ProcessImpl.<init>(ProcessImpl.java:314)
at java.base/java.lang.ProcessImpl.start(ProcessImpl.java:244)
at java.base/java.lang.ProcessBuilder.start(ProcessBuilder.java:1110)
... 7 common frames omitted
[2024-03-07 03:17:20,114] <db-server> INFO db - Starting database process...
[2024-03-07 03:17:20,205] <db-server> ERROR system - unable to exec
java.io.IOException: Cannot run program "bin/mongod" (in directory "/usr/lib/unifi"): error=0, Failed to exec spawn helper: pid: 755109, signal: 11
at java.base/java.lang.ProcessBuilder.start(ProcessBuilder.java:1143)
at java.base/java.lang.ProcessBuilder.start(ProcessBuilder.java:1073)
at com.ubnt.ace.B.ô00000(Unknown Source)
at com.ubnt.ace.B.oÔ0000(Unknown Source)
at com.ubnt.service.system.z.Òô0000(Unknown Source)
at com.ubnt.service.system.z$1.run(Unknown Source)
at java.base/java.lang.Thread.run(Thread.java:833)
Caused by: java.io.IOException: error=0, Failed to exec spawn helper: pid: 755109, signal: 11
at java.base/java.lang.ProcessImpl.forkAndExec(Native Method)
at java.base/java.lang.ProcessImpl.<init>(ProcessImpl.java:314)
at java.base/java.lang.ProcessImpl.start(ProcessImpl.java:244)
at java.base/java.lang.ProcessBuilder.start(ProcessBuilder.java:1110)
... 6 common frames omitted
[2024-03-07 03:17:20,205] <db-server> INFO db - Database process stopped...
[2024-03-07 03:17:21,904] <stamgr> WARN cache - unable to retrieve settings in site 6432ba9476f22131549ac718
com.google.common.util.concurrent.UncheckedExecutionException: com.mongodb.MongoTimeoutException: Timed out after 10000 ms while waiting to connect. Client view of cluster state is {type=UNKNOWN, servers=[{address=localhost:27117, type=UNKNOWN, state=CONNECTING, exception={com.mongodb.MongoSocketOpenException: Exc>
at com.google.common.cache.LocalCache$Segment.get(LocalCache.java:2055)
at com.google.common.cache.LocalCache.get(LocalCache.java:3966)
at com.google.common.cache.LocalCache.getOrLoad(LocalCache.java:3989)
at com.google.common.cache.LocalCache$LocalLoadingCache.get(LocalCache.java:4950)
at com.ubnt.service.system.OooO.ôöØ000(Unknown Source)
at com.ubnt.service.system.OooO.oøØ000(Unknown Source)
at com.ubnt.service.event.A.newreturnnew(Unknown Source)
at com.ubnt.service.event.A.oöÓ000(Unknown Source)
at com.ubnt.service.event.A.ÔõÓ000(Unknown Source)
at com.ubnt.service.devmgr.classObject.StringdoObject(Unknown Source)
at com.ubnt.service.system.newnew.ÖO0000(Unknown Source)
at com.ubnt.ace.B$_OOo.run(Unknown Source)
at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:539)
at java.base/java.util.concurrent.FutureTask.runAndReset(FutureTask.java:305)
at java.base/java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:305)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
at java.base/java.lang.Thread.run(Thread.java:833)
Caused by: com.mongodb.MongoTimeoutException: Timed out after 10000 ms while waiting to connect. Client view of cluster state is {type=UNKNOWN, servers=[{address=localhost:27117, type=UNKNOWN, state=CONNECTING, exception={com.mongodb.MongoSocketOpenException: Exception opening socket}, caused by {java.net.ConnectE>
at com.mongodb.internal.connection.BaseCluster.getDescription(BaseCluster.java:180)
at com.mongodb.internal.connection.SingleServerCluster.getDescription(SingleServerCluster.java:44)
at com.mongodb.client.internal.MongoClientDelegate.getConnectedClusterDescription(MongoClientDelegate.java:144)
at com.mongodb.client.internal.MongoClientDelegate.createClientSession(MongoClientDelegate.java:101)
at com.mongodb.client.internal.MongoClientDelegate$DelegateOperationExecutor.getClientSession(MongoClientDelegate.java:291)
at com.mongodb.client.internal.MongoClientDelegate$DelegateOperationExecutor.execute(MongoClientDelegate.java:183)
at com.mongodb.client.internal.FindIterableImpl.first(FindIterableImpl.java:213)
at com.ubnt.service.system.z.Stringnull(Unknown Source)
at com.ubnt.service.system.z.Ó00000(Unknown Source)
at com.ubnt.service.system.floatsuper.ØÕ0000(Unknown Source)
at com.ubnt.service.system.OooO$2.o00000(Unknown Source)
at com.ubnt.service.system.OooO$2.load(Unknown Source)
at com.google.common.cache.LocalCache$LoadingValueReference.loadFuture(LocalCache.java:3533)
at com.google.common.cache.LocalCache$Segment.loadSync(LocalCache.java:2282)
at com.google.common.cache.LocalCache$Segment.lockedGetOrLoad(LocalCache.java:2159)
at com.google.common.cache.LocalCache$Segment.get(LocalCache.java:2049)
... 17 common frames omitted
[2024-03-07 03:17:21,904] <stamgr> INFO db - waiting for db connection...
[2024-03-07 03:17:22,011] <discover> INFO discover - [Internal] incomplete device information received
com.mongodb.MongoTimeoutException: Timed out after 10000 ms while waiting to connect. Client view of cluster state is {type=UNKNOWN, servers=[{address=localhost:27117, type=UNKNOWN, state=CONNECTING, exception={com.mongodb.MongoSocketOpenException: Exception opening socket}, caused by {java.net.ConnectException: C>
at com.mongodb.internal.connection.BaseCluster.getDescription(BaseCluster.java:180)
at com.mongodb.internal.connection.SingleServerCluster.getDescription(SingleServerCluster.java:44)
at com.mongodb.client.internal.MongoClientDelegate.getConnectedClusterDescription(MongoClientDelegate.java:144)
at com.mongodb.client.internal.MongoClientDelegate.createClientSession(MongoClientDelegate.java:101)
at com.mongodb.client.internal.MongoClientDelegate$DelegateOperationExecutor.getClientSession(MongoClientDelegate.java:291)
at com.mongodb.client.internal.MongoClientDelegate$DelegateOperationExecutor.execute(MongoClientDelegate.java:183)
at com.mongodb.client.internal.FindIterableImpl.first(FindIterableImpl.java:213)
at com.ubnt.service.system.z.Stringnull(Unknown Source)
at com.ubnt.service.system.z.Ó00000(Unknown Source)
at com.ubnt.service.devmgr.o0O0o.Õôö000(Unknown Source)
at com.ubnt.service.devmgr.o0O0o.thisinterfaceString(Unknown Source)
at com.ubnt.net.float.ÔÒø000(Unknown Source)
at com.A.A.oOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO.Object.ô00000(Unknown Source)
at com.A.A.oOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO.oOoO$1.run(Unknown Source)
at java.base/java.lang.Thread.run(Thread.java:833)
[2024-03-07 03:17:22,011] <discover> INFO db - waiting for db connection...
Der Fehler sagt aus, das er Probleme mit der mongo db also der Datenbank gibt.
Zuerst muss der Dienst gestoppt werden:
service unifi stop
In einigen Fällen, in denen das Journal beschädigt ist, ist es hilfreich, den folgenden Befehl auszuführen, bevor die Datenbank repariert wird, um sie an einen anderen Ort zu verschieben
mv -vi /usr/lib/unifi/data/db/journal /usr/lib/unifi/data/db/journal-$(date -I)
Reparieren Sie die Datenbank mit diesem Befehl:
mongod --dbpath /usr/lib/unifi/data/db --logpath /usr/lib/unifi/logs/mongod.log --repair
Starten Sie schließlich den UniFi-Dienst neu
service unifi start
Hinweis: Wenn dieser Prozess als Root durchgeführt wurde, hat sich der Dateibesitz möglicherweise geändert. Dies kann geändert werden mit:
chown -R unifi:unifi /usr/lib/unifi/data/db/
chown -R unifi:unifi /usr/lib/unifi/logs/
Linux - Zeit setzen - timedatectl
Manchmal gibt es Situationen, wo eine andere Uhrzeit Simuliert werden muss, dabei kann dir diese Seite helfen.
Uhrzeit abfragen
timedatectl
NTP deaktivieren
timedatectl set-ntp false
Kurzform - Zeit ändern
Um nur die Stunden zu ändern, reicht es, die Stunde und Minute einzutragen.
timedatectl set-time 12:00
Falls du aber nur den Tag, Jahr, usw. ändern willst, reicht das hier auch aus.
timedatectl set-time 2025-03-10
Langform - Zeit ändern
timedatectl set-time "2023-01-01 12:00"
NTP aktivieren - Normalbetrieb
timedatectl set-ntp true
Postfix
User anlegen
Ganz einfach im Terminal adduser und den Namen eingeben und danach das Passwd für den Account hinterlegen
adduser [name]
Also:
root@postfix:/home/jj# adduser nextcloud
info: Adding user `nextcloud' ...
info: Selecting UID/GID from range 1000 to 59999 ...
info: Adding new group `nextcloud' (1006) ...
info: Adding new user `nextcloud' (1006) with group `nextcloud (1006)' ...
info: Creating home directory `/home/nextcloud' ...
info: Copying files from `/etc/skel' ...
New password:
Retype new password:
passwd: password updated successfully
Changing the user information for nextcloud
Enter the new value, or press ENTER for the default
Full Name []:
Room Number []:
Work Phone []:
Home Phone []:
Other []:
Is the information correct? [Y/n]
info: Adding new user `nextcloud' to supplemental / extra groups `users' ...
info: Adding user `nextcloud' to group `users' ...
root@postfix:/home/jj#
Danach den Postfix neu einlesen lassen, bin mir nicht sicher ob das wirklich notwendig ist, habe ich noch nicht ausgiebig getestet.
Korrigiere, ist nicht notwendig, geht auch so.....
systemctl reload postfix
Webserver
Fonts
Gute Fonts
https://www.freefonts.io/download/cambria/
https://www.freefonts.io/free-ageo-geometric-sans-font-family/
https://www.freefonts.io/download/ageo-geometric-sans/
MariaDB
MariaDB Installation - Linux
sudo apt update
sudo apt install mariadb-server -y
sudo systemctl start mariadb.service
sudo mysql_secure_installation
Temp:
Die Fehlermeldung deutet darauf hin, dass es ein Problem mit der Struktur der Systemtabellen in Ihrer MariaDB-Datenbank gibt. Die Tabelle mysql.column_stats hat eine inkorrekte Definition, die nicht mit dem von Ihrer MariaDB-Version erwarteten Schema übereinstimmt.
Diese Art von Fehler kann nach einem Upgrade von MariaDB auftreten, wenn die Systemtabellen nicht korrekt aktualisiert wurden.
Lösungsschritte zur Behebung:
1. Überprüfen der MariaDB-Version
Zuerst sollten Sie die aktuelle Version Ihrer MariaDB-Installation überprüfen, um sicherzustellen, dass sie mit den erwarteten Systemtabellen übereinstimmt:
bash
mariadb --version
2. Aktualisieren der Systemtabellen
Um die Systemtabellen an das aktuelle Schema Ihrer MariaDB-Version anzupassen, können Sie den Befehl mysql_upgrade ausführen. Dieser Befehl überprüft und repariert die Systemtabellen.
Führen Sie den folgenden Befehl als root-Benutzer oder mit ausreichenden Berechtigungen aus:
bash
sudo mysql_upgrade
Starten Sie den MariaDB-Dienst nach dem Upgrade neu:
bash
sudo systemctl restart mariadb
3. Überprüfung der Tabelle mysql.column_stats
Falls der Fehler weiterhin besteht, sollten Sie die Tabelle mysql.column_stats manuell überprüfen und anpassen.
Melden Sie sich bei MariaDB an:
bash
sudo mysql -u root -p
Überprüfen Sie die Struktur der Tabelle mysql.column_stats:
sql
DESCRIBE mysql.column_stats;
Vergleichen Sie die Ausgabe mit der erwarteten Struktur laut Fehlermeldung. Es sollte wie folgt aussehen:
Spalte hist_type sollte vom Typ enum('SINGLE_PREC_HB','DOUBLE_PREC_HB','JSON_HB') sein.
Spalte histogram sollte vom Typ longblob sein.
Anpassen der Tabelle (falls nötig):
Falls die Struktur nicht korrekt ist, können Sie die Tabelle manuell anpassen:
sql
ALTER TABLE mysql.column_stats MODIFY hist_type ENUM('SINGLE_PREC_HB','DOUBLE_PREC_HB','JSON_HB');
ALTER TABLE mysql.column_stats MODIFY histogram LONGBLOB;
4. Überprüfen Sie die MariaDB-Logs
Nach den Änderungen und dem Neustart von MariaDB können Sie die MariaDB-Logs überprüfen, um sicherzustellen, dass keine weiteren Fehler auftreten:
bash
sudo tail -f /var/log/mysql/error.log
Zusammenfassung:
Führen Sie mysql_upgrade aus, um die Systemtabellen zu aktualisieren.
Überprüfen Sie die Struktur der Tabelle mysql.column_stats.
Starten Sie den MariaDB-Dienst neu und prüfen Sie die Logs.
Wenn die Fehler weiterhin bestehen oder neue Fragen aufkommen, lassen Sie es mich wissen!
UUID
UUID von Partitionen:
sudo blkid
root@Turbo:/home/jj# sudo blkid
/dev/mmcblk0p1: LABEL_FATBOOT="bootfs" LABEL="bootfs" UUID="A7E6-0C92" BLOCK_SIZE="512" TYPE="vfat" PARTUUID="5e89687f-01"
/dev/mmcblk0p2: LABEL="rootfs" UUID="f6cc7216-ff28-4ec1-86d6-b391f5f31405" BLOCK_SIZE="4096" TYPE="ext4" PARTUUID="5e89687f-02"
root@Turbo:/home/jj#
Linux System UUID:
cat /etc/machine-id
Links
Ordner wo anders mounten, unter einem anderen Pfad:
mount --bind /pfad/zum/ursprungsordner /pfad/zum/neuen/ort
Geräte ohne Internetverbindung / Keine Updates
debian / Ubuntu
syslog Ausgabe (Snapd Auto-Update):
Dec 29 00:12:21 000000005acde0e1 snapd[671]: autorefresh.go:643: Cannot prepare auto-refresh change due to a permanent network error: persistent network error: Post "https://api.snapcraft.io/v2/snaps/refresh": dial tcp: lookup api.snapcraft.io: Temporary failure in name resolution
Update-Timer auf eine ungenutzte Zeit setzen:
sudo snap set system refresh.timer=00:00-24:00
Dies legt einen Zeitbereich fest, der effektiv keine automatischen Updates ermöglicht.
Automatische Aktualisierungen vollständig deaktivieren:
Es gibt keine direkte Methode, um automatische Updates komplett zu deaktivieren, aber Sie können den Update-Intervall verlängern:
sudo snap set system refresh.hold="$(date --date='100 years' +%Y-%m-%dT%H:%M:%S)"
Dadurch werden Updates für einen sehr langen Zeitraum zurückgehalten.
Snapd-Dienst komplett deaktivieren:
Wenn Sie Snapd nicht benötigen, können Sie den Dienst komplett deaktivieren und entfernen
Snapd-Dienst stoppen und deaktivieren:
sudo systemctl stop snapd.service
sudo systemctl disable snapd.service
sudo systemctl mask snapd.service
stop: Stoppt den laufenden Snapd-Dienst.disable: Verhindert, dass Snapd beim Systemstart automatisch startet.mask: Blockiert die Möglichkeit, den Dienst manuell oder automatisch zu starten.
Snapd entfernen:
Wenn Sie sicher sind, dass Sie Snapd nicht mehr benötigen, können Sie es deinstallieren:
sudo apt purge snapd
sudo rm -rf /var/cache/snapd/
Hinweis: Stellen Sie sicher, dass keine installierten Anwendungen von Snapd abhängen, bevor Sie es entfernen.
Optional: Entfernen von Snap-Paketen und Verzeichnissen:
Um alle Snap-Pakete und zugehörigen Verzeichnisse zu entfernen:
rm -rf ~/snap
sudo rm -rf /snap
sudo rm -rf /var/snap
sudo rm -rf /var/lib/snapd
syslog Ausgabe (Linux Auto-Update):
Dec 30 11:41:00 000000005acde0e1 python3[8175]: ["2024-12-30T11:41:00.605", "WARNING", "ubuntupro.apt", "fail", 907, "Failed to fetch ESM Apt Cache item: https://esm.ubuntu.com/apps/ubuntu/dists/jammy-apps-security/InRelease", {}]
Automatische Update-Dienste deaktivieren
Ubuntu verwendet systemd-Timer, um regelmäßig nach Updates zu suchen und diese zu installieren. Sie können diese Timer deaktivieren:
sudo systemctl stop apt-daily.timer
sudo systemctl disable apt-daily.timer
sudo systemctl stop apt-daily-upgrade.timer
sudo systemctl disable apt-daily-upgrade.timer
Automatische Update-Dienste maskieren
Um sicherzustellen, dass die Dienste nicht versehentlich wieder aktiviert werden, können Sie sie maskieren:
sudo systemctl mask apt-daily.service
sudo systemctl mask apt-daily-upgrade.service
Unattended Upgrades deaktivieren
Falls das Paket unattended-upgrades installiert ist, sollten Sie es deaktivieren:
sudo systemctl stop unattended-upgrades
sudo systemctl disable unattended-upgrades
syslog Ausgabe (Linux Auto-News):
Jan 1 03:43:46 000000005acde0e1 systemd[1]: Starting Update APT News...
Deaktivieren des apt-news Dienstes
Der apt-news Dienst ist dafür verantwortlich, Nachrichten von den APT-Repositories abzurufen. Um diesen Dienst zu deaktivieren:
sudo systemctl stop apt-news.service
sudo systemctl disable apt-news.service
Überprüfen Sie, ob ein Timer für apt-news existiert, und deaktivieren Sie diesen ebenfalls:
sudo systemctl stop apt-news.timer
sudo systemctl disable apt-news.timer
Debian
Display nie ausgehen lassen
nano /etc/lightdm/lightdm.conf
xserver-command=X -s 0 -dpms
Docker installation
Hier findest du eine Schritt‑für‑Schritt-Anleitung, wie du Docker unter Debian bzw. Kali Linux installierst:
1. Voraussetzungen aktualisieren und notwendige Pakete installieren
Öffne ein Terminal und führe folgende Befehle aus:
apt-get update
apt-get install ca-certificates curl
2. Docker’s GPG-Schlüssel hinzufügen
Erstelle zunächst das Verzeichnis für die Schlüssel und lade dann den offiziellen Docker-GPG-Schlüssel herunter:
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
3. Docker-Repository in die APT-Quellen aufnehmen
Füge das Repository zu deinen APT-Quellen hinzu. Unter Debian verwendest du dazu in der Regel den Codename deiner Distribution, den du mit $(. /etc/os-release && echo "$VERSION_CODENAME") auslesen kannst:
# Add Docker's official GPG key:
apt-get update
apt-get install ca-certificates curl
install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
chmod a+r /etc/apt/keyrings/docker.asc
# Add the repository to Apt sources:
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \
$(. /etc/os-release && echo "${UBUNTU_CODENAME:-$VERSION_CODENAME}") stable" | \
tee /etc/apt/sources.list.d/docker.list > /dev/null
apt-get update
Hinweis für Kali Linux:
Da Kali eine abgeleitete Distribution ist, kann es sein, dass der automatisch ermittelte Codename (über $(. /etc/os-release && echo "$VERSION_CODENAME")) nicht korrekt ist.
In diesem Fall ersetze diesen Ausdruck manuell durch den entsprechenden Debian-Codename, z. B.:
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/debian \
bookworm stable" | \
tee /etc/apt/sources.list.d/docker.list > /dev/null
Aktualisiere danach erneut die Paketliste:
apt-get update
4. Docker-Pakete installieren
Installiere die neuesten Versionen der Docker-Pakete mit:
apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
Docker Container erstellen
Container erstellen
1. Dockerfile erstellen
Ein Dockerfile definiert, wie dein Container aufgebaut sein soll. Erstelle ein neues Verzeichnis und eine Datei Dockerfile:
# Basis-Image wählen (z. B. Debian, Ubuntu oder Alpine)
FROM ubuntu:latest
# Update und Installation von Paketen
RUN apt update && apt install -y nano curl htop
# Standard-Shell setzen
CMD ["/bin/bash"]
# Basis-Image wählen (z. B. Debian, Ubuntu oder Alpine)
FROM ubuntu:latest
# Update und Installation von Paketen
RUN apt update && apt install -y nano curl htop iputils-ping iproute2 ethstatus vnstat btop htop sshfs wget sudo cifs-utils python3 python3-venv python3-pip git
# Standard-Shell setzen
CMD ["/bin/bash"]
2. Container bauen
docker build -t mein-linux-container .
3. Container starten
Starte den Container im interaktiven Modus:
docker run -it mein-linux-container
Container CPU beschränken
Option 1 - Begrenzung mit --cpus (empfohlen)
Da dein System 12 CPU-Kerne hat und du dem Docker-Container 95% der Gesamtleistung zuweisen möchtest, hast du zwei Möglichkeiten:
Du kannst den Container mit --cpus so starten:
docker run -it --cpus="11.4" mein-linux-container
🔹 Erklärung:
- 12 Kerne * 95% = 11.4 Kerne
- Der Container kann bis zu 11.4 Kerne nutzen, aber nicht mehr.
Falls der Container bereits läuft, kannst du die Einstellung nachträglich setzen:
docker update --cpus="11.4" mein-linux-container
Option 2 - Begrenzung mit --cpu-quota und --cpu-period
Falls du eine genauere Kontrolle möchtest:
docker run -it --cpu-quota=950000 --cpu-period=1000000 mein-linux-container
🔹 Erklärung:
--cpu-period=1000000→ Definiert eine Zeitspanne von 1 Sekunde (1.000.000 Mikrosekunden).--cpu-quota=950000→ Bedeutet, dass der Container in dieser Sekunde nur 950.000 Mikrosekunden CPU-Zeit nutzen darf (also 95%).
Falls dein Container bereits läuft:
docker update --cpu-quota=950000 --cpu-period=1000000 mein-linux-container
Option 3 - Begrenzung auf bestimmte Kerne mit --cpuset-cpus
Falls du den Container auf 11 von 12 Kernen begrenzen möchtest:
docker run -it --cpuset-cpus="0-10" mein-linux-container
🔹 Erklärung:
- Der Container darf nur CPU 0 bis CPU 10 nutzen (11 Kerne von 12).
- Dadurch wird die Leistung auf ca. 91.6% begrenzt (11/12), was nahe an 95% liegt.
Fazit: Welche Methode solltest du nehmen?
✅ Für eine einfache Begrenzung:
Nutze --cpus="11.4" → Leicht verständlich und flexibel.
✅ Für eine exakte Kontrolle über CPU-Zeit:
Nutze --cpu-quota=950000 --cpu-period=1000000.
✅ Falls du nur bestimmte Kerne zuweisen willst:
Nutze --cpuset-cpus="0-10" (≈91.6% Leistung).
Container CPU beschränken ohne Datenverlust
Option 1 - Container mit --rm vermeiden
Falls du den Container mit --rm gestartet hast, wird er nach dem Beenden gelöscht.
Starte den Container stattdessen ohne --rm, damit er bestehen bleibt:
docker run -it --cpus="11.4" --name mein-linux-container mein-linux-container
🔹 Erklärung:
--name test_land_1_container→ Gibt dem Container einen festen Namen, damit du ihn später wiederfinden kannst.- Nach
exitbleibt der Container bestehen, aber gestoppt.
Starte ihn später wieder mit:
docker start -ai mein-linux-container
Falls du ihn nicht interaktiv starten willst:
docker start mein-linux-container
docker attach mein-linux-container
Option 2 - Den Container committen (Änderungen dauerhaft speichern)
Falls du sysbench bereits installiert hast und den Container beenden möchtest, kannst du die Änderungen mit docker commit in ein neues Image speichern:
docker commit mein-linux-container mein-linux-container
🔹 Erklärung:
- Erstellt ein neues Image mit dem Namen
test_land_1_sysbench, das alle Änderungen enthält. - Danach kannst du es jederzeit mit folgendem Befehl starten:
docker run -it --cpus="11.4" mein-linux-container
Falls du möchtest, dass der Container diese Änderungen auch nach dem Schließen speichert, kannst du stattdessen docker start verwenden:
docker start -ai mein-linux-container
Option 3 - Ein Dockerfile nutzen (Empfohlen für reproduzierbare Container)
Falls du sysbench immer in diesem Container haben willst, solltest du ein Dockerfile erstellen:
Erstelle eine Datei Dockerfile:
FROM ubuntu:latest
RUN apt update && apt install -y sysbench
CMD ["/bin/bash"]
Baue das Image mit:
docker build -t mein-linux-container .
Starte den Container:
docker run -it --cpus="11.4" mein-linux-container
Vorteile:
✅ Jedes Mal, wenn du das Image nutzt, ist sysbench bereits installiert.
✅ Reproduzierbar – kannst du auf anderen Systemen wiederverwenden.
Nützliche Pakete
Ping (ping 1.1.1.1):
apt-get install iputils-ping -y
ip tools (ip a):
apt install iproute2 -y
Shortcuts - FN Tasten
Überprüfen von ACPI-Ereignissen
Installiere und starte den ACPI-Dienst:
sudo apt-get update
sudo apt-get install acpid
sudo systemctl enable acpid
sudo systemctl start acpid
Verwende acpi_listen, um zu sehen, ob die Fn-Tasten ACPI-Ereignisse auslösen:
acpi_listen
Drücke nun nacheinander die Fn-Tasten F9, F10 und F11.
Beobachte die Ausgabe im Terminal.
ACPI
ACPI arbeitet über ein Ereignissystem, das in deinem System so konfiguriert ist, dass es bei bestimmten Hardware-Ereignissen (wie z. B. Fn-Tastendrücken) automatisch Skripte oder Befehle ausführt. Hier eine Erklärung, wie das im Detail funktioniert:
-
ACPI-Ereignisdateien:
Im Verzeichnis/etc/acpi/events/liegen Konfigurationsdateien wiemedia_prev. Jede dieser Dateien enthält zwei wichtige Teile:- event=...
Hier wird ein Muster definiert, das einem bestimmten ACPI-Ereignis entspricht. Zum Beispiel könnteevent=ibm/hotkey LEN0268:00 00000080 00001317genau dem Signal entsprechen, das gesendet wird, wenn du F9 drückst. - action=...
Hier wird angegeben, welcher Befehl oder welches Skript ausgeführt werden soll, wenn ein Ereignis eintritt, das dem Muster entspricht. Im Fall vonmedia_prevwäre das beispielsweise ein Skript, das den Befehlplayerctl previousausführt, um zum vorherigen Track zu wechseln.
- event=...
-
Der ACPI-Daemon (acpid):
Beim Systemstart lädt der ACPI-Daemon (acpid) alle Dateien aus/etc/acpi/events/ein. Er „kennt“ dadurch alle Muster und die zugehörigen Aktionen.
Sobald ein ACPI-Ereignis (z. B. das Drücken von F9) vom Kernel erzeugt wird, vergleicht acpid dieses Ereignis mit den Mustern in den Konfigurationsdateien.- Passender Treffer: Findet acpid ein Muster, das zu deinem Tastendruck passt, wird automatisch die in der Datei definierte Aktion ausgeführt.
-
Kein manuelles „Verlinken“ nötig:
Es gibt keine separate Konfigurationsdatei, in der du explizit die Fn-Tasten mit den Skripten verknüpfst.
Stattdessen durchforstet acpid beim Start das Verzeichnis/etc/acpi/events/und „registriert“ alle darin enthaltenen Ereignismuster.
Wenn du also F9 drückst und das ACPI-Ereignis exakt mit dem in der Dateimedia_prevdefinierten Muster übereinstimmt, weiß acpid automatisch, dass es das entsprechende Skript (bzw. den Befehl) ausführen soll.
Zusammengefasst:
- ACPI-Ereignisdateien im Verzeichnis
/etc/acpi/events/definieren, welches ACPI-Signal (Muster) welcher Aktion zugeordnet ist. - Der ACPI-Daemon liest diese Dateien beim Start und überwacht fortlaufend die Ereignisse.
- Wenn ein Ereignis (z. B. F9) erkannt wird, das mit einem in einer dieser Dateien definierten Muster übereinstimmt, führt acpid die entsprechende Aktion aus (z. B. "Track zurück").
So „weiß“ das System also automatisch, dass bei einem F9-Druck der vorherige Track abgespielt werden soll – alles basiert auf den in den ACPI-Ereignisdateien definierten Mustern und Aktionen.
Next Song - Spotify
/etc/acpi/events/media_next
event=ibm/hotkey LEN0268:00 00000080 00001319
action=/usr/bin/sudo -u jj /etc/acpi/local/media_next.sh
/etc/acpi/local/media_next.sh
#!/bin/bash
export DISPLAY=:0.0
export XAUTHORITY=/home/jj/.Xauthority
export DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus
playerctl -p spotify next
Previous Song - Spotfy
/etc/acpi/events/media_prev
event=ibm/hotkey LEN0268:00 00000080 00001317
action=/usr/bin/sudo -u jj /etc/acpi/local/media_prev.sh
/etc/acpi/local/media_prev.sh
#!/bin/bash
export DISPLAY=:0.0
export XAUTHORITY=/home/jj/.Xauthority
export DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus
playerctl -p spotify previous
Play and Pause - Spotify
/etc/acpi/events/media_play_pause
event=ibm/hotkey LEN0268:00 00000080 00001318
action=/usr/bin/sudo -u jj /etc/acpi/local/media_play_pause.sh
/etc/acpi/local/media_play_pause.sh
#!/bin/bash
export DISPLAY=:0.0
export XAUTHORITY=/home/jj/.Xauthority
export DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus
playerctl -p spotify play-pause
Syslog Server
Release Key hinzufügen:
wget -qO - https://ose-repo.syslog-ng.com/apt/syslog-ng-ose-pub.asc | sudo apt-key add -
Reposetory vorbereiten
echo "deb https://ose-repo.syslog-ng.com/apt/ stable ubuntu-noble" | sudo tee -a /etc/apt/sources.list.d/syslog-ng-ose.list
Listen Updaten:
apt-get update
Installieren:
apt-get install syslog-ng-core syslog-ng-scl
Syslog einrichten
/etc/syslog-ng/syslog-ng.conf:
Füge das ganz unten dazu:
source s_network {
# Empfang über UDP an Port 514
udp(ip("0.0.0.0") port(514));
# Falls auch TCP benötigt wird, kannst Du diesen Block hinzufügen:
tcp(ip("0.0.0.0") port(514));
};
destination d_remote {
file("/var/log/syslog-ng/remote.log"
owner("root") group("adm")
perm(0640)
create-dirs(yes));
};
log {
source(s_network);
destination(d_remote);
};
Testen:
sudo syslog-ng -s
Neustarten:
sudo systemctl restart syslog-ng
Netzwerk
Ubuntu - Statische IP Setzen
Um unter Ubuntu dauerhaft eine feste IP-Addresse zu setzen, musst du die Datei von netplan bearbeiten.
Ubuntu:
Um zu starten musst du folgende Datei bearbeiten.
Ubuntu Server 24.01 LTS:
nano /etc/netplan/50-cloud-init.yaml
Ubuntu Server 22.01 LTS:
nano /etc/netplan/00-installer-config.yaml
Die Datei sollte in etwa diesen Inhalt haben:
# This file is generated from information provided by the datasource. Changes
# to it will not persist across an instance reboot. To disable cloud-init's
# network configuration capabilities, write a file
# /etc/cloud/cloud.cfg.d/99-disable-network-config.cfg with the following:
# network: {config: disabled}
network:
ethernets:
ens160:
# dhcp4: true
dhcp4: no
addresses:
- 10.0.0.10/24
gateway4: 10.0.0.1
nameservers:
addresses: [1.1.1.1, 8.8.8.8]
version: 2
ens160 is dabei mein Netzwerk Interface, das ist von System zu System unterschiedlich.
Um dein Interface zu erkennen, kannst du im Terminal ip a eingeben, danach werden dir alle erkannten Netzwerk Interfaces angezeigt.dhcp4: no muss gesetzt sein, da du sonst per DHCP auch nochmal eine Addresse bekommst.addresses: da kannst du entweder eine oder mehere IP Addressen eintragen, vergiss nicht dahinter die passende Subnetmaske zu setzen.gateway4: ist dann in dem falle dein Router/Firewall, halt das Gatewaynameservers: hier kannst du deine DNS Server eintragen die genutzt werden sollen
Je nachdem was für ne Rakete du bist, kannst du das ganze direkt anwenden, mit dem Risiko, das du dich von von deinem System verabschiedest und nicht mehr per SSH rauf kommst oder du testest das ganze erstmal.
Testen:
netplan try -timeout 180
Mach die Rakete oder wenn's funktioniert, dauerhaft anwenden:
netplan apply
Debian - Statische IP Setzen
Statische IP
Um unter Debian dauerhaft eine feste IP-Adresse zu setzen, musst du die Datei /etc/network/interfaces bearbeiten.
Debian:
Öffne die Datei mit nano /etc/network/interfaces und ersetze ihren Inhalt beispielsweise durch Folgendes:
auto lo
iface lo inet loopback
auto eth0
iface eth0 inet static
address 10.0.0.10
netmask 255.255.255.0
gateway 10.0.0.1
dns-nameservers 1.1.1.1 8.8.8.8
dns-search example.local
up echo "supersede ntp-servers 10.0.0.1;" >> /etc/dhcp/dhclient.conf
up echo "supersede bootfile-name 'pxelinux.0';" >> /etc/dhcp/dhclient.conf
up echo "supersede next-server 10.0.0.1;" >> /etc/dhcp/dhclient.conf
eth0 ist hier dein Netzwerk‑Interface (Name kann abweichen – prüfe mit ip a).
Testen:
netplan try -timeout 180
Dauerhaft anwenden:
netplan apply
DNS Server
Falls du die DNS‑Server nicht über DHCP verteilen möchtest oder sie sich häufig ändern, kannst du /etc/resolv.conf direkt anpassen (und optional schreibschützen):
nameserver 1.1.1.1
nameserver 8.8.8.8
Schreibschutz aktivieren:
chattr +i /etc/resolv.conf
Schreibschutz entfernen:
chattr -i /etc/resolv.conf
NTP Server abfragen und Netzwerk prüfen
NTP nutzt UDP Port 123. Ein normaler TCP-Portcheck ist daher nicht ausreichend. Wenn bestimmte NTP-Server per IP-Adresse getestet werden sollen, muss eine echte NTP-Anfrage an diese IP gesendet werden.
Keine Zusatzpakete notwendig
Der folgende Test benötigt keine zusätzlichen NTP-Tools wie ntpdig, sntp oder ntpdate. Er verwendet nur python3, falls es auf dem System vorhanden ist.
Auf normalen Debian-Systemen ist python3 häufig vorhanden. Auf sehr minimalen Systemen ist das aber nicht garantiert. Ohne python3 oder ein NTP-Tool ist ein sauberer direkter NTP-Test gegen beliebige IP-Adressen nicht sinnvoll möglich.
1. Einzelne NTP-IP testen
Beispiel-IP anpassen:
python3 - 192.168.10.10 <<'PY'
import datetime
import ipaddress
import socket
import struct
import sys
if len(sys.argv) != 2:
print("FEHLER: Bitte genau eine IP-Adresse angeben.")
sys.exit(2)
host = sys.argv[1].strip()
try:
ipaddress.ip_address(host)
except ValueError:
print(f"FEHLER {host}: Keine gültige IP-Adresse.")
sys.exit(2)
packet = bytearray(48)
packet[0] = 0x23
try:
infos = socket.getaddrinfo(host, 123, type=socket.SOCK_DGRAM)
family, socktype, proto, _, sockaddr = infos[0]
with socket.socket(family, socktype, proto) as sock:
sock.settimeout(3)
sock.sendto(packet, sockaddr)
data, addr = sock.recvfrom(512)
if len(data) < 48:
print(f"FEHLER {host}: Antwort zu kurz, keine gültige NTP-Antwort.")
sys.exit(1)
stratum = data[1]
tx_seconds, tx_fraction = struct.unpack("!II", data[40:48])
unix_time = tx_seconds - 2208988800 + tx_fraction / 2**32
server_time = datetime.datetime.fromtimestamp(unix_time, datetime.timezone.utc)
if stratum == 0:
print(f"WARNUNG {host}: Antwort erhalten, aber Stratum 0. Server lehnt die Anfrage möglicherweise ab.")
else:
print(f"OK {host}: NTP-Antwort erhalten, Stratum {stratum}, Serverzeit {server_time.isoformat()}")
except socket.timeout:
print(f"FEHLER {host}: Timeout. Keine NTP-Antwort über UDP Port 123.")
sys.exit(1)
except OSError as e:
print(f"FEHLER {host}: Netzwerkfehler: {e}")
sys.exit(1)
PY
2. Mehrere NTP-IPs testen
Die IP-Adressen in der ersten Zeile anpassen:
for ip in 192.168.10.10 192.168.10.11 192.168.10.12; do
python3 - "$ip" <<'PY'
import datetime
import ipaddress
import socket
import struct
import sys
host = sys.argv[1].strip()
try:
ipaddress.ip_address(host)
except ValueError:
print(f"FEHLER {host}: Keine gültige IP-Adresse.")
sys.exit(2)
packet = bytearray(48)
packet[0] = 0x23
try:
infos = socket.getaddrinfo(host, 123, type=socket.SOCK_DGRAM)
family, socktype, proto, _, sockaddr = infos[0]
with socket.socket(family, socktype, proto) as sock:
sock.settimeout(3)
sock.sendto(packet, sockaddr)
data, addr = sock.recvfrom(512)
if len(data) < 48:
print(f"FEHLER {host}: Antwort zu kurz, keine gültige NTP-Antwort.")
sys.exit(1)
stratum = data[1]
tx_seconds, tx_fraction = struct.unpack("!II", data[40:48])
unix_time = tx_seconds - 2208988800 + tx_fraction / 2**32
server_time = datetime.datetime.fromtimestamp(unix_time, datetime.timezone.utc)
if stratum == 0:
print(f"WARNUNG {host}: Antwort erhalten, aber Stratum 0. Server lehnt die Anfrage möglicherweise ab.")
else:
print(f"OK {host}: NTP-Antwort erhalten, Stratum {stratum}, Serverzeit {server_time.isoformat()}")
except socket.timeout:
print(f"FEHLER {host}: Timeout. Keine NTP-Antwort über UDP Port 123.")
except OSError as e:
print(f"FEHLER {host}: Netzwerkfehler: {e}")
PY
done
3. Prüfen, ob Python vorhanden ist
python3 --version
Wenn eine Versionsnummer angezeigt wird, kann der Test verwendet werden. Wenn python3: command not found erscheint, ist Python auf diesem System nicht installiert.
Warum nicht curl oder wget?
curl und wget können keine echte NTP-Abfrage machen. NTP läuft über UDP Port 123, nicht über HTTP oder HTTPS.
Mit curl oder wget kann man nur prüfen, ob HTTP/HTTPS funktioniert:
curl -I https://www.debian.org
wget --spider https://www.debian.org
Das sagt aber nichts Sicheres darüber aus, ob NTP über UDP Port 123 erlaubt ist. Denn natürlich kann Netzwerkdiagnose nicht einfach mal logisch sein.
Warum nicht nur Bash mit /dev/udp?
Bash kann zwar Daten an /dev/udp/IP/PORT senden, aber UDP hat keinen Verbindungsaufbau wie TCP. Nur weil ein UDP-Paket gesendet wurde, weiß man noch nicht, ob ein NTP-Server geantwortet hat.
Für einen brauchbaren Test muss eine echte NTP-Anfrage gesendet und die Antwort ausgewertet werden. Genau das macht der Python-Test oben.
Ergebnis bewerten
| Ergebnis | Bedeutung |
|---|---|
OK ... NTP-Antwort erhalten |
Die IP-Adresse antwortet auf NTP über UDP Port 123. |
WARNUNG ... Stratum 0 |
Der Server hat geantwortet, lehnt die Anfrage aber möglicherweise ab oder liefert keine nutzbare Zeit. |
Timeout |
Keine Antwort erhalten. UDP Port 123 wird möglicherweise blockiert oder der Server antwortet nicht. |
Netzwerkfehler |
Es gibt ein lokales Netzwerkproblem, Routingproblem oder ein Problem mit der Adresse. |
Keine gültige IP-Adresse |
Der angegebene Wert ist keine gültige IPv4- oder IPv6-Adresse. |
Kurzfazit
Wenn bestimmte IP-Adressen getestet werden sollen, reicht timedatectl nicht aus. Für einen direkten Test braucht man entweder ein NTP-Tool wie ntpdig oder einen kleinen UDP-NTP-Test wie oben mit python3.
Ohne python3, ntpdig, sntp oder ntpdate ist ein sauberer direkter NTP-Test gegen beliebige IP-Adressen nicht realistisch möglich.
Internet teilen (NAT) und Loggen
Interface identifizieren
root@Turbo:/home/jj# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host noprefixroute
valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
link/ether e4:5f:01:36:43:ce brd ff:ff:ff:ff:ff:ff
inet 192.168.6.112/24 brd 192.168.6.255 scope global dynamic noprefixroute eth0
valid_lft 75086sec preferred_lft 75086sec
inet6 fe80::782e:63d3:252f:a8d8/64 scope link noprefixroute
valid_lft forever preferred_lft forever
3: wlan0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether FF:5f:FF:36:FF:cf brd ff:ff:ff:ff:ff:ff
inet 172.200.0.1/24 brd 172.200.0.255 scope global wlan0
valid_lft forever preferred_lft forever
inet6 fe80::e65f:1ff:fe36:43cf/64 scope link
valid_lft forever preferred_lft forever
4: wlan1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
link/ether d0:37:45:36:17:ef brd ff:ff:ff:ff:ff:ff
inet 10.1.143.2/30 brd 10.1.143.3 scope global dynamic wlan1
valid_lft 75098sec preferred_lft 75098sec
root@Turbo:/home/jj#
In dem falle haben bei mir jetzt eth0 und wlan1 Internetzugriff und wlan0 macht einfach nur nen Hotspot.
SMB
SAMBA Befehle
http://lug.krems.cc/docu/samba/ch08_06.html
Influx
Daten in einem Measurement Löschen - Influx
🧹 InfluxDB 2.x – Alle Daten eines Measurements löschen
Ziel: Vollständiges Löschen aller Daten eines bestimmten Measurements aus einem Bucket in InfluxDB 2.x
📌 Voraussetzungen
- InfluxDB 2.x ist installiert und erreichbar
- Zugriff auf Influx CLI oder HTTP API
- Ein gültiger API Token mit
delete-Rechten - Bekannte Namen für:
- Measurement
- Bucket
- Organisation
🖥️ Methode 1: Löschen per Influx CLI
influx delete \
--org "MEINE_ORG" \
--bucket "MEIN_BUCKET" \
--start 1970-01-01T00:00:00Z \
--stop 2100-01-01T00:00:00Z \
--predicate '_measurement="MEIN_MEASUREMENT"'
📝 Erklärung
--org: Organisation (z. B.MyCompany)--bucket: Bucket-Name (z. B.production-metrics)--start/--stop: Zeitbereich – großzügig wählen--predicate: Filter auf Measurement
🔐 Authentifizierung
export INFLUX_TOKEN="DEIN_TOKEN_HIER"
🌐 Methode 2: Löschen über HTTP API
📩 Request
POST /api/v2/delete?org=MEINE_ORG&bucket=MEIN_BUCKET
Authorization: Token DEIN_TOKEN
Content-Type: application/json
{
"start": "1970-01-01T00:00:00Z",
"stop": "2100-01-01T00:00:00Z",
"predicate": "_measurement=\"MEIN_MEASUREMENT\""
}
🔗 Beispiel mit curl
curl --request POST \
"http://localhost:8086/api/v2/delete?org=MEINE_ORG&bucket=MEIN_BUCKET" \
--header "Authorization: Token DEIN_TOKEN" \
--header "Content-Type: application/json" \
--data '{
"start": "1970-01-01T00:00:00Z",
"stop": "2100-01-01T00:00:00Z",
"predicate": "_measurement=\"MEIN_MEASUREMENT\""
}'
⚠️ Hinweise
- Ein Zeitbereich ist zwingend erforderlich – kein direktes
DROP MEASUREMENT - Daten sind nicht wiederherstellbar – ggf. vorher sichern
- Bei mehreren Measurements: Prozess einzeln wiederholen
✅ Beispiel
influx delete \
--org "my-org" \
--bucket "iot-data" \
--start 1970-01-01T00:00:00Z \
--stop 2100-01-01T00:00:00Z \
--predicate '_measurement="temperatur_sensor"'
Influx - Datenbank anlegen
0 | Vorbereitungen
apt-get update
apt-get install -y \
curl gnupg ca-certificates lsb-release coreutils
1 | Repository & Paketinstallation
curl --silent --location -O https://repos.influxdata.com/influxdata-archive.key
echo "943666881a1b8d9b849b74caebf02d3465d6beb716510d86a39f6c8e8dac7515 influxdata-archive.key" \
| sha256sum --check -
cat influxdata-archive.key | gpg --dearmor \
| tee /etc/apt/trusted.gpg.d/influxdata-archive.gpg >/dev/null
echo 'deb [signed-by=/etc/apt/trusted.gpg.d/influxdata-archive.gpg] https://repos.influxdata.com/debian stable main' \
| tee /etc/apt/sources.list.d/influxdata.list
apt-get update
apt-get install -y influxdb2
systemctl enable --now influxdb
2 | Selbst-signiertes Zertifikat erzeugen (100 Jahre)
cat > /root/san.cnf <<'EOF'
[req]
distinguished_name = dn
req_extensions = v3_req
prompt = no
[dn]
CN = influxdb.local
[v3_req]
keyUsage = digitalSignature, keyEncipherment, dataEncipherment
extendedKeyUsage = serverAuth
subjectAltName = @alt
[alt]
DNS.1 = influxdb.local
IP.1 = 127.0.0.1
EOF
openssl req -new -newkey rsa:4096 -nodes \
-keyout /etc/ssl/influxdb.key \
-out /etc/ssl/influxdb.csr \
-config /root/san.cnf
openssl x509 -req -in /etc/ssl/influxdb.csr \
-signkey /etc/ssl/influxdb.key \
-out /etc/ssl/influxdb.crt \
-days 36500 -extensions v3_req -extfile /root/san.cnf
rm /etc/ssl/influxdb.csr /root/san.cnf
chown influxdb:influxdb /etc/ssl/influxdb.{crt,key}
chmod 644 /etc/ssl/influxdb.crt
chmod 600 /etc/ssl/influxdb.key
3 | HTTPS in config.toml aktivieren
# Default-Konfig erzeugen, falls nicht vorhanden
test -f /etc/influxdb/config.toml || influxd print-config > /etc/influxdb/config.toml
# Port sicherstellen & alte TLS-Zeilen entfernen
sed -i \
-e 's|^[# ]*http-bind-address .*|http-bind-address = ":8086"|' \
-e '/^[# ]*tls-cert /d' \
-e '/^[# ]*tls-key /d' \
/etc/influxdb/config.toml
# TLS-Pfad-Direktiven anhängen
cat >> /etc/influxdb/config.toml <<'EOT'
tls-cert = "/etc/ssl/influxdb.crt"
tls-key = "/etc/ssl/influxdb.key"
EOT
# Influx-Startskript auf diese Konfig verweisen
echo 'INFLUXD_CONFIG_PATH=/etc/influxdb/config.toml' > /etc/default/influxdb2
systemctl daemon-reload
systemctl restart influxdb
4 | Funktionstest
curl --insecure https://localhost:8086/api/v2/ping -I
# Erwartung: HTTP/1.1 204 No Content
Hinweise
- Browser warnen bei selbst-signierten Zertifikaten – für interne Netze meist unkritisch.
- Für öffentliche Zugriffe besser Let’s Encrypt verwenden.
- InfluxDB 3-Docker-Images akzeptieren die TLS-Pfad-Parameter direkt in
docker run ….
5 | Alles-in-einem-Skript (Copy & Paste)
#!/usr/bin/env bash
# install_influxdb_https.sh – Einmal ausführen, um InfluxDB 2 + HTTPS einzurichten
set -euo pipefail
### 0 | Pakete
apt-get update
apt-get install -y curl gnupg ca-certificates lsb-release coreutils
### 1 | Repo & Paket
curl --silent --location -O https://repos.influxdata.com/influxdata-archive.key
echo "943666881a1b8d9b849b74caebf02d3465d6beb716510d86a39f6c8e8dac7515 influxdata-archive.key" | sha256sum --check -
cat influxdata-archive.key | gpg --dearmor | tee /etc/apt/trusted.gpg.d/influxdata-archive.gpg >/dev/null
echo 'deb [signed-by=/etc/apt/trusted.gpg.d/influxdata-archive.gpg] https://repos.influxdata.com/debian stable main' \
| tee /etc/apt/sources.list.d/influxdata.list
apt-get update
apt-get install -y influxdb2
systemctl enable --now influxdb
### 2 | TLS-Zertifikat (100 Jahre)
cat >/tmp/san.cnf <<'EOF'
[req]
distinguished_name = dn
req_extensions = v3_req
prompt = no
[dn]
CN = influxdb.local
[v3_req]
keyUsage = digitalSignature, keyEncipherment, dataEncipherment
extendedKeyUsage = serverAuth
subjectAltName = @alt
[alt]
DNS.1 = influxdb.local
IP.1 = 127.0.0.1
EOF
openssl req -new -newkey rsa:4096 -nodes \
-keyout /etc/ssl/influxdb.key \
-out /etc/ssl/influxdb.csr \
-config /tmp/san.cnf
openssl x509 -req -in /etc/ssl/influxdb.csr -signkey /etc/ssl/influxdb.key \
-out /etc/ssl/influxdb.crt -days 36500 -extensions v3_req -extfile /tmp/san.cnf
rm /etc/ssl/influxdb.csr /tmp/san.cnf
chown influxdb:influxdb /etc/ssl/influxdb.{crt,key}
chmod 644 /etc/ssl/influxdb.crt
chmod 600 /etc/ssl/influxdb.key
### 3 | config.toml anpassen
test -f /etc/influxdb/config.toml || influxd print-config > /etc/influxdb/config.toml
sed -i -e 's|^[# ]*http-bind-address .*|http-bind-address = ":8086"|' \
-e '/^[# ]*tls-cert /d' -e '/^[# ]*tls-key /d' \
/etc/influxdb/config.toml
printf "\ntls-cert = \"/etc/ssl/influxdb.crt\"\ntls-key = \"/etc/ssl/influxdb.key\"\n" \
>> /etc/influxdb/config.toml
echo 'INFLUXD_CONFIG_PATH=/etc/influxdb/config.toml' > /etc/default/influxdb2
### 4 | Neustart & Test
systemctl daemon-reload
systemctl restart influxdb
curl --insecure https://localhost:8086/api/v2/ping -I
echo "✔ InfluxDB läuft jetzt per HTTPS auf Port 8086"
Vim
Änderungen rückgängig machen
In Vim kannst du Änderungen mit u (undo) rückgängig machen und mit Strg + R (redo) wiederherstellen:
- In den Normal Mode wechseln (drücke
Esc, um sicherzugehen, dass du im Normal Mode bist). udrücken, um den letzten Befehl bzw. die letzte Änderung rückgängig zu machen.- Mehrmals
udrücken, um mehrere Schritte rückgängig zu machen. Strg + Rdrücken, um rückgängig gemachte Schritte wiederherzustellen (Redo).
Berechtigungen - chmod
🔐 Rechteverwaltung unter Linux – chmod erklärt
Linux verwendet ein einfaches, aber mächtiges System zur Rechtevergabe für Dateien und Ordner. Mit dem Befehl chmod kannst du steuern, wer lesen, schreiben oder ausführen darf – mit Zahlen (z. B. chmod 770) oder Buchstaben (z. B. chmod g+s).
📁 Die 3 Ebenen der Dateiberechtigungen
- Owner – der Benutzer, dem die Datei gehört
- Group – die Gruppe, der die Datei zugewiesen ist
- Others – alle anderen Benutzer
Für jede dieser Ebenen kannst du Berechtigungen vergeben:
r= read (lesen)w= write (schreiben)x= execute (ausführen, z. B. Skript starten oder in Ordner wechseln)
🔢 chmod mit Zahlen
Die häufigste Form ist die Zahlendarstellung, z. B. chmod 755 datei
Jede Ziffer steht für einen Teil der Berechtigung:
| Zahl | Binär | Bedeutung | Erlaubt |
|---|---|---|---|
| 0 | 000 | --- | keine Rechte |
| 1 | 001 | --x | nur ausführen |
| 2 | 010 | -w- | nur schreiben |
| 3 | 011 | -wx | schreiben + ausführen |
| 4 | 100 | r-- | nur lesen |
| 5 | 101 | r-x | lesen + ausführen |
| 6 | 110 | rw- | lesen + schreiben |
| 7 | 111 | rwx | alles erlaubt |
Beispiel:
chmod 750 meinskript.sh
# ergibt: rwxr-x--- (Owner: alles, Group: lesen + ausführen, Others: nichts)
🔤 chmod mit Buchstaben (symbolische Schreibweise)
Du kannst Berechtigungen auch gezielt setzen oder entfernen:
chmod u+x datei→ gib dem Owner das Recht, die Datei auszuführenchmod g-w datei→ entziehe der Gruppe das Schreibrechtchmod o=r datei→ setze für „Others“ nur Leserecht
Die Buchstaben stehen für:
- u = user (Owner)
- g = group
- o = others
- a = all
⚙️ Spezielle Modi: Setuid, Setgid, Sticky
| Bit | Zahl | Symbol | Beschreibung |
|---|---|---|---|
| Setuid | 4 | s | Prozesse starten mit den Rechten des Dateibesitzers |
| Setgid | 2 | s | Neue Dateien im Ordner erben die Gruppenzugehörigkeit |
| Sticky Bit | 1 | t | Nur der Besitzer darf Dateien löschen (z. B. in /tmp) |
Beispiel: Gruppenvererbung aktivieren
chmod 2770 /gemeinsamer/ordner
# Ergebnis: rwxrws--- (Setgid aktiv → Gruppe wird vererbt!)
Alternativ:
chmod g+s /pfad
🧠 Beispiele aus der Praxis
# Nur Besitzer darf lesen + schreiben, Gruppe darf nur lesen:
chmod 640 datei.txt
# Alles für Besitzer und Gruppe, andere dürfen durch Verzeichnis springen:
chmod 2771 /mnt/shared
# Alle dürfen alles:
chmod 777 /mnt/offen
# Gruppe "admin" soll dauerhaft Zugriff behalten:
chown root:admin /mnt/projekt
chmod 2770 /mnt/projekt
🔍 Rechte prüfen mit ls -l
Mit ls -l siehst du die Rechte:
-rwxrws--- 1 root admin ... ← s = Setgid aktiv
drwxrwxrwt 2 root root ... ← t = Sticky Bit aktiv (z. B. /tmp)
✅ Zusammenfassung
- Numerisch:
chmod 755 datei - Symbolisch:
chmod g+s ordner - Gruppenvererbung: Setgid mit
chmod 2XXX - Prüfen:
ls -lzeigt alle Rechte
Nutze Setgid für gemeinsame Team-Ordner, Sticky für geteilte Schreibbereiche und plane Rechte frühzeitig – spart dir später Ärger 😉
Bluetooth Autoconnect
Bluetooth-Geräte verbinden sich ständig von selbst? – Fix für Kali Linux (2024 / 2025)
Betroffene Systeme
Kali Linux Rolling ab etwa 2024-04 bis heute (Debian testing / sid).
Entscheidend ist die neue Kombination aus pipewire 1.0 +, wireplumber 0.5 + und blueman 2.3 +.
Das Symptom
Nach einem Dist-Upgrade verbindet sich der Laptop alle 30-60 s wieder mit bereits gekoppelten Bluetooth-Geräten (Headsets, Lautsprecher …), auch wenn diese gerade an einem anderen Gerät (z. B. Handy) genutzt werden.
Warum passiert das?
- Blueman ist das kleine Tray-Tool, das Deine Bluetooth-Verbindungen verwaltet. Seit Version 2.3 ist sein Plugin “Auto Connect” standardmäßig aktiv.
- Das Plugin prüft periodisch die Liste
servicesin der Benutzerdatenbank (dconf). Ist die Liste nicht leer, versucht Blueman dauernd „verwaiste“ Geräte wieder einzuhängen, egal wasbluetoothd, PipeWire oder WirePlumber dazu sagen.
Was bewirkt dconf reset -f /org/blueman/ ?
dconf ist die Datenbank, in der GTK-Programme ihre Benutzer-Einstellungen speichern (ähnlich der Windows-Registry). Der Befehl dconf reset -f /org/blueman/ löscht alle Blueman-Schlüssel **für den aktuellen Benutzer** – also auch die Liste services des Auto-Connect-Plugins.
Schritt-für-Schritt-Fix
- Öffne ein Terminal als Dein normaler Benutzer (nicht
root). -
Blueman beenden:
killall blueman-applet 2>/dev/null -
Blueman-Einstellungen zurücksetzen:
→ die Listedconf reset -f /org/blueman/serviceswird auf[]gesetzt, alle Plugins stehen wieder auf ihren Default-Werten (Auto-Connect = aus). -
Applet neu starten (leise im Hintergrund):
nohup blueman-applet >/dev/null 2>&1 & -
Test:
- Headset am Laptop trennen.
- Headset am Handy verbinden.
- Eine Minute warten – der Laptop soll jetzt nicht mehr stören.
Was, wenn ich Auto-Connect später wieder brauche?
Einfach Blueman-Manager → Plugins → Häkchen bei “Auto Connect” erneut setzen (oder mitgsettings set org.blueman.plugins.autoconnect services "['audio', 'input']" die Dienste einzeln hinzufügen).
vnstat - Interface adden
vnStat: Netzwerk-Traffic-Monitoring für mehrere Interfaces
vnStat ist ein ressourcenschonendes Tool zur Überwachung von Netzwerkdatenverkehr unter Linux. Diese Anleitung erklärt, wie du vnStat so einrichtest, dass es alle verfügbaren Interfaces überwacht, inklusive VPN- oder virtuellen Interfaces wie wg0 (WireGuard), tailscale0, usw.
1. Voraussetzungen
- Debian oder kompatibles Linux-System
- Root-Rechte (
sudo) vnstatinstalliert:
sudo apt install vnstat
2. Verfügbare Netzwerkschnittstellen anzeigen
Zeige alle verfügbaren Interfaces an:
ip link show
Oder alternativ:
ls /sys/class/net/
Beispielausgabe:
lo eth0 wg0 tailscale0
3. Schnittstellen zu vnStat hinzufügen
Füge jedes gewünschte Interface manuell zur vnStat-Datenbank hinzu:
sudo vnstat --add -i <interface-name>
Beispiel:
sudo vnstat --add -i wg0
sudo vnstat --add -i tailscale0
Wiederhole den Befehl für jedes Interface, das du überwachen möchtest.
4. Dienst neu starten
Damit vnStat mit den neuen Einstellungen arbeitet, starte den Dienst neu:
sudo systemctl restart vnstat
5. Überwachte Interfaces anzeigen
Überprüfe, welche Interfaces derzeit überwacht werden:
vnstat --iflist
Oder zeige Statistiken für ein bestimmtes Interface:
vnstat -i wg0
6. Optional: Automatisches Hinzufügen neuer Interfaces
Falls du häufig neue oder virtuelle Interfaces nutzt (z. B. durch VPNs), kannst du folgendes Skript verwenden, um automatisch alle Schnittstellen hinzuzufügen, die noch nicht überwacht werden:
#!/bin/bash
for IFACE in $(ls /sys/class/net/); do
if ! vnstat --iflist | grep -q "$IFACE"; then
sudo vnstat --add -i "$IFACE"
fi
done
Speichern z. B. als /usr/local/bin/vnstat-interface-check.sh und ausführbar machen:
chmod +x /usr/local/bin/vnstat-interface-check.sh
Dann via cron regelmäßig ausführen lassen:
crontab -e
0 * * * * /usr/local/bin/vnstat-interface-check.sh
→ Das Skript läuft stündlich und fügt neue Interfaces bei Bedarf hinzu.
7. Hinweise
- Statistiken werden in
/var/lib/vnstat/gespeichert. - Interfaces wie
lo(Loopback) sind meist nicht relevant. - Die erste Datenerfassung kann 5–10 Minuten dauern, je nach Netzwerkaktivität.
Fertig! Du hast nun eine vollständige vnStat-Konfiguration für mehrere Interfaces eingerichtet.
Nachricht an alle angemeldeten User senden
Nachrichten an angemeldete Benutzer im Linux-Terminal senden
In Linux-Systemen gibt es einfache Möglichkeiten, Nachrichten an aktuell angemeldete Benutzer zu senden. Dies ist besonders nützlich für Systemadministratoren, um wichtige Informationen schnell zu verbreiten.
1. Aktuell angemeldete Benutzer anzeigen
Verwende den Befehl who, um eine Liste aller derzeit angemeldeten Benutzer zu erhalten:
who
Die Ausgabe zeigt:
- Benutzername: Name des angemeldeten Benutzers
- Terminal: Das verwendete Terminal (z. B. pts/0)
- Datum und Uhrzeit: Zeitpunkt der Anmeldung
- IP-Adresse oder Hostname: Herkunft des Benutzers
2. Nachricht an alle Benutzer senden
Mit dem Befehl wall kannst du eine Nachricht an alle angemeldeten Benutzer senden:
wall Hallo zusammen!
Alle Benutzer sehen die Nachricht in ihrem Terminal.
3. Nachricht an einen bestimmten Benutzer senden
Verwende den Befehl write, um einem bestimmten Benutzer eine Nachricht zu senden:
write benutzername
Bitte kommen Sie in mein Büro
Beispiel:
write robert
Bitte kommen Sie in mein Büro
Falls der Benutzer mehrfach angemeldet ist, wird die Nachricht an das erste gefundene Terminal gesendet:
write: robert is logged in more than once; writing to pts/0
4. Nachricht an eine Benutzergruppe senden
Um Nachrichten an eine bestimmte Gruppe von Benutzern zu senden, kannst du wall in Kombination mit grep verwenden. Beispiel:
who | grep 'benutzergruppe' | awk '{print $1}' | xargs -I {} write {} Nachrichtentext
Ersetze benutzergruppe durch ein eindeutiges Merkmal der Benutzer (z. B. Gruppennamen) und Nachrichtentext durch die gewünschte Nachricht.
Fazit
Die Befehle who, wall und write ermöglichen eine effektive Kommunikation mit Benutzern direkt über das Terminal, ohne zusätzliche Software installieren zu müssen.
Thunderbird
Vivaldi anstatt Firefox als Standard - Thunderbird Linux
Diese Anleitung zeigt Schritt für Schritt, wie du Thunderbird so konfigurierst, dass Links in Vivaldi (und nicht Firefox) geöffnet werden. Sie behandelt außerdem ein häufiges Absturzproblem nach dem Link-Klick unter Kali/Debian.
1. Vivaldi als Standardbrowser im System festlegen
xdg-settings set default-web-browser vivaldi-stable.desktop
update-alternatives --set x-www-browser /usr/bin/vivaldi-stable
Prüfen mit:
xdg-settings get default-web-browser
xdg-mime query default x-scheme-handler/http
xdg-mime query default x-scheme-handler/https
Falls nötig, setzen mit:
xdg-mime default vivaldi-stable.desktop x-scheme-handler/http
xdg-mime default vivaldi-stable.desktop x-scheme-handler/https
2. Thunderbird anpassen (Konfiguration über about:config)
- Thunderbird starten
- Menü → Einstellungen → Allgemein → ganz unten „Konfiguration bearbeiten“
- Suche nach:
network.protocol-handler.app.httpnetwork.protocol-handler.app.https
→ Falls vorhanden: Zurücksetzen oder auf folgendes setzen:
/usr/bin/vivaldi-stable
Zusätzlich sicherstellen:
network.protocol-handler.external.http = true
network.protocol-handler.external.https = true
→ Falls nicht vorhanden, neu hinzufügen als Boolean.
3. Absturzproblem beheben (Vivaldi detached starten)
Bei manchen Systemen stürzt Thunderbird ab, wenn er Vivaldi direkt startet. Lösung:
- Starte Vivaldi detached im Terminal zum Test:
nohup /usr/bin/vivaldi-stable https://example.com >/dev/null 2>&1 &
- Erstelle ein Wrapper-Skript:
nano ~/vivaldi-detached.sh
Inhalt:
#!/bin/bash
nohup /usr/bin/vivaldi-stable "$@" >/dev/null 2>&1 &
- Speichern und ausführbar machen:
chmod +x ~/vivaldi-detached.sh
- In Thunderbird (
about:config):
network.protocol-handler.app.http = /home/USERNAME/vivaldi-detached.sh
network.protocol-handler.app.https = /home/USERNAME/vivaldi-detached.sh
Jetzt öffnet Thunderbird Vivaldi detached und stürzt nicht mehr ab.
4. Falls Thunderbird trotzdem crasht: Neues Profil testen
Thunderbird-Profil kann beschädigt sein.
- Alle Fenster schließen
- Terminal öffnen:
thunderbird -P
- Neues Profil erstellen (z. B. „Testprofil“)
- Starten und Vivaldi wie oben konfigurieren
5. Optional: handlers.json zurücksetzen
rm ~/.thunderbird/*.default*/handlers.json
Beim nächsten Link-Klick fragt Thunderbird, welches Programm verwendet werden soll → Vivaldi auswählen und Häkchen setzen.
Fertig! Thunderbird nutzt nun systemweit Vivaldi, stürzt nicht mehr ab, und dein Setup ist sauber konfiguriert.
RDP
Version_0.5 xfreerdp - Skript
RDP-Launcher mit xfreerdp3 – Schnellstart & Nutzung
venv schon existiert)
- Terminal öffnen
Ctrl+Alt+T - In Projektordner wechseln
cd ~/rdp-launcher - Virtuelle Umgebung aktivieren
source .venv/bin/activate
(Bei jedem neuen Terminal nötig!) - Launcher starten
./xfreerdp_launcher.py
(Falls nicht ausführbar:chmod +x xfreerdp_launcher.pynur 1x nötig)
Oder per Python:python3 xfreerdp_launcher.py - Menü nutzen, Standort & Server auswählen
- Erste Passwortabfrage – wird sicher im Keyring gespeichert
Diese Anleitung richtet sich an absolute Einsteiger und führt dich in wenigen Schritten zur ersten RDP-Sitzung.
Bitte arbeite jeden Schritt der Reihe nach ab.
1. Voraussetzungen prüfen (nur 1x nötig)
- Python & Pip:
Fehlt was?python3 --version pip3 --versionsudo apt update sudo apt install python3 python3-pip python3-venv - xfreerdp3 installieren:
sudo apt install freerdp3-x11 - Keyring-Backend? (Gnome, KDE etc: schon dabei)
2. Projektordner & venv erstellen (nur 1x nötig)
- Ordner anlegen & wechseln:
mkdir -p ~/rdp-launcher cd ~/rdp-launcher - Virtuelle Umgebung erstellen:
python3 -m venv .venv - venv aktivieren:
source .venv/bin/activate - Abhängigkeit installieren:
pip install keyring
source .venv/bin/activate ausführen, bevor du arbeitest!3. Python-Skript anlegen
Speichere folgendes als xfreerdp_launcher.py im Projektordner:
▶ Python-Code anzeigen / ausklappen
#!/usr/bin/env python3
"""
xfreerdp_launcher.py – RDP-Launcher mit TUI und Keyring-Support
Features:
- Übersichtliche, farbige Menüführung (TUI)
- Passwörter sicher im System-Keyring gespeichert
- Automatisches Neuladen der Konfiguration bei Änderungen
- Voll kompatibel mit xfreerdp3-Parametern
Benötigt:
- Python ≥ 3.9
- keyring (pip install keyring)
- config.json im selben Ordner
"""
import argparse
import json
import subprocess
import sys
import os
from pathlib import Path
from getpass import getpass
import keyring
CONFIG_FILE = Path("./config.json").resolve()
SERVICE = "xfreerdp_launcher"
def farbig(text, farbe="reset"):
farben = {
"reset": "\033[0m", "bold": "\033[1m", "red": "\033[31m",
"green": "\033[32m", "yellow": "\033[33m", "blue": "\033[34m",
"magenta": "\033[35m", "cyan": "\033[36m", "gray": "\033[90m",
"bright_red": "\033[91m", "bright_green": "\033[92m",
"bright_yellow": "\033[93m", "bright_blue": "\033[94m",
"bright_magenta": "\033[95m", "bright_cyan": "\033[96m",
"bright_white": "\033[97m"
}
return f"{farben.get(farbe, '')}{text}{farben['reset']}"
def lade_config():
try:
return json.loads(CONFIG_FILE.read_text())
except Exception as e:
print(farbig(f"⚠️ Fehler in config.json: {e}", "red"))
return {}
def passwort_holen(cred_alias, domain, user):
cred_id = f"{cred_alias}|{domain}|{user}"
pw = keyring.get_password(SERVICE, cred_id)
if pw is None:
pw = getpass(f"Passwort für {user}@{domain}: ")
if not pw:
sys.exit("Abbruch – kein Passwort eingegeben.")
keyring.set_password(SERVICE, cred_id, pw)
print(farbig("Passwort gespeichert.", "green"))
return pw
def rdp_starten(ip, domain, user, pw, extra_args):
cmd = [
"xfreerdp3",
f"/u:{user}", f"/d:{domain}", f"/v:{ip}",
"/dynamic-resolution", "/clipboard", "/cert:ignore",
f"/p:{pw}"
] + extra_args
try:
subprocess.Popen(cmd)
except Exception as e:
print(farbig(f"Fehler beim Start: {e}", "red"))
def host_verbinden(entry, creds, default_cred, extra_args):
cred = entry.get("cred", default_cred)
profile = creds.get(cred)
if not profile:
print(farbig(f"Credential '{cred}' fehlt!", "red"))
input("⏎ Weiter...")
return
pw = passwort_holen(cred, profile["domain"], profile["user"])
rdp_starten(entry["host"], profile["domain"], profile["user"], pw, extra_args)
print(farbig(f"Sitzung zu {entry['alias']} gestartet.", "cyan"))
input("⏎ Weiter...")
def menue(section, creds, default_cred, extra_args, path="", offene=set()):
is_root = (path == "")
while True:
config = lade_config()
groups = config.get("groups", {})
credentials = config.get("credentials", {})
default = config.get("default_cred", default_cred)
if is_root:
section = {"groups": groups}
creds = credentials
default_cred = default
os.system("clear")
print(farbig(f"=== RDP-Menü {path} ===\n", "bold"))
groups = section.get("groups", {})
hosts = section.get("hosts", [])
index = {}
i = 1
if is_root:
for name, content in groups.items():
print(f" {i:2}) {farbig(name, content.get('color', 'reset'))} →")
index[str(i)] = ("group", content, f"{path}/{name}")
i += 1
else:
for h in hosts:
alias = h["alias"]
mark = farbig("✅", "green") if alias in offene else " "
print(f" {i:2}) {farbig(alias, h.get('color', 'reset'))} – {h['host']} {mark}")
index[str(i)] = ("host", h)
i += 1
print("\n b) Zurück")
print(" q) Beenden")
sel = input(farbig("Auswahl: ", "bold")).strip()
if sel == "q":
sys.exit("Beende Launcher.")
elif sel == "b":
return
elif sel in index:
typ, eintrag, *rest = index[sel]
if typ == "group":
menue({"hosts": eintrag.get("hosts", [])}, creds, default_cred, extra_args, rest[0], offene)
elif typ == "host":
offene.add(eintrag["alias"])
host_verbinden(eintrag, creds, default_cred, extra_args)
else:
print(farbig("Ungültige Auswahl.", "red"))
input("⏎ Weiter...")
def main():
parser = argparse.ArgumentParser(description="xfreerdp Launcher mit Keyring")
parser.add_argument("freerdp_args", nargs=argparse.REMAINDER, help="zusätzliche xfreerdp3-Parameter")
args = parser.parse_args()
offene = set()
while True:
config = lade_config()
creds = config.get("credentials", {})
default = config.get("default_cred", "")
groups = config.get("groups")
if not groups:
print(farbig("⚠️ Keine Gruppen in config.json.", "yellow"))
input("⏎ Weiter...")
continue
menue({"groups": groups}, creds, default, args.freerdp_args, "", offene)
if __name__ == "__main__":
try:
main()
except KeyboardInterrupt:
print("\n[Abbruch]")
4. Beispiel config.json
Erstelle im selben Ordner eine Datei config.json mit folgendem Inhalt:
▶ Beispiel-Konfiguration anzeigen / ausklappen
{
"default_cred": "user1",
"credentials": {
"user1": { "domain": "FIRMENNETZ", "user": "max.mustermann" },
"user2": { "domain": "INTRANET", "user": "maria.musterfrau" }
},
"groups": {
"Standort_A": {
"color": "bright_blue",
"hosts": [
{ "alias": "Server-A1", "host": "10.0.10.11", "color": "bright_green", "cred": "user1" },
{ "alias": "Server-A2", "host": "10.0.10.12", "color": "bright_magenta","cred": "user2" }
]
},
"Standort_B": {
"color": "bright_yellow",
"hosts": [
{ "alias": "Server-B1", "host": "10.0.20.21", "color": "bright_cyan", "cred": "user1" },
{ "alias": "Server-B2", "host": "10.0.20.22", "color": "bright_red", "cred": "user2" }
]
}
}
}
IP-Adressen, Farben etc. kannst du jederzeit anpassen!
5. Alles ausführen – Zusammengefasst
- Terminal öffnen →
cd ~/rdp-launcher - venv aktivieren →
source .venv/bin/activate - Launcher starten →
./xfreerdp_launcher.py - Durch das Menü klicken: Standort → Server → Passwort
- Passwort wird einmalig abgefragt & im Keyring gespeichert
- Zum Beenden: q eingeben
Ctrl+Alt+T cd ~/rdp-launcher source .venv/bin/activate ./xfreerdp_launcher.pyLinux - SSH
SSH Authentifizierung
Debian SSH: Passwort für normale User, SSH-Key für root
Diese Anleitung zeigt, wie du OpenSSH so konfigurierst, dass sich normale Benutzer mit Passwort anmelden können, während sich root ausschließlich mit SSH-Schlüssel (Zertifikat/Key) anmelden darf.
Voraussetzungen
- Debian/Ubuntu mit
openssh-server - Zugriff als root (oder per
sudo) - Ein funktionierender SSH-Key für root (z. B. Ed25519)
1) SSH-Key für root vorbereiten
- Auf deinem Admin-Client (nicht auf dem Server) einen Key erzeugen (falls noch nicht vorhanden):
ssh-keygen -t ed25519 -a 100 -f ~/.ssh/id_ed25519ssh-keygen -t ed25519 -a 256 -f ~/.ssh/id_ed25519 -C "jj@little-snitch" - Öffentlichen Schlüssel auf den Server in die root-Authorized Keys kopieren:
ssh-copy-id -i ~/.ssh/id_ed25519.pub root@server.example.comAlternativ manuell:
cat ~/.ssh/id_ed25519.pub | ssh root@server.example.com 'mkdir -p /root/.ssh && chmod 700 /root/.ssh && cat >> /root/.ssh/authorized_keys && chmod 600 /root/.ssh/authorized_keys'
2) Bestehende SSH-Konfiguration sichern
cp -a /etc/ssh/sshd_config /etc/ssh/sshd_config.backup.$(date +%F-%H%M%S)
3) Kerneinstellungen
Die zentrale Idee:
PermitRootLogin prohibit-password→ verbietet root-Passwortlogin, erlaubt aber Schlüssel.PasswordAuthentication yes→ Passwortlogin global erlaubt (wird in Match-Blöcken eingeschränkt).Match User root→ für root nur SSH-Key.Match User <username>→ optional: für bestimmte User Verhalten festlegen.
4) Beispiel: vollständige /etc/ssh/sshd_config
Folgende Konfiguration entspricht deinem Beispiel und erzwingt für root Key-Login, lässt für master771 sowohl Passwort als auch Key zu. Andere Benutzer folgen den globalen Einstellungen (Passwort erlaubt, Key erlaubt):
root@mqtt:~# cat /etc/ssh/sshd_config
# This is the sshd server system-wide configuration file. See
# sshd_config(5) for more information.
# This sshd was compiled with PATH=/usr/local/bin:/usr/bin:/bin:/usr/games
# The strategy used for options in the default sshd_config shipped with
# OpenSSH is to specify options with their default value where
# possible, but leave them commented. Uncommented options override the
# default value.
Include /etc/ssh/sshd_config.d/*.conf
#Port 22
#AddressFamily any
#ListenAddress 0.0.0.0
#ListenAddress ::
#HostKey /etc/ssh/ssh_host_rsa_key
#HostKey /etc/ssh/ssh_host_ecdsa_key
#HostKey /etc/ssh/ssh_host_ed25519_key
# Ciphers and keying
#RekeyLimit default none
# Logging
#SyslogFacility AUTH
#LogLevel INFO
# Authentication:
#LoginGraceTime 2m
#PermitRootLogin prohibit-password
PermitRootLogin prohibit-password
#StrictModes yes
#MaxAuthTries 6
#MaxSessions 10
#PubkeyAuthentication yes
PubkeyAuthentication yes
# Expect .ssh/authorized_keys2 to be disregarded by default in future.
#AuthorizedKeysFile .ssh/authorized_keys .ssh/authorized_keys2
#AuthorizedPrincipalsFile none
#AuthorizedKeysCommand none
#AuthorizedKeysCommandUser nobody
# For this to work you will also need host keys in /etc/ssh/ssh_known_hosts
#HostbasedAuthentication no
# Change to yes if you don't trust ~/.ssh/known_hosts for
# HostbasedAuthentication
#IgnoreUserKnownHosts no
# Don't read the user's ~/.rhosts and ~/.shosts files
#IgnoreRhosts yes
# To disable tunneled clear text passwords, change to "no" here!
#PasswordAuthentication yes
PasswordAuthentication yes
#PermitEmptyPasswords no
# Change to "yes" to enable keyboard-interactive authentication. Depending on
# the system's configuration, this may involve passwords, challenge-response,
# one-time passwords or some combination of these and other methods.
# Beware issues with some PAM modules and threads.
KbdInteractiveAuthentication no
# Kerberos options
#KerberosAuthentication no
#KerberosOrLocalPasswd yes
#KerberosTicketCleanup yes
#KerberosGetAFSToken no
# GSSAPI options
#GSSAPIAuthentication no
#GSSAPICleanupCredentials yes
#GSSAPIStrictAcceptorCheck yes
#GSSAPIKeyExchange no
# Set this to 'yes' to enable PAM authentication, account processing,
# and session processing. If this is enabled, PAM authentication will
# be allowed through the KbdInteractiveAuthentication and
# PasswordAuthentication. Depending on your PAM configuration,
# PAM authentication via KbdInteractiveAuthentication may bypass
# the setting of "PermitRootLogin prohibit-password".
# If you just want the PAM account and session checks to run without
# PAM authentication, then enable this but set PasswordAuthentication
# and KbdInteractiveAuthentication to 'no'.
UsePAM yes
#AllowAgentForwarding yes
#AllowTcpForwarding yes
#GatewayPorts no
X11Forwarding yes
#X11DisplayOffset 10
#X11UseLocalhost yes
#PermitTTY yes
PrintMotd no
#PrintLastLog yes
#TCPKeepAlive yes
#PermitUserEnvironment no
#Compression delayed
#ClientAliveInterval 0
#ClientAliveCountMax 3
#UseDNS no
#PidFile /run/sshd.pid
#MaxStartups 10:30:100
#PermitTunnel no
#ChrootDirectory none
#VersionAddendum none
# no default banner path
#Banner none
# Allow client to pass locale and color environment variables
AcceptEnv LANG LC_* COLORTERM NO_COLOR
# override default of no subsystems
Subsystem sftp /usr/lib/openssh/sftp-server
# Example of overriding settings on a per-user basis
#Match User anoncvs
# X11Forwarding no
# AllowTcpForwarding no
# PermitTTY no
# ForceCommand cvs server
Match User root
PasswordAuthentication no
PubkeyAuthentication yes
Match User master771
PasswordAuthentication yes
PubkeyAuthentication yes
5) Syntax prüfen und SSH neu laden
- Syntaxcheck:
sshd -tWenn keine Ausgabe erfolgt, ist die Syntax OK.
- Dienst neu laden (ohne laufende Sessions zu kappen):
systemctl reload sshFalls
reloadnicht verfügbar, dann:systemctl restart ssh
6) Sicher testen (zweite Session!)
- Neue Terminal-Session öffnen, bestehende Sitzung nicht schließen.
- Test root per Key:
ssh -i ~/.ssh/id_ed25519 root@server.example.com - Test root per Passwort (soll scheitern):
ssh -o PreferredAuthentications=password -o PubkeyAuthentication=no root@server.example.com - Test normaler Benutzer per Passwort (soll funktionieren):
ssh -o PreferredAuthentications=password -o PubkeyAuthentication=no master771@server.example.com
Optionen & Varianten
- Nur Passwort für bestimmte Benutzer erzwingen:
Match User alice,bob PasswordAuthentication yes PubkeyAuthentication no - Key-Login global erlauben, aber root-Passwort strikt verbieten: Bereits abgedeckt durch
PermitRootLogin prohibit-passwordund denMatch User root-Block. - Brute-Force eindämmen:
fail2banverwenden undMaxAuthTriessenken (z. B.MaxAuthTries 3).
Rollback
Falls etwas schiefgeht, via Konsole (z. B. VM-Konsole) die Sicherung zurückspielen:
mv /etc/ssh/sshd_config.backup.YYYY-MM-DD-HHMMSS /etc/ssh/sshd_config
systemctl restart ssh
Hinweise zur Sicherheit
- Lege für alle Benutzer starke Passwörter fest oder nutze ggf. 2FA (z. B.
google-authenticator) zusätzlich. - Bevorzuge Ed25519-Schlüssel. RSA nur mit ausreichend großer Länge (min. 3072 Bit).
- Überlege, den SSH-Port zu ändern und/oder Port-Knocking bzw. VPN vorzuschalten.
- Halte
openssh-serveraktuell (apt update && apt upgrade).
Stand: aktualisiere diese Seite, wenn sich deine Policy ändert oder neue Benutzer hinzukommen.
SSH - only key
Ziel: Auf dem Client ein Ed25519-Schlüsselpaar mit Passphrase erzeugen und in ~/.ssh/config hinterlegen. Auf dem Server Logins für root und jj auf Public-Key-Authentifizierung beschränken.
Platzhalter
SERVER_IP: IP oder FQDN des Zielservers$Dieser_Client: Kommentar (z. B. Hostname des Clients)little-ghost: frei wählbarer Schlüsselnamens-Ordner
1) Client: SSH-Key mit Passphrase erzeugen
Befehl (kopierbar)
ssh-keygen \
-t ed25519 \
-a 1024 \
-o \
-Z aes256-ctr \
-C "$Dieser_Client" \
-f "/root/.ssh/$org/$device_name/id_ed25519"
Beispielausgabe
Generating public/private ed25519 key pair.
Enter passphrase for "/root/.ssh/JSc/little-ghost/id_ed25519" (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /root/.ssh/JSc/little-ghost/id_ed25519
Your public key has been saved in /root/.ssh/JSc/little-ghost/id_ed25519.pub
The key fingerprint is:
SHA256:**************************** little-ghost
The key's randomart image is:
+--[ED25519 256]--+
|*****************|
|*****************|
|*****************|
|*****************|
|*****************|
|*****************|
|*****************|
|*****************|
|*****************|
+----[SHA256]-----+
Optional: Rechte setzen
chmod 700 /root/.ssh /root/.ssh/JSc /root/.ssh/JSc/little-ghost
chmod 600 /root/.ssh/JSc/little-ghost/id_ed25519
chmod 644 /root/.ssh/JSc/little-ghost/id_ed25519.pub
Beispielausgabe
# (keine Ausgabe bei Erfolg)
# Kontrolle:
ls -ld /root/.ssh /root/.ssh/JSc /root/.ssh/JSc/little-ghost
ls -l /root/.ssh/JSc/little-ghost/
2) Client: SSH-Konfiguration für Zielhost
In /root/.ssh/config eintragen/ergänzen:
Dateiinhalt (kopierbar)
Host SERVER_IP
HostName SERVER_IP
IdentitiesOnly yes
IdentityFile /root/.ssh/JSc/little-ghost/id_ed25519
ForwardAgent no
ForwardX11 no
StrictHostKeyChecking ask
UserKnownHostsFile /root/.ssh/known_hosts
Beispielausgabe
# Kontrolle:
cat /root/.ssh/config
3) Client: Public Key anzeigen/kopieren
Befehl (kopierbar)
cat /root/.ssh/JSc/little-ghost/id_ed25519.pub
Beispielausgabe
ssh-ed25519 AAAAAAAAAABBBBBBBBBB/CCCCCCCCCC little-ghost
Diesen Einzeiler auf dem Server in die Datei ~<user>/.ssh/authorized_keys einfügen (eine Zeile pro Key, keine Umbrüche).
4) Server: root nur per Public Key
Datei /etc/ssh/sshd_config.d/10-root-only-key.conf anlegen/ändern.
Dateiinhalt (kopierbar)
# Root: nur noch Public-Key, keine Passwörter/Keyboard-Interactive
Match User root
PubkeyAuthentication yes
PasswordAuthentication no
KbdInteractiveAuthentication no
AuthenticationMethods publickey
PermitRootLogin prohibit-password
Beispielausgabe
# Kontrolle:
cat /etc/ssh/sshd_config.d/10-root-only-key.conf
5) Server: jj nur per Public Key
Datei /etc/ssh/sshd_config.d/20-jj-only-key.conf anlegen/ändern.
Dateiinhalt (kopierbar)
# jj: nur noch Public-Key, keine Passwort-/Keyboard-Interactive-Logins
Match User jj
PubkeyAuthentication yes
PasswordAuthentication no
KbdInteractiveAuthentication no
AuthenticationMethods publickey
Beispielausgabe
# Kontrolle:
cat /etc/ssh/sshd_config.d/20-jj-only-key.conf
6) Server: Syntax prüfen & Dienst neu laden
Befehl (kopierbar)
sshd -t
sleep 30
systemctl reload ssh # Debian-Standarddienstname
Beispielausgabe
# Bei korrekter Konfiguration keine Ausgabe.
# Fehler würden hier mit Zeile/Datei gemeldet werden.
7) Client: Login zum Server testen
Befehl (kopierbar)
ssh SERVER_IP
Beispielausgabe
The authenticity of host 'SERVER_IP (SERVER_IP)' can't be established.
ED25519 key fingerprint is SHA256:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added 'SERVER_IP' (ED25519) to the list of known hosts.
Enter passphrase for key '/root/.ssh/JSc/little-ghost/id_ed25519':
Last login: Wed Sep 24 12:34:56 2025 from 203.0.113.42
root@server:~#
Hinweise
- Dateirechte: Verzeichnisse
700, Private Key600, Public Key644. - Known Hosts: Datei heißt
known_hosts(nichtknown_hos). - Debug bei Problemen:
ssh -v SERVER_IPzeigt, welchen Key der Client nutzt.
Stand: 25.09.2025
SSHFS - Storage
🔐 SSHFS-Mount Anleitung für Linux + Nextcloud
Beispiele nutzen Fantasie-Namen und RFC-5737-Dummy-IP (192.0.2.0/24):
Client: orion-client • Server: atlas-storage • Server-IP: 192.0.2.55
Zielpfad auf dem Server: /srv/projects/ai/labs/local-sdxl-cpu
0. Voraussetzungen (Server)
# Gruppe für SSHFS-Nutzer anlegen (falls noch nicht vorhanden)
groupadd sshfsusers
# Verzeichnis für hinterlegte Public Keys anlegen und absichern
mkdir -p /etc/sshfs_keys
chown root:root /etc/sshfs_keys
chmod 0755 /etc/sshfs_keys
1. SSH-Schlüssel erstellen (Client)
# moderner Schlüssel (ed25519)
ssh-keygen -t ed25519 -a 2048 -o -Z aes256-ctr -f ~/.ssh/orion_to_atlas -C "sshfs orion-client → atlas-storage"
2. Öffentlichen Schlüssel auf den Server übertragen
scp ~/.ssh/orion_to_atlas.pub root@192.0.2.55:/etc/sshfs_keys/sshfs_orion.pub
# auf dem Server:
chown root:root /etc/sshfs_keys/sshfs_orion.pub
chmod 0644 /etc/sshfs_keys/sshfs_orion.pub
3. SSHFS-Benutzer auf dem Server anlegen
# Benutzer ohne Home (kein Risiko durch dotfiles), in Gruppe sshfsusers
useradd -M -g sshfsusers -s /usr/sbin/nologin sshfs_orion
# Ziel-Verzeichnisstruktur (nur Beispielpfad)
mkdir -p /srv/projects/ai/labs/local-sdxl-cpu
# Eigentümer/Gruppe setzen, setgid auf dem Zielordner
chown -R root:sshfsusers /srv/projects
chmod 2750 /srv/projects/ai/labs/local-sdxl-cpu
Wichtig (Traversal nur für die Gruppe): Damit der Benutzer sshfs_orion den Zielordner erreicht, müssen alle Elternordner das x-Recht für die Gruppe haben, ohne Leserechte (kein Listing). Das hält den Pfad geschlossen und erlaubt nur Durchgang.
# Elternordner: Gruppe setzen + nur Durchgang (710)
chgrp sshfsusers /srv
chmod 710 /srv
chgrp sshfsusers /srv/projects
chmod 710 /srv/projects
chgrp sshfsusers /srv/projects/ai
chmod 710 /srv/projects/ai
chgrp sshfsusers /srv/projects/ai/labs
chmod 710 /srv/projects/ai/labs
# Zielordner: nur Besitzer+Gruppe, setgid damit neue Dateien in der Gruppe bleiben
chgrp sshfsusers /srv/projects/ai/labs/local-sdxl-cpu
chmod 2770 /srv/projects/ai/labs/local-sdxl-cpu
4. SSH-Konfiguration auf dem Server
Datei /etc/ssh/sshd_config bearbeiten und am Ende hinzufügen:
Match User sshfs_orion
AuthorizedKeysFile /etc/sshfs_keys/%u.pub
PubkeyAuthentication yes
KbdInteractiveAuthentication no
PasswordAuthentication no
AllowTcpForwarding no
X11Forwarding no
PermitTTY no
PermitTunnel no
ForceCommand internal-sftp
# Syntax prüfen und Dienst neu laden
sshd -t
systemctl reload ssh
5. FUSE erlauben (Client & ggf. Server)
Datei /etc/fuse.conf öffnen und sicherstellen, dass die Zeile ohne Kommentar vorhanden ist:
user_allow_other
6. Bequemer Host-Alias auf dem Client (empfohlen)
Datei ~/.ssh/config (Client) ergänzen:
Host atlas
HostName 192.0.2.55
User sshfs_orion
IdentityFile ~/.ssh/orion_to_atlas
IdentitiesOnly yes
ServerAliveInterval 15
ServerAliveCountMax 3
StrictHostKeyChecking yes
7. SSHFS-Mount auf dem Client
# lokaler Mountpunkt
mkdir -p /mnt/atlas_labs
# Mount (streng: others=0 → umask=007)
sshfs -o IdentityFile=~/.ssh/orion_to_atlas \
-o reconnect \
-o ServerAliveInterval=15 \
-o ServerAliveCountMax=3 \
-o allow_other \
-o default_permissions \
-o uid=1000 \
-o gid=1000 \
-o umask=007 \
-o idmap=user \
atlas:/srv/projects/ai/labs/local-sdxl-cpu /mnt/atlas_labs
Hinweise:
umask=007ergibt effektiv 770/660 auf dem Mount (keine Rechte für others). (umask=002würde 775/664 zulassen.)default_permissionssorgt dafür, dass Kernel-Rechte lokal erzwungen werden.
8. Optional: Dauerbetrieb per /etc/fstab (Client)
sshfs#sshfs_orion@192.0.2.55:/srv/projects/ai/labs/local-sdxl-cpu /mnt/atlas_labs fuse.sshfs \
IdentityFile=/root/.ssh/orion_to_atlas,allow_other,default_permissions,uid=1000,gid=1000,umask=007, \
reconnect,ServerAliveInterval=15,ServerAliveCountMax=3,idmap=user,_netdev 0 0
🎁 Bonus: Nutzung mit Nextcloud
Mount für www-data (uid/gid 33):
mkdir -p /mnt/nextcloud_data
sshfs -o IdentityFile=/root/.ssh/nextcloud_key \
-o reconnect -o ServerAliveInterval=15 -o ServerAliveCountMax=3 \
-o allow_other -o default_permissions \
-o uid=33 -o gid=33 -o umask=007 -o idmap=user \
nextcloud_svc@192.0.2.55:/srv/nextcloud/export /mnt/nextcloud_data
- In Nextcloud: Admin → Externer Speicher → Pfad
/mnt/nextcloud_dataeinbinden.
9. Troubleshooting (kurz & sicher)
- Passwort-Prompt statt Key: Rechte prüfen:
/etc/sshfs_keys= 0755, Dateien = 0644, Owner = root:root. Dannsshd -T -C user=sshfs_orionauf dem Server und aufauthorizedkeysfileachten. - Zugriff verweigert trotz korrektem Key: Elternordner-Traversal mit
namei -l /srv/projects/ai/labs/local-sdxl-cpuprüfen. Jeder Ordner brauchtg+xbei Gruppesshfsusers. - Host verwechselt: Host-Alias in
~/.ssh/confignutzen, nicht rohe IPs tippen.
Linux - Mounts (SMB, SSH....)
SSHFS mount hängt
Wenn der Befehl df -h hängt oder ein Mount nicht mehr reagiert, kannst du folgende Schritte testen.
1. Prüfen, welche sshfs-Verbindungen aktiv sind
ps aux | grep sshfs
Bei mir wurde dabei deutlich, dass noch mehrere sshfs-Prozesse aktiv waren – einer davon schon sehr lange:
root 3026932 1.5 0.0 1708128 12612 ? Ssl Jul31 298:43 sshfs -o IdentityFile=...
2. Hängenden sshfs-Prozess beenden
Den betroffenen Prozess mit seiner PID (hier 3026932) beenden:
sudo kill -9 3026932
3. Ergebnis
Nach dem Beenden des Prozesses war mein df -h-Problem sofort gelöst.
4. Ursache
Das Problem lag daran, dass df -h auch Informationen zu FUSE-Dateisystemen wie sshfs abfragt. Wenn eine solche Verbindung hängt oder der sshfs-Daemon nicht mehr antwortet, bleibt der df-Prozess im sogenannten D-State (uninterruptible sleep) stecken und kann nicht normal beendet werden. Das Beenden des zugehörigen sshfs-Prozesses löst die blockierte Anfrage im Kernel, sodass df -h wieder funktioniert.
Linux - Komprimierung
TAR
📦 Linux: Tar-Archive erstellen, komprimieren und entpacken
Mit dem tar-Befehl kannst du unter Linux einfach komplette Ordner archivieren und optional komprimieren. Hier ist eine vollständige, übersichtliche Anleitung mit allen wichtigen Optionen und Beispielen.
1️⃣ Einfaches Tar-Archiv erstellen
tar -cvf archivname.tar /pfad/zum/ordner
-c→ Neues Archiv erstellen-v→ Ausgabe der Dateien im Terminal (verbose)-f→ Dateiname für das Archiv
Beispiel:
tar -cvf meinArchiv.tar meinOrdner/
2️⃣ Archiv mit Kompression erstellen
a) Mit gzip (.tar.gz / .tgz)
tar -czvf meinArchiv.tar.gz meinOrdner/
-z → gzip-Kompression
b) Mit bzip2 (.tar.bz2)
tar -cjvf meinArchiv.tar.bz2 meinOrdner/
-j → bzip2-Kompression
c) Mit xz (.tar.xz)
tar -cJvf meinArchiv.tar.xz meinOrdner/
-J → xz-Kompression (stärkste Kompression, aber langsamer)
3️⃣ Nützliche Optionen
a) Verzeichniswechsel mit -C
tar -czvf meinArchiv.tar.gz -C /pfad/zum meinOrdner/
→ Nimmt nur meinOrdner, nicht den gesamten Pfad ins Archiv auf
b) Dateien oder Verzeichnisse ausschließen
tar -czvf meinArchiv.tar.gz --exclude='*.log' meinOrdner/
→ Schließt alle .log-Dateien vom Archiv aus
c) Archivgröße vor und nach Kompression prüfen
du -sh meinArchiv.tar.gz
4️⃣ Inhalt eines Archivs anzeigen (ohne entpacken)
a) Unkomprimiertes Archiv:
tar -tvf meinArchiv.tar
b) Komprimiertes Archiv (gzip):
tar -tzvf meinArchiv.tar.gz
5️⃣ Archiv entpacken
a) Unkomprimiertes Archiv:
tar -xvf meinArchiv.tar
b) Mit gzip:
tar -xzvf meinArchiv.tar.gz
c) Mit bzip2:
tar -xjvf meinArchiv.tar.bz2
d) Mit xz:
tar -xJvf meinArchiv.tar.xz
6️⃣ Komplettes Beispiel
Archivieren und komprimieren:
tar -czvf projekt.tar.gz projekt/
Wiederherstellen / Entpacken:
tar -xzvf projekt.tar.gz
💡 Tipps
- Nutze
--exclude, um große, unnötige Dateien auszusparen - Verwende
absolute Pfadenur mit-C, damit dein Archiv sauber bleibt - Du kannst mehrere Ordner/Dateien auf einmal archivieren:
tar -czvf backup.tar.gz /etc /var/log /home/user1
🧪 Test-Modus: Was würde tar tun?
tar -cvf meinArchiv.tar --dry-run meinOrdner/
Simuliert die Archiv-Erstellung, ohne eine Datei zu schreiben (nur mit --dry-run in Kombination mit GNU tar)
📚 Weiterführende Hilfe
man tar
Oder online: https://man7.org/linux/man-pages/man1/tar.1.html
Linux - GPG
GPG - Yubikey "not found"
YubiKey wird von GPG nicht erkannt – Lösung mit pcscd Neustart
Wenn der YubiKey bereits eingesteckt ist, aber gpg oder gpg2 ihn nicht erkennt (z. B. mit dem Fehler gpg: selecting card failed: No such device), liegt das häufig an einem Problem mit dem Smartcard-Dienst pcscd.
Fehlermeldung
gpg: selecting card failed: No such device
gpg: OpenPGP card not available: No such device
Lösung: pcscd Dienst neu starten
- Öffne ein Terminal mit Root-Rechten oder verwende
sudo. - Führe den folgenden Befehl aus, um den Dienst neu zu starten:
sudo systemctl restart pcscd
Alternativ bei älteren Systemen:
sudo service pcscd restart
- Danach kannst du
gpg2 --card-editerneut ausführen:
gpg2 --card-edit
Nun sollte der YubiKey korrekt erkannt werden und Informationen wie Seriennummer, Hersteller und Kartentyp anzeigen.
Hinweis
- Wenn du den YubiKey erst nach dem Systemstart einsteckst, kann es ebenfalls nötig sein,
pcscdneu zu starten. - Um dies in Zukunft zu vermeiden, kannst du die automatische Aktivierung mit folgendem Befehl ermöglichen:
sudo systemctl enable pcscd.socket
Dies stellt sicher, dass der Dienst automatisch gestartet wird, sobald ein Smartcard-Gerät verwendet wird.
GPG Keys exportieren
GPG - Sicheren Schlüssel erstellen und Ordner verschlüsseln
GPG maximal hart: Schlüssel erstellen & kompletten Ordner sicher verschlüsseln (mit Erklärungen)
0) Vorbereiten & Umgebung schützen – warum überhaupt?
Eine aktuelle GnuPG-Version bringt neue Sicherheitsfeatures (z. B. AEAD/OCB). GPG_TTY sorgt für saubere Passphrase-Prompts. umask 077 und strikte Rechte verhindern, dass Konfigs/Backups aus Versehen für andere lesbar sind.
# Version prüfen (2.4+ ideal):
gpg --version
# Terminal-Integration:
export GPG_TTY=$(tty)
# Verzeichnis und Rechte:
umask 077
mkdir -p ~/.gnupg && chmod 700 ~/.gnupg
1) Sehr starken OpenPGP-Schlüssel anlegen
ECC/Curve25519 liefert heute eine hervorragende Kombination aus Sicherheit, Geschwindigkeit und Kompatibilität: du erhältst einen Ed25519-Signierschlüssel plus X25519-(cv25519)-Verschlüsselungs-Subkey. Das ist „state of the art“ für die meisten Anwendungsfälle.
gpg --expert --full-generate-key
# Im Dialog:
# Typ: (9) ECC und ECC → Kurve: Curve25519
# Ablaufdatum: z.B. 2y (verlängerbar)
# Name/E-Mail setzen
# sehr starke Passphrase vergeben
1.1) Fingerprint & Notfall: Widerrufszertifikat
Der Fingerprint identifiziert deinen Schlüssel zweifelsfrei. Ein Widerrufszertifikat ist deine „Notbremse“, falls der private Schlüssel verloren/kompromittiert ist.
gpg --list-keys
gpg --fingerprint "Dein Name"
gpg --output revoke.asc --gen-revoke "Dein Name"
3) Einen kompletten Ordner verschlüsseln – Dateinamen & Struktur verbergen
Ein simples „alle Dateien einzeln verschlüsseln“ leakt Dateinamen und Ordnerstruktur. Besser: zuerst deterministisch zu tar bündeln (glättet Metadaten), dann gpg drüber. Ergebnis: .tar.gpg – sauber, dicht, auditierbar.
3.0) Pipeline: tar → gpg (maximale Härte)
# Variablen
ORDNER="mein_geheimer_ordner"
EMPFAENGER="Dein Name <you@example.com>" # oder: 40-stelliger Fingerprint
OUT="mein_geheimer_ordner.tar.gpg"
# Deterministisch packen & sofort verschlüsseln (mit AEAD/OCB):
tar --sort=name \
--mtime='UTC 1970-01-01' \
--owner=0 --group=0 --numeric-owner \
-C "$(dirname "$ORDNER")" -cf - "$(basename "$ORDNER")" \
| gpg --encrypt \
--recipient "$EMPFAENGER" \
--cipher-algo AES256 \
--force-ocb \
--output "$OUT"
# Kompatibilitätsmodus (ohne OCB):
# ... | gpg --encrypt --recipient "$EMPFAENGER" --cipher-algo AES256 -o "$OUT"
3.1) Alternative „aus einem Guss“: gpgtar
gpgtar kapselt Archivieren + Verschlüsseln in einem Tool – komfortabel und sicher, Dateinamen bleiben verborgen.
# Erstellen:
gpgtar --encrypt --recipient "$EMPFAENGER" --output geheim.gpg "$ORDNER"
# Entpacken:
gpgtar --decrypt --output entpackt geheim.gpg
3.2) Erfolg prüfen (ohne zu entschlüsseln)
Zur Kontrolle, welche Paket-/Algo-Infos tatsächlich drinstecken (nützlich für Audits):
gpg --list-packets "$OUT" | sed -n '1,40p'
3.3) Originaldaten entfernen – HDD vs. SSD
Auf klassischen HDDs kann shred sinnvoll sein. Auf SSDs/Copy-on-Write-FS (btrfs, zfs) sind Überschriften nicht zuverlässig – setze dort lieber auf Voll-Disk-Verschlüsselung (LUKS) und sichere Löschprozesse auf Geräteebene.
shred -vzun 3 -r -- "$ORDNER" # ACHTUNG: für SSDs ungeeignet!
blkdiscard je nach Hardware/Setup.4) Entschlüsseln & auspacken – bewusst zweistufig
Erst entschlüsseln (fragt nach Passphrase/Token), dann das Tar entpacken – so bleibt der Ablauf transparent und nachvollziehbar.
gpg --output ordner.tar --decrypt mein_geheimer_ordner.tar.gpg
tar -xf ordner.tar
5) Schlüssel sichern & Vertrauen setzen – was braucht’s wirklich?
Teile deinen öffentlichen Schlüssel, sichere den privaten offline, und setze die Vertrauensstufe bewusst, damit dein System Signaturen korrekt bewertet.
# Public Key exportieren:
gpg --armor --export "$EMPFAENGER" > publickey.asc
# Private Keys sichern (offline aufbewahren!):
gpg --armor --export-secret-keys "$EMPFAENGER" > privatekey-backup.asc
# Vertrauen setzen (optional):
gpg --edit-key "$EMPFAENGER"
gpg> trust # 5 = ultimate
gpg> save
6) Zusätzliche Härtung – wann lohnt sich der Extra-Aufwand?
- Hardware-Token (YubiKey/Smartcard): Private Keys aufs Token verschieben – Schlüsselmaterial verlässt den Rechner nie. Ideal, wenn Geräte geteilt werden oder du „Defense in Depth“ willst.
- Primärschlüssel offline, Subkeys produktiv: Primärschlüssel nur als „Root of Trust“ offline lagern, mit Subkeys signieren/verschlüsseln – einfachere Rotation.
- Passphrase-Qualität: 6–8+ Diceware-Wörter oder 20–30+ zufällige Zeichen aus Passwort-Manager; regelmäßig rotieren.
- Key-Präferenzen am Key selbst setzen & verteilen: Damit Sender automatisch starke Verfahren wählen (siehe
gpg --edit-key → setpref).
7) Troubleshooting (kurz & praxisnah)
- OCB wird nicht verwendet? Prüfe
gpg --version(2.4+) und ob du--force-ocbgesetzt hast; bei Fremd-Stacks bleibt OCB evtl. unverständlich – dann ohne OCB arbeiten. - Entschlüsseln ist langsam mit „hidden recipients“? Das ist normal: alle eigenen Keys werden probiert. Für Backups ok, für E-Mail eher abwägen.
- Tar meckert über Zeiten/Owner? Stelle sicher, dass du GNU tar nutzt und die Optionen wie oben gesetzt sind.
8) Schnellreferenz
# Schlüssel (Curve25519):
gpg --expert --full-generate-key
# Ordner → deterministisches Tar → GPG (mit OCB):
tar --sort=name --mtime='UTC 1970-01-01' --owner=0 --group=0 --numeric-owner \
-C "$(dirname "$ORDNER")" -cf - "$(basename "$ORDNER")" \
| gpg --encrypt --recipient "$EMPFAENGER" --cipher-algo AES256 --force-ocb -o "$OUT"
# Entschlüsseln:
gpg -o ordner.tar -d "$OUT" && tar -xf ordner.tar
# gpgtar-Variante:
gpgtar --encrypt -r "$EMPFAENGER" -o geheim.gpg "$ORDNER"
gpgtar --decrypt -o entpackt geheim.gpg
Kompatibilitätsnotiz: Für alte Gegenstellen ohne --force-ocb arbeiten. Für lokale Backups und moderne GnuPG-Umgebungen OCB beibehalten.Linux - Server erstellen
Software installieren
Debian:
Hilfreiche Software installieren:
apt update \
&& \
apt install -y \
openssh-server \
nano \
curl \
htop \
btop \
iputils-ping \
iproute2 \
iptables \
ipset \
ethstatus \
vnstat \
sshfs \
wget \
cifs-utils \
python3 \
python3-venv \
python3-pip \
tmux \
tree \
rsync \
tcpdump \
isc-dhcp-client \
gpg \
ntfs-3g \
util-linux \
parted \
fuse \
dosfstools \
tmux für crontab vorbereiten und auto update vorbereiten:
echo 'set-option -g default-shell /bin/bash' >> ~/.tmux.conf
mkdir manual
echo -e 'apt-get update\napt-get full-upgrade -y\n/sbin/reboot now' >> manual/update_and_reboot.sh
echo -e 'apt-get update\napt-get full-upgrade -y' >> manual/just_update.sh
mini Skript für neu installierte Debian Systeme:
# 1) /etc/apt/sources.list komplett ersetzen
cat > /etc/apt/sources.list <<'EOF'
deb http://deb.debian.org/debian/ trixie main contrib non-free-firmware non-free
deb http://security.debian.org/debian-security trixie-security main contrib non-free-firmware non-free
deb http://deb.debian.org/debian/ trixie-updates main contrib non-free-firmware non-free
deb http://deb.debian.org/debian trixie-backports main contrib non-free-firmware non-free
EOF
# 2) /etc/resolv.conf komplett ersetzen
cat > /etc/resolv.conf <<'EOF'
nameserver 1.1.1.1
EOF
chattr +i /etc/resolv.conf
apt-get update
apt-get install tmux -y
# 3) tmux Sessions tm0 bis tm12 erstellen (falls nicht vorhanden)
for i in $(seq 0 12); do
if ! tmux has-session -t "tm${i}" 2>/dev/null; then
tmux new-session -d -s "tm${i}"
fi
done
tmux send-keys -t tm0 "cd /root/" C-m
tmux send-keys -t tm0 "apt update \
&& \
apt install -y \
openssh-server \
nano \
curl \
htop \
btop \
iputils-ping \
iproute2 \
iptables \
ipset \
ethstatus \
vnstat \
sshfs \
wget \
cifs-utils \
python3 \
python3-venv \
python3-pip \
tmux \
tree \
rsync \
tcpdump \
isc-dhcp-client \
gpg \
ntfs-3g \
util-linux \
parted \
fuse \
dosfstools" C-m
Linux - Nützliche Software
Audio
Amberol
Amberol finde ich sehr cool, da er deine Playlist auch nach dem schließen noch kennt
https://apps.gnome.org/de/Amberol/
apt-get install amberol -y
VLC
Klassiker, is immer gut den zu haben
apt-get install vlc -y
Programmierung / Entwicklung
Atom
Sehr sehr alt, wurde damals von Microsoft's Visual Studio Code abgelöst und wird heute nicht mehr weiter geupdatet, aber ich liebe Atom, da mir Visual Studio Code viel zu überladen is und ich noch nicht super in VIM bin.
Arduino IDE
Das is nur was für Leute die mit Mikrocontrollern arbeiten, ansonsten bringt es einen wenig.
Ich bevorzuge die alte Legacy IDE, welche auf der Download Seite etwas tiefer zu finden is, da man dort den seriellen Monitor noch in einem separaten Fenster hat.
https://docs.arduino.cc/software/ide-v1/tutorials/Linux/
Linux - Festplatten
NetApp-Shelf - 520-Byte Sektoren
Diese Anleitung erklärt warum 520-Byte-Sektoren existieren, wie man betroffene Platten identifiziert und welche Wege es gibt, sie nutzbar zu machen (oder bewusst auszublenden), ohne produktive Datenträger anzutasten.
Inhalt
- Warum haben manche NetApp-Platten 520 B/Sektor?
- Typische Symptome & Kernel-Logs
- Voraussetzungen & Pakete
- Betroffene Platten sicher finden (ohne Risiko für Daten)
- Entscheidung: Reformatieren, Übersetzen oder Ausblenden
- Reformatieren auf 512 B/4 Kn (falls erlaubt)
- Fortschritt & Status überwachen
- Nachbereitung: Rescan, Multipath, Partition/FS
- Wenn Reformatierung verweigert wird (Vendor-Lock)
- Optional: Multipath-Spam vermeiden (Blacklist)
- Troubleshooting-Tabelle
- Anhang: hilfreiche One-Liner/Skripte
1) Warum haben manche NetApp-Platten 520 Byte pro Sektor?
- 520 B = 512 B Nutzdaten + 8 B T10 PI/DIF (Protection Information).
- DIF/PI fügt pro Block Tags/Checksummen hinzu (u. a. LBA-Tag), womit End-to-End-Integrität von Host → Controller → Medium geprüft wird.
- Vorteile: bessere Fehlererkennung, Schutz gegen „silent corruption“, wichtig in Enterprise-Storage (z. B. ONTAP).
- Nachteil unter Standard-Linux: Der Kernel erwartet 512n/4Kn. 520 B werden als „unsupported“ abgelehnt.
Merke: 4160 B physische Blockgröße in Logs = 8 × 520 B.
2) Typische Symptome & Kernel-Logs
Unsupported sector size 520Preferred minimum I/O size 4096 bytes not a multiple of physical block size (4160 bytes)- Multipath:
failed to setup map ... uevent trigger error - Geräte erscheinen mehrfach (mehrere SAS-Pfade), z. B.
/dev/sdcx,/dev/sdcy,/dev/sg108,/dev/sg109– sind aber derselbe physische Datenträger.
3) Voraussetzungen & Pakete
# Debian/Ubuntu
apt-get update
apt-get install -y sg3-utils lsscsi multipath-tools smartmontools
# RHEL/CentOS/Rocky/Alma
yum install -y sg3_utils lsscsi device-mapper-multipath smartmontools
sg_format) zerstört alle Daten auf der betroffenen Platte. Diese Anleitung zeigt, wie du nur die neuen/unerwünschten 520 B-Platten anfasst und produktive Disks sicher ignorierst.4) Betroffene Platten sicher finden (ohne Risiko)
4.1 Geräte & Pfade auflisten
lsscsi -g | grep -E "NETAPP|HGST|Seagate|TOSHIBA" # Beispielhaft; Hersteller ggf. anpassen
# Ausgabe zeigt je Zeile: ... /dev/sdX /dev/sgY
4.2 Prüfen, ob 520 B gemeldet werden
Die sg*-Geräte (SCSI generic) für Detailabfragen verwenden:
sg_readcap -l /dev/sg108
# Wichtige Zeilen:
# Logical block length=520 bytes
# Logical blocks per physical block exponent=3 [phys = 4160 bytes]
# Device size: ... 5.99 TB
4.3 Sicherstellen, dass es derselbe physische Datenträger ist (Multipath)
Bei mehreren Pfaden hat jedes einen eigenen /dev/sg*. Die LU name (LUN-WWN) ist identisch:
sg_inq -i /dev/sg108 | grep -E "Unit serial number|LU name"
sg_inq -i /dev/sg109 | grep -E "Unit serial number|LU name"
# Sind LU name und/oder Unit serial identisch → gleicher Datenträger über zwei Pfade.
/dev/sg108) zum selben Laufwerk verwenden!5) Entscheidung: Reformatieren, Übersetzen oder Ausblenden
| Weg | Wann? | Pro | Contra |
|---|---|---|---|
| Reformatieren auf 512 B/4096 B | Nur bei neuen/leerem Laufwerk, wenn Firmware es erlaubt | Standard-Linux nutzbar, keine Spezial-HW | Vernichtet Daten; 2–4 h/6 TB (oft), manche NetApp-OEMs verbieten es |
| On-the-fly Übersetzung (HBA/RAID mit DIF-Translation) | Wenn Reformat blockiert ist, aber Controller PI/DIF-Translation beherrscht | OS sieht 512 B, Laufwerk bleibt 520 B | Abhängig von Hardware-Modell/Firmware; nicht jeder HBA kann das |
| Ausblenden/Blacklisten | Wenn Platte nicht benötigt/kompatibel ist | Ruhe im syslog/multipath | Platte bleibt ungenutzt |
6) Reformatieren auf 512 B/4 Kn (falls erlaubt)
LU name und Unit serial number. Niemals produktive Disks anfassen.6.1 Multipath kurz pausieren (verhindert Verwirrung)
systemctl stop multipathd
multipath -F # alle Maps flushen
6.2 Probe-Format (Dry-Run)
Testet nur, ob die Firmware 512/4096 akzeptiert – es passiert noch nichts:
# 512-Byte testen
sg_format --format --size=512 --six --fmtpinfo=0 --dry-run /dev/sg108
# 4Kn (4096) als Alternative testen
sg_format --format --size=4096 --six --fmtpinfo=0 --dry-run /dev/sg108
# Typische Fehler bei Vendor-Lock:
# "INVALID FIELD IN CDB" oder "Device not ready" → Reformat nicht erlaubt.
6.3 Schnellstmögliches Format anstoßen
Wenn der Dry-Run OK ist, starte das Format. Manche Firmwares unterstützen „fast“/„complete list“ – andere ignorieren es.
# Schnellvariante versuchen (falls Firmware unterstützt):
sg_format --format --size=512 --six --fmtpinfo=0 --cmplst=1 --early /dev/sg108
# Fällt Firmware auf Full-Format zurück, dauert es entsprechend (2–4h/6TB).
# Alternative "fast format":
sg_format --format --size=512 --six --fmtpinfo=0 --ffmt=1 --early /dev/sg108
Hinweis: --early kehrt sofort zurück, das Laufwerk formatiert im Hintergrund weiter. Auf Systemen ohne --early beende das Userspace-Tool notfalls mit Ctrl+C; der Vorgang im Laufwerk läuft weiter.
7) Fortschritt & Status überwachen
# Regelmäßig Sense-Daten abfragen (zeigt Fortschritt, wenn verfügbar)
sg_requests /dev/sg108
# Beispielausgabe:
# Sense key: Not Ready
# Additional sense: Logical unit not ready, format in progress
# Progress indication: 37.50%
# Alternativ (je nach Build):
sg_turs /dev/sg108 # "Unit ready" wenn fertig; manche Builds können nicht anzeigen
# Live-Monitoring:
watch -n 60 sg_requests /dev/sg108
FORMAT UNIT lässt sich nicht sauber abbrechen. Stromlos/Slot ziehen ist riskant und endet oft damit, dass du erneut formatieren musst.8) Nachbereitung: Rescan, Multipath, Partition & Filesystem
# Nach Abschluss erneut einlesen
rescan-scsi-bus.sh -a # ggf. aus 'sg3-utils' Zusatzpaket
# prüfen:
sg_readcap -l /dev/sg108
# Erwartet: "Logical block length=512 bytes" (oder 4096)
# Blockgeräte-Ansicht
lsblk -o NAME,HCTL,WWN,MODEL,LOG-SEC,PHY-SEC,SIZE
# Multipath wieder starten
systemctl start multipathd
multipath -ll
# (Optional) Partition & Filesystem
# GPT anlegen und 1 große Partition:
parted -s /dev/sdX mklabel gpt mkpart primary 1MiB 100%
# z. B. XFS:
mkfs.xfs -f /dev/sdX1
# oder ext4:
mkfs.ext4 -F -L data01 /dev/sdX1
# Mountpunkt
mkdir -p /mnt/data01
echo '/dev/sdX1 /mnt/data01 xfs defaults,noatime 0 2' >> /etc/fstab
mount -a
9) Wenn Reformatierung verweigert wird (Vendor-Lock)
- Erkennung:
sg_format --dry-runoder direktessg_formatmeldet INVALID FIELD IN CDB / Device not ready (bei MODE SENSE/SELECT) oder akzeptiert nur 520 B. - Optionen:
- Platte hinter einem NetApp-Controller (ONTAP) verwenden (520 B nativ).
- HBA/RAID einsetzen, der PI/DIF-Translation (520→512) beherrscht (einige Broadcom/LSI-MegaRAID-Modelle). OS sieht 512 B.
- Platte tauschen gegen 512n/4Kn-Modell.
10) Optional: Multipath-Spam vermeiden (Blacklist)
Wenn du 520 B-Platten nicht nutzen kannst/willst, blackliste sie (z. B. nach Vendor/Product):
# /etc/multipath/conf.d/blacklist.conf
blacklist {
vendor "NETAPP"
product "X316_SMKRE06TA07"
}
systemctl reload multipathd
11) Troubleshooting-Tabelle
| Symptom | Ursache | Maßnahme |
|---|---|---|
Unsupported sector size 520 |
Linux erwartet 512n/4Kn | Reformat (falls erlaubt) oder HBA-Übersetzung oder Blacklist |
Preferred minimum I/O size 4096 ... not a multiple of 4160 |
Physischer Block = 4160 B (8×520) | Wie oben; Platte ist 520 B-formatiert |
multipathd: failed to setup map ... |
Gerät mit 520 B; kein nutzbares Blockdevice | Nach Reformat OK; sonst Blacklist |
sg_format ... Device not ready (MODE SENSE) |
Firmware blockiert Reformat / bereits Format läuft | Mit sg_requests prüfen; ggf. später erneut versuchen |
INVALID FIELD IN CDB |
Reformat auf 512/4096 verboten (Vendor-Lock) | Nur NetApp/HBA-Translation/tauschen |
Mehrere /dev/sg* für dieselbe Platte |
Mehrpfad (zwei Controller/Ports) | Nur einen Pfad formatieren; Gleichheit via LU name prüfen |
12) Anhang: hilfreiche One-Liner & Schnipsel
12.1 Alle 520 B-Kandidaten listen (mit sd-Mapping & LU-WWN)
#!/usr/bin/env bash
# list-520.sh — listet alle SCSI-Geräte mit 520-Byte-Sektoren
for sg in /dev/sg*; do
cap=$(sg_readcap -l "$sg" 2>/dev/null | tr -d '\r')
[[ -z "$cap" ]] && continue
if echo "$cap" | grep -q "Logical block length=520 bytes"; then
sd=$(lsscsi -g | awk -v s="$sg" '$NF==s{print $(NF-1)}')
inq=$(sg_inq -i "$sg" 2>/dev/null)
serial=$(echo "$inq" | awk -F': ' '/Unit serial number/{print $2}')
lun=$(echo "$inq" | awk -F': ' '/LU name/{print $2}')
size=$(echo "$cap" | awk -F': ' '/Device size/{print $2}')
printf "%-8s %-8s %-20s %-20s %s\n" "$sg" "${sd:--}" "${serial:--}" "${lun:--}" "$size"
fi
done
12.2 Nur einen Pfad pro physischer Disk wählen (per LU-Name deduplizieren)
#!/usr/bin/env bash
# pick-one-path.sh — gibt pro LU (LUN WWN) genau EIN /dev/sg* aus
declare -A seen
for sg in /dev/sg*; do
lun=$(sg_inq -i "$sg" 2>/dev/null | awk -F': ' '/LU name/{print $2}')
[[ -z "$lun" ]] && continue
if [[ -z "${seen[$lun]}" ]]; then
echo "$sg"
seen[$lun]=1
fi
done
12.3 Format sicher anstoßen (schnellstmöglich, wenn erlaubt)
# Beispiel: genau EINEN Pfad der Zielplatte verwenden!
systemctl stop multipathd
multipath -F
# Dry-Run (prüfen, ob 512 akzeptiert wird)
sg_format --format --size=512 --six --fmtpinfo=0 --dry-run /dev/sgXYZ
# Start (Firmware versucht "fast", fällt ggf. auf "full" zurück)
sg_format --format --size=512 --six --fmtpinfo=0 --cmplst=1 --early /dev/sgXYZ
# Fortschritt
watch -n 60 sg_requests /dev/sgXYZ
# Nach Abschluss
rescan-scsi-bus.sh -a
sg_readcap -l /dev/sgXYZ
systemctl start multipathd
multipath -ll
Kurzfazit: 520 B-Sektoren sind bei NetApp wegen T10 PI/DIF ein Feature für Datenintegrität. Unter generischem Linux sind solche Platten ohne Reformat/Übersetzung nicht nutzbar. Wenn die Firmware Reformat erlaubt: sicher auf 512 B/4 Kn umstellen (nur einen Pfad!), Fortschritt mit sg_requests prüfen, danach wie gewohnt einbinden. Wenn nicht: NetApp-Controller oder HBA mit DIF-Translation verwenden – ansonsten die Geräte sauber blacklisten.
NVIDIA
nvidia-smi
„nvidia-smi: command not found“ – so fixt du das (Debian/Kali)
Diese Anleitung hilft dir, nvidia-smi wieder lauffähig zu machen und erklärt kurz, warum der Fehler passiert. Sie ist bewusst einfach gehalten – Schritt für Schritt, mit Kopierbefehlen.
TL;DR – Schnelllösung
- Stelle sicher, dass das NVIDIA/CUDA-Repository aktiv ist (für Treiber 580.x):
install -d /etc/apt/keyrings
curl -fsSL https://developer.download.nvidia.com/compute/cuda/repos/debian12/x86_64/3bf863cc.pub \
| gpg --dearmor -o /etc/apt/keyrings/cuda-archive-keyring.gpg
cat >/etc/apt/sources.list.d/cuda-debian12-x86_64.list <<'EOF'
deb [arch=amd64 signed-by=/etc/apt/keyrings/cuda-archive-keyring.gpg] https://developer.download.nvidia.com/compute/cuda/repos/debian12/x86_64/ /
EOF
apt-get update
- Reihen konsistent halten: gleiche Treiberlinie verwenden (hier 580.x). Prüfe die installierten Versionen:
apt-cache policy nvidia-driver nvidia-alternative libnvidia-ml1 | sed -n '1,200p'
- Fehlendes
nvidia-alternativein 580 installieren (sofern nicht schon da):
apt-get install -y nvidia-alternative=580.82.07-1
- Falls das 580er Repo keine echte
nvidia-smi-Binary liefert: nur die Binary aus 560er-Paket extrahieren (kein Downgrade!):
apt-get download nvidia-smi=560.35.05-1
dpkg-deb -x nvidia-smi_560.35.05-1_amd64.deb /tmp/nsmi
install -D -m 0755 /tmp/nsmi/usr/lib/nvidia/current/nvidia-smi /usr/local/bin/nvidia-smi
ln -sf /usr/local/bin/nvidia-smi /usr/bin/nvidia-smi
hash -r
nvidia-smi -h
nvidia-smi -q | head -n 20
nvidia-smi-Binary. In der Praxis ist das mit libnvidia-ml1 580 kompatibel und genügt für Monitoring.Warum passiert der Fehler?
nvidia-smigehört nicht immer zum Paketnvidia-smi. In manchen Repos ist das nur ein „Dummy“ (enthält nur Doku).- Die echte Binary steckt je nach Distribution/Version in anderen Paketen (z. B.
nvidia-driver-bin,nvidia-utils-*) – oder wird über Metapakete geliefert. - Mischt man Repositories (z. B. Kali 550.x + NVIDIA 580.x), passen die Versionsabhängigkeiten oft nicht zusammen – dann fehlt am Ende die Binary im
PATH.
Sauberer Weg (empfohlen): konsistente Repo-Linie
Entscheide dich für eine Linie: entweder komplett 580.x (NVIDIA/CUDA) oder komplett 550.x (Kali). Mischen führt zu Konflikten.
Variante A – 580.x (NVIDIA/CUDA)
- CUDA-Repo eintragen (siehe TL;DR) und doppelte Zeilen entfernen:
awk '!seen[$0]++' /etc/apt/sources.list.d/cuda-debian12-x86_64.list \
> /etc/apt/sources.list.d/cuda-debian12_x86_64.fixed && \
mv /etc/apt/sources.list.d/cuda-debian12_x86_64.fixed /etc/apt/sources.list.d/cuda-debian12-x86_64.list
apt-get update
- Sicherstellen, dass alle Kernpakete 580 sind:
apt-cache policy nvidia-driver nvidia-alternative libnvidia-ml1
nvidia-alternativeggf. nachziehen:
apt-get install -y nvidia-alternative=580.82.07-1
Wenn keine 580er nvidia-smi-Binary verfügbar ist: siehe Abschnitt „Binary pragmatisch bereitstellen“.
Variante B – 550.x (Kali)
Nur falls du auf Kali-Stand bleiben willst.
- CUDA-Repo deaktivieren (um Versionen nicht zu mischen).
- Kali-Pakete sauber auf 550 ausrichten:
apt-get update
apt-get install -y \
nvidia-driver=550.163.01-3 \
nvidia-driver-bin=550.163.01-3 \
nvidia-alternative=550.163.01-3 \
libnvidia-ml1=550.163.01-3 \
--allow-downgrades
Danach ist /usr/bin/nvidia-smi normalerweise direkt vorhanden.
Binary pragmatisch bereitstellen (ohne System-Downgrade)
Wenn die 580er Repo-Linie keine nvidia-smi-Binary liefert, extrahieren wir nur die Binary aus dem 560er Paket:
apt-get download nvidia-smi=560.35.05-1
dpkg-deb -x nvidia-smi_560.35.05-1_amd64.deb /tmp/nsmi
install -D -m 0755 /tmp/nsmi/usr/lib/nvidia/current/nvidia-smi /usr/local/bin/nvidia-smi
ln -sf /usr/local/bin/nvidia-smi /usr/bin/nvidia-smi
hash -r
nvidia-smi -q | head -n 20
rm -f /usr/bin/nvidia-smi /usr/local/bin/nvidia-smi
rm -rf /tmp/nsmi
Prüfen, ob der Treiber wirklich läuft
nvidia-smi startet auch ohne aktive GPU, zeigt dann aber z. B. „No devices were found“. Treiberstatus prüfen:
lsmod | grep -i nvidia || modprobe nvidia || true
dmesg | grep -i nvidia | tail -n 60
uname -r
Wenn das Kernelmodul fehlt oder nicht baut:
apt-get install -y dkms linux-headers-$(uname -r)
reboot
Alternative: Im Container testen
Mit nvidia-docker2/nvidia-container-toolkit kannst du nvidia-smi im Container ausführen (ohne Host-Binary):
docker run --rm --gpus all nvidia/cuda:12.4.1-base-ubuntu24.04 nvidia-smi
Fehlersuche (Kurzcheckliste)
- Repo doppelt? Datei auf doppelte Zeilen prüfen:
nl -ba '/etc/apt/sources.list.d/cuda-debian12-x86_64.list' - zsh „bad pattern“? Eckige Klammern in Befehlen quoten:
noglob cat /etc/apt/sources.list.d/cuda-debian12-x86_64.list - Welche Versionen verfügbar?
apt-cache policy nvidia-driver nvidia-driver-bin nvidia-alternative libnvidia-ml1 - Wo liegt die Binary?
apt-file update apt-file search -x '(^|/)nvidia-smi$' - Secure Boot? Kann das Laden des Moduls blockieren → Logs prüfen:
dmesg | grep -i 'nvidia\|secure\|module verification'
FAQ
Ist die 560er Binary mit 580 kompatibel?
Für die reine Abfrage über NVML (nvidia-smi) funktioniert das üblicherweise problemlos. Wir installieren keine 560er Systempakete, sondern nutzen nur die einzelne Binary.
Warum nicht einfach „apt install nvidia-smi“?
Weil dieses Paket in einigen Repositories nur ein Platzhalter/Dummy ist (liefert keine Binary). Die echte nvidia-smi kann in anderen Paketen stecken.
Wie mache ich das rückgängig?
Symlinks/Binary entfernen:
rm -f /usr/bin/nvidia-smi /usr/local/bin/nvidia-smi
Repository-Zeilen ggf. wieder anpassen und apt-get update.
Stand: Beispielbefehle für Debian 12/Kali, Treiberlinie 580.x. Versionsnummern bitte bei Bedarf mit apt-cache policy prüfen.
TMUX
tmux - crontab
Default‑Shell schnell auf /bin/bash festlegen
Oft bleibt eine neue tmux‑Session schwarz, wenn keine gültige Standard‑Shell definiert ist. Mit der folgenden Ein‑Zeiler‑ oder Schritt‑für‑Schritt‑Anleitung schreibst du den notwendigen Eintrag in ~/.tmux.conf.
Ein‑Zeiler (sofort ausführen)
echo 'set-option -g default-shell /bin/bash' >> ~/.tmux.conf
echo 'set-option -g default-shell /bin/bash' >> ~/.tmux.conf
mkdir manual
echo -e 'apt-get update\napt-get full-upgrade -y\n/sbin/reboot now' >> manual/update_and_reboot.sh
echo -e 'apt-get update\napt-get full-upgrade -y' >> manual/just_update.sh
Hinweis: /bin/bash ist auf fast allen Linux‑Systemen vorhanden. Wer plattformunabhängig arbeiten möchte, setzt lieber /usr/bin/env bash.
Schritt‑für‑Schritt‑Variante
- Datei öffnen:
nano ~/.tmux.conf - Zeile hinzufügen – ganz egal, wo:
set-option -g default-shell /bin/bash - Speichern & schließen:
Ctrl+O, Enter, Ctrl+X - tmux‑Konfiguration neu laden (ohne Neustart):
tmux source-file ~/.tmux.conf
tmux hängt im toten Netzlaufwerk – Notfall‑Cheatsheet
Wenn dein tmux‑Fenster in einem Pfad steht, der auf einem abgestürzten NFS‑/CIFS‑Mount liegt, wirkt das Terminal wie eingefroren: jeder I/O‑Aufruf wartet ewig auf eine Antwort, die nie kommt. Diese Anleitung zeigt dir, wie du die blockierte Shell verlässt, die Pane reparierst – oder den kaputten Mount brutal löst – ohne deine ganze tmux‑Sitzung zu verlieren.
1 · Schnelle Hilfe direkt in tmux
| Aktion | Tastenfolge (Prefix = Ctrl+b) | Ergebnis |
|---|---|---|
| Neues Window | Ctrl+b c | Frische Login‑Shell in $HOME oder /. |
| Neue Pane (horizontal) | Ctrl+b " | Zweite Shell, unabhängig vom blockierten Verzeichnis. |
| Hängende Pane killen | Ctrl+b x → y | Nur die kaputte Pane wird beendet. |
| Pane neu starten | Ctrl+b : → respawn-pane -k |
Kills + sofortiger Neustart der Shell darin. |
| Ganzes Window killen | Ctrl+b & → y | Alle Panes dieses Fensters schließen. |
Tipp: Meist reicht es, Ctrl+b c zu drücken, sich in der neuen Shell per pwd den aktuellen Pfad anzeigen zu lassen und anschließend den defekten Mount zu lösen (→ Abschnitt 3).
2 · Festhängende Prozesse gezielt töten
# 1 · TTY der Pane herausfinden
who # Spalte "PTS" merken (z. B. pts/4)
# 2 · laufende Prozesse auf diesem TTY zeigen
ps -o pid,stat,cmd -t pts/4
# 3 · sanft beenden (SIGTERM), notfalls hart (SIGKILL)
kill <PID> # SIGTERM
kill -9 <PID> # SIGKILL
Sobald der blockierende Prozess endet, reagiert die Shell sofort wieder.
3 · Abgestürzten Netz‑Mount „faul“ abhängen
sudo umount -l -f /pfad/zum/netzlaufwerk
-l(lazy) entfernt den Mount sofort aus dem Namensraum, selbst wenn noch offene Handles existieren.-f(force) erzwingt das Umounten auch bei NFS‑Server‑Timeout.
Danach funktionieren alle Befehle wieder, die nicht nochmals auf dieses Verzeichnis zugreifen.
4 · Letzter Ausweg – komplette Session schließen
# innerhalb von tmux
Ctrl-b d # detach
# auf der Login-Shell
tmux kill-session -t <sessionname>
Das beendet alles in einem Rutsch. Nützlich, wenn mehrere Windows abhängig sind oder sich die Lage anders nicht bereinigen lässt.
5 · Dauerhafte Prävention
- Automount (systemd.automount / autofs) einsetzen, damit inaktive NFS/CIFS‑Mounts nach Timeout verschwinden.
- Shell‑Prompt optimieren: Entferne jede
$PWD-Auflösung inPROMPT_COMMAND, wenn du häufig in Netzpfaden arbeitest. - Watchdog‑Cronjob: Skript, das hängende Mounts erkennt und
umount -l -fausführt.
6 · „Neue tmux‑Session bleibt leer“ – Konfiguration fixen
Manche Distributionen starten tmux ohne explizite Login‑Shell. Ist die voreingestellte Shell nicht ausführbar (z. B. durch einen defekten Symlink oder ein fehlendes Home‑Verzeichnis), erscheint nur ein schwarzer Bildschirm. Setze deshalb eine valide Standard‑Shell in deiner ~/.tmux.conf:
nano ~/.tmux.conf
# ------------------------------
# Saubere Login‑Shell erzwingen:
set-option -g default-shell /usr/bin/env bash
# Optional: gleich als Login‑Shell starten
set-option -g default-command "bash -l"
# ------------------------------
Verbesserung gegenüber deinem ursprünglichen Trick: /usr/bin/env bash findet bash auch dann, wenn sie nicht unter /bin liegt, und funktioniert daher auf nahezu allen Linux‑Varianten (inkl. macOS / BSD). Mit default-command "bash -l" bekommst du zusätzlich ein vollwertiges Login‑Environment (u. a. /etc/profile wird geladen).
7 · Kurzanleitung für die Hosentasche
# Pane hängt im toten Mount?
Ctrl-b c # neues Window
sudo umount -l -f … # Mount loswerden
Ctrl-b x # alte Pane killen
Fertig! Deine tmux‑Sitzung lebt weiter, und du sparst dir den Logout.
Datenspeicher
Festplatte vergrößern / resize
Linux: Root-Partition mit Bordmitteln vergrößern (fdisk + resize2fs)
Ziel: Die bestehende Root-Partition /dev/sda2 wird ohne Zusatzpakete vergrößert. Wir ändern nur die Partitionstabelle (nicht das Dateisystem selbst) und lassen anschließend das ext4-Dateisystem online wachsen.
Kernprinzip für Sicherheit: Beim Neu-Anlegen der vergrößerten Partition muss der Startsektor von /dev/sda2 exakt gleich bleiben. Dadurch zeigen die Partitions-Metadaten weiterhin auf die gleiche Datenposition – das Dateisystem bleibt unbeschädigt. Wir schreiben erst am Ende mit w; bis dahin sind alle Änderungen nur im Speicher.
1) Voraussetzungen & Vorab-Checks
# Dateisystemtyp von / ermitteln (wichtig für den Grow-Befehl)
findmnt -no FSTYPE /
# Partitionslayout anzeigen und Startsektor von sda2 notieren
fdisk -l /dev/sda
- Notieren: Den Wert in der Spalte Start von
/dev/sda2. Dieser Wert muss später identisch eingegeben werden. - Backup-Empfehlung: Mindestens Konfigs und wichtige Daten (
/etc,/var/lib/<dienst>).
Hinweis: Wenn sich freier Platz rechts (am Ende) von /dev/sda2 befindet, kann sie erweitert werden. In einem MBR-Layout mit einer kleinen erweiterten Partition vor sda2 (wie im Beispiel unten) blockiert diese das Wachstum nicht.
2) Umsetzung nur mit Bordmitteln (fdisk → resize2fs)
2.1 Swap (wenn nötig) temporär deaktivieren
Ist Swap rechts hinter /dev/sda2, muss er aus dem Weg. Im gezeigten Layout liegt /dev/sda5 vor /dev/sda2, daher war keine Aktion nötig. Allgemein:
swapoff -a # Swap überall deaktivieren (nur temporär)
Warum: Aktiver Swap kann das Ändern/Löschen seiner Partition verhindern.
2.2 Partitionstabelle mit fdisk anpassen
fdisk /dev/sda
Kommandos in fdisk (Beispiel-Sitzung passend zu deinem Fall):
p # p = print: aktuelle Tabelle zur Kontrolle anzeigen
d # d = delete: die alte sda2 löschen (nur Tabelleneintrag!)
2 # Partitionsnummer 2
n # n = new: neue Partition anlegen
p # p = primary
2 # Partitionsnummer 2 wiederverwenden
<Startsektor> # exakt den zuvor notierten Start von sda2 eingeben (z.B. 1953792)
<Ende> # Enter für "bis zum Ende" (oder +<Größe> lassen, falls man Platz für Swap-Partition reservieren will)
p # zur Kontrolle (Start muss identisch, Größe nun größer)
w # w = write: Änderungen auf die Disk schreiben
- Was passiert hier? Wir löschen nur den Tabellen-Eintrag von
sda2und legen ihn neu an – mit gleichem Start, aber größerem Ende. Die Nutzdaten bleiben an Ort und Stelle. - Warum sicher? Solange der Startsektor identisch bleibt, beginnt das ext4-Dateisystem am gleichen Offset. Es wird nicht „verschoben“ – nur die Partition informiert den Kernel, dass nun mehr Platz dazugehört.
Optional: Boot-Flag (BIOS/MBR)
In manchen Setups war die Root-Partition bootable (Sternchen in der Spalte Boot). Falls nötig, kann man den Boot-Flag wieder setzen:
a # a = toggle bootable flag
2 # für Partition 2
w # schreiben
Viele GRUB-Installationen booten auch ohne gesetztes Flag, aber wenn es zuvor gesetzt war, empfiehlt es sich, es wieder zu setzen.
2.3 Reboot (nur falls erforderlich)
Bei Root-Disks kann der Kernel die neue Geometrie nicht immer „live“ einlesen. In deinem Fall hat das Online-Resizing direkt funktioniert. Allgemein ist ein Neustart empfehlenswert:
reboot
3) Dateisystem online vergrößern
Für ext4 geht das im laufenden Betrieb:
# optionaler Konsistenzcheck im Online-Modus
e2fsck -f /dev/sda2
# ext4 bis zum Partitionsende vergrößern
resize2fs /dev/sda2
Was macht das? resize2fs liest die neue (größere) Partitionslänge aus und erweitert die internen Strukturen des ext4-Dateisystems, sodass der zusätzliche Platz nutzbar wird.
Ergebnis prüfen:
df -h /
lsblk
4) Deine konkrete Sitzung (vorher → nachher)
# Vorher (auszug)
Disklabel type: dos
Device Boot Start End Sectors Size Id Type
/dev/sda1 2046 1953791 1951746 953M 5 Extended
/dev/sda2 * 1953792 314570751 312616960 149.1G 83 Linux
/dev/sda5 2048 1953791 1951744 953M 82 Linux swap / Solaris
# Aktion in fdisk:
d (2) → n (p, 2, Start=1953792, Ende=629145599) → w
# Nachher
Device Boot Start End Sectors Size Id Type
/dev/sda1 2046 1953791 1951746 953M 5 Extended
/dev/sda2 1953792 629145599 627191808 299.1G 83 Linux
/dev/sda5 2048 1953791 1951744 953M 82 Linux swap / Solaris
# Dateisystem vergrößert:
resize2fs /dev/sda2
→ The filesystem on /dev/sda2 is now 78398976 (4k) blocks long.
# Platzgewinn sichtbar:
df -h /
→ /dev/sda2 294G used 97G free 184G (Beispielwerte)
Besonderheit deines Layouts: Die kleine erweiterte Partition (/dev/sda1 mit /dev/sda5 als Swap) liegt am Anfang der Platte – vor /dev/sda2. Da wir /dev/sda2 nach rechts bis ans Plattenende vergrößert haben, störte der Swap nicht und musste nicht verschoben/gelöscht werden.
5) Warum das Verfahren sicher ist (wenn man es korrekt macht)
- Unveränderte Datenlage: Es wird kein Byte des Dateisystems verschoben. Wir ändern nur die Beschreibung (Partitionseintrag) und vergrößern danach das FS „in-place“.
- Zentraler Sicherheitsanker: Der Startsektor der Root-Partition bleibt exakt identisch.
- Transaktionscharakter in fdisk: Bis zum Befehl
wsind alle Änderungen nur im Speicher. Mitqkönnte man gefahrlos abbrechen. - Online-Resize in ext4: Das Vergrößern geht im gemounteten Zustand; ext4 ist dafür ausgelegt.
Wenn es schief geht? Typische Fehler entstehen nur, wenn der Startsektor falsch eingegeben wird (→ dann zeigt der Eintrag nicht mehr auf das Dateisystem). Deshalb: Vor dem w mit p gegentesten und den Startwert doppelt prüfen.
6) Typische Stolpersteine & Checks
- Boot-Flag: Falls vorher gesetzt, ggf. mit
awieder setzen. - /etc/fstab: Root wird meist via FS-UUID gemountet (bleibt unverändert). Falls per
PARTUUIDoder Gerätenamen gearbeitet wird, nachziehen. - Swap: Wenn die Swap-Partition gelöscht/verschoben wurde,
/etc/fstabanpassen oder auf ein Swapfile umstellen. - XFS: XFS kann nur wachsen (Befehl:
xfs_growfs /), nicht schrumpfen. - Kernel-Re-Read: Auf Root-Disk gelingt das Live-Einlesen nicht immer → ggf. Reboot einplanen.
7) Alternative: Swap als Datei (empfohlen)
Wer künftig flexibel bleiben will, legt Swap als Datei an und spart sich MBR/erweiterte-Partition-Themen:
# 2 GiB Swapfile (Größe anpassen)
fallocate -l 2G /swapfile || dd if=/dev/zero of=/swapfile bs=1M count=2048
chmod 600 /swapfile
mkswap /swapfile
swapon /swapfile
printf "\n/swapfile none swap sw 0 0\n" >> /etc/fstab
8) Kurzzusammenfassung (Cheat Sheet)
# 1) Startsektor notieren
fdisk -l /dev/sda
# 2) fdisk: sda2 löschen > neu anlegen (gleicher Start, größeres Ende)
fdisk /dev/sda
# p, d (2), n (p, 2), Start=<alter Start>, Ende=<Enter für Ende>, p, w
# 3) (ggf.) reboot
# 4) Dateisystem vergrößern (ext4)
resize2fs /dev/sda2
# 5) prüfen
df -h /
lsblk
Damit ist die Root-Partition vergrößert, ohne zusätzliche Tools zu installieren, minimal-invasiv und sicher – sofern der Startsektor gleich bleibt und die Kontrolle mit p vor dem w sorgfältig erfolgt.
Linux - SoCat
SoCat - Fast start
1. Was ist socat?
Socat (SOcket CAT) ist ein sehr flexibles Kommandozeilen-Tool zum Weiterleiten von Datenströmen zwischen Netzwerk-Ports, Dateien, Pipes, UNIX Sockets oder SSL/TLS-Verbindungen.
- Temporäres Port-Forwarding zwischen unterschiedlichen Netzen oder Interfaces
- Debugging & Überbrückung von Netzwerkrestriktionen
- Brücke zwischen alten und neuen Protokollen (z.B. altes TLS zu modernem TLS)
Tipp: Für produktiven Dauerbetrieb sind Reverse-Proxys, VPNs oder Firewalls die bessere Wahl – socat ist ideal als temporärer Workaround!
2. Installation unter Debian/Linux
apt-get update
apt-get install socat
apt-get update: Paketquellen aktualisieren.apt-get install socat: Socat installieren.
3. Einfaches Port-Forwarding: 192.168.0.1 → localhost
Beispiel: Du möchtest einen Dienst auf 192.168.0.1:8080 lokal als localhost:8000 bereitstellen.
socat TCP-LISTEN:8000,bind=localhost,reuseaddr,fork TCP:192.168.0.1:8080
- TCP-LISTEN:8000,bind=localhost: Lauscht lokal auf Port 8000 (nur auf localhost).
- reuseaddr,fork: Mehrere/kurze Verbindungen, sofortige Wiederverwendung.
- TCP:192.168.0.1:8080: Weiterleitung zum Dienst auf
192.168.0.1:8080.
4. Mehrere Ports/Services von 192.168.0.1 zu localhost weiterleiten
socat TCP-LISTEN:8001,bind=localhost,reuseaddr,fork TCP:192.168.0.1:8081
5. Optionen erklärt
- fork: Parallele Verbindungen möglich
- reuseaddr: Port sofort wieder benutzbar
- bind=localhost: Lauscht nur auf localhost (kein LAN-Zugriff möglich)
6. Verbindung nach Abbruch automatisch wiederherstellen (persist)
socat -d -d TCP:192.168.0.1:8080,persist STDOUT
- persist: Baut Verbindung bei Abbruch erneut auf
- -d -d: Debug-Ausgabe
- STDOUT: Gibt Daten im Terminal aus (Beispiel)
7. SSL/TLS: Verbindung von altem 192.168.0.1-SSL auf lokalen Dienst
Beispiel: Dienst auf 192.168.0.1:8443 nutzt nur TLS 1.0, du möchtest lokal localhost:8000 bereitstellen.
openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem -days 365 -nodes -subj "/CN=localhost"
socat openssl-connect:192.168.0.1:8443,method=TLS1 TCP-LISTEN:8000,bind=localhost,reuseaddr,fork
8. Umgekehrter Weg: Lokaler Dienst auf localhost nach 192.168.0.1 im anderen Netz bereitstellen
socat TCP-LISTEN:8080,bind=192.168.0.1,reuseaddr,fork TCP:localhost:8000
9. Hinweise & Tipps
- Der Rechner mit socat braucht Zugriff auf beide IPs/Netze.
- Temporärer Einsatz: Nach Nutzung
Strg+Coder Terminal schließen. - Für längere Nutzung: Reverse-Proxy, VPN oder Firewall bevorzugen.
- Mit
-d -dbekommst du hilfreiche Debug-Ausgaben.
10. Ressourcen
Sudo deinstallieren
1) Ziel & Hintergrund
Auf Systemen wie Kali/Debian existiert immer ein Root-Account. sudo ist ein Komfort- und Kontrollwerkzeug, um Root-Rechte selektiv an normale Benutzer zu delegieren. Diese Anleitung stellt um auf das klassische Modell: kein sudo, Adminzugriff nur über su - mit Root-Passwort.
2) Auswirkungen & Trade-offs
| Aspekt | Mit sudo |
Mit su - (ohne sudo) |
|---|---|---|
| Berechtigungen | Feingranular delegierbar | Alles oder nichts über Root-Passwort |
| Nachvollziehbarkeit | Pro-User-Logging möglich | Weniger granular; Fokus auf Auth-Logs |
| Komfort | Befehlsweise Elevation | Bewusster Wechsel in Root-Shell |
| Angriffsfläche | Zusätzliche Binary & Policy | Weniger Komponenten, ein Geheimnis (Root-PW) |
sudo installiert ist. Sicherheit entsteht hier primär durch Zugriffskontrolle, Härtung und Auditing.3) Vorbereitung (Root & Backup)
- Sicherstellen, dass Root aktiviert ist und ein Passwort hat:
# falls aktuell noch sudo vorhanden ist: sudo passwd root # ab dann: su - - Backups der sudo-Konfiguration:
mkdir -p /root/backup-sudo-files cp -a /etc/sudoers /root/backup-sudo-files/ 2>/dev/null || true cp -a /etc/sudoers.d /root/backup-sudo-files/ 2>/dev/null || true
4) sudo entfernen (Paket oder manuell)
4.1 Paketzuordnung prüfen
which sudo
ls -l /usr/bin/sudo
dpkg -S /usr/bin/sudo 2>/dev/null || echo "Kein dpkg-Eintrag (manuell installiert)"
4.2 Falls als Paket installiert
apt update
apt purge -y sudo sudo:arm64 || true
apt autoremove -y
4.3 Falls nicht paketverwaltet (manuell installiert)
sudo nicht von dpkg verwaltet wird.cp -a /usr/bin/sudo /root/backup-sudo # Sicherung
rm -v /usr/bin/sudo # Entfernen
# optional: visudo entfernen, falls vorhanden
[ -e /usr/bin/visudo ] && rm -v /usr/bin/visudo
5) Bereinigen von Gruppen & Resten
# Benutzer aus sudo-Gruppe entfernen (Beispiel: jj)
deluser jj sudo
# sudo-Gruppe ggf. ganz entfernen
getent group sudo && delgroup sudo || true
Optional: su auf bestimmte Gruppe beschränken (pam_wheel)
Damit nur Mitglieder einer bestimmten Gruppe (z. B. wheel) su benutzen dürfen:
groupadd wheel 2>/dev/null || true
gpasswd -a deinadmin wheel
# PAM anpassen (Zeile aktivieren):
sed -i 's|^#\s*auth\s\+required\s\+pam_wheel.so\s\+use_uid|auth required pam_wheel.so use_uid|' /etc/pam.d/su
Damit ist nicht jeder lokale User zu su berechtigt.
6) Verifikation & Funktionstests
# Existenz prüfen
command -v sudo || echo "sudo nicht gefunden (erwartet)"
# als normaler Benutzer: sudo sollte scheitern
sudo id || echo "OK: sudo nicht verfügbar"
# Rootwechsel via su -
su - -c 'id && whoami'
/var/log/auth.log (oder Journal) sollte su-Events zeigen.7) Warum das der Sicherheit hilft
- Reduzierte Angriffsfläche: Entfernt eine zusätzliche, setuid-fähige Binary (
/usr/bin/sudo) und deren Policy/Parser. - Einheitliches Geheimnis: Nur das Root-Passwort erlaubt Privilege Escalation. Kein Nebeneingang über falsch konfigurierte
sudoers-Regeln. - Bewusster Admin-Kontext: Klare Trennung: normale Arbeit als User, gezielter Wechsel in eine Root-Login-Shell.
su-Logging und ggf. pam_wheel (siehe nächster Abschnitt).8) Zusätzliche Härtung (Best Practices)
8.1 SSH
# /etc/ssh/sshd_config anpassen:
PermitRootLogin prohibit-password # Root nur per Key; oder 'no' wenn du Root-SSH ganz verbietest
PasswordAuthentication no # globale Passwort-Logins aus (nur Keys)
PubkeyAuthentication yes
ChallengeResponseAuthentication no
UsePAM yes
# danach:
systemctl restart ssh
Wenn du Root-SSH doch per Passwort brauchst
Dann setze PermitRootLogin yes und erzwinge starke Passwörter + Fail2Ban. Besser ist dennoch: SSH-Keys + ggf. 2FA (PAM/Google Authenticator).
8.2 Passwortrichtlinien
# Beispiel: libpam-pwquality nutzen
apt install -y libpam-pwquality
# /etc/security/pwquality.conf anpassen (Minimallänge, Klassen, etc.)
8.3 Auditing & Log-Monitoring
apt install -y auditd
auditctl -l | cat
# su/Passwort-Events erscheinen in /var/log/auth.log bzw. journalctl -u ssh -u systemd-logind
8.4 Brute-Force-Schutz
apt install -y fail2ban
# jail.local anpassen, insbesondere für sshd; dann:
systemctl enable --now fail2ban
8.5 su einschränken (PAM Wheel)
Siehe Abschnitt 5: Nur Mitglieder von wheel dürfen su verwenden.
9) Rollback (sudo wiederherstellen)
- Neuinstallation:
apt update apt install -y sudo - Benutzer berechtigen:
usermod -aG sudo # neue Gruppenmitgliedschaft gilt nach neuem Login - Konfiguration prüfen:
visudo # Syntaxcheck & Policy anpassen
10) Anhang: Ein-Befehl-Variante (vorsichtig!)
Führt Backup, Entfernung (Paket oder manuell) und Gruppenbereinigung in einem Rutsch aus. Vorher lesen!
bash -c '
set -euo pipefail
echo ">>> Backup"; mkdir -p /root/backup-sudo-files;
cp -a /etc/sudoers /root/backup-sudo-files/ 2>/dev/null || true;
cp -a /etc/sudoers.d /root/backup-sudo-files/ 2>/dev/null || true;
SUDO_BIN="$(command -v sudo || true)";
if [ -n "$SUDO_BIN" ]; then
echo ">>> Gefunden: $SUDO_BIN";
dpkg -S "$SUDO_BIN" &>/dev/null && {
echo ">>> Paketverwaltet: apt purge";
apt update;
apt purge -y sudo sudo:arm64 || true;
apt autoremove -y;
} || {
echo ">>> Nicht paketverwaltet: manuell entfernen";
cp -a "$SUDO_BIN" /root/backup-sudo-files/;
rm -v "$SUDO_BIN";
[ -e /usr/bin/visudo ] && rm -v /usr/bin/visudo || true;
};
else
echo ">>> sudo nicht im PATH";
fi
# Beispielbenutzer anpassen:
if getent group sudo &>/dev/null; then
deluser jj sudo || true;
delgroup sudo || true;
fi
echo ">>> Fertig."
'
jj im Script an deine Umgebung an.Linux - MQTT
MQTT - Retained Message
Diese Anleitung erklärt kurz, was retained messages sind, wie du eine retained Nachricht gezielt löschen kannst, und was es mit der LWT (Last Will and Testament) auf sich hat.
Was ist eine retained message?
Eine retained message ist die zuletzt veröffentlichte Nachricht einer Topic, die der Broker speichert und sofort an neue Subscriber ausliefert, sobald sie das Topic abonnieren. Das ist praktisch für Statuswerte (z. B. „online“), kann aber zu unerwünschtem Verhalten führen, wenn versehentlich ein Steuerbefehl mit retain veröffentlicht wurde.
Symptom: Du abonnierst ein Topic und ein alter Befehl wird sofort wieder angewendet – obwohl niemand gerade etwas sendet. Das ist fast immer eine retained message.
Retained message löschen
Löschen geht, indem du auf genau dieselbe Topic eine leere Payload mit gesetztem Retain-Flag veröffentlichst.
Beispiel (Mosquitto-Tools)
# -r = retained publish, -n = empty payload
mosquitto_pub -h <broker> -t 'dein/topic' -r -n
# mit Benutzer/Passwort:
mosquitto_pub -h <broker> -u <user> -P <pass> -t 'dein/topic' -r -n
# mit TLS (falls benötigt), Zertifikat prüfen:
mosquitto_pub -h <broker> -p 8883 --capath /etc/ssl/certs -t 'dein/topic' -r -n
- Wildcards (
+,#) funktionieren hier nicht. Es muss exakt dieselbe Topic sein. - Nach dem Löschen erhalten neue Subscriber beim ersten Abo keine alte Nachricht mehr (bis wieder retained gepublished wird).
Retained Nachrichten prüfen / sichtbar machen
Beim Abonnieren sendet der Broker retained Nachrichten sofort. So siehst du, ob noch eine da ist:
# zeigt auch retained beim Start
mosquitto_sub -v -h <broker> -t 'dein/topic'
# retained unterdrücken (nur Live-Nachrichten)
mosquitto_sub -v -h <broker> -t 'dein/topic' -R
Vermeiden, dass es wieder passiert
- Beim Senden kein Retain-Flag setzen (bei
mosquitto_pubalso ohne-r). - In deinem MQTT-Client die Option „retain“ bzw. „Retained Message“ deaktivieren, sofern nicht bewusst benötigt.
- Für Statuswerte (z. B. Sensorzustände) ist retain okay; für Steuerbefehle (z. B. „schalte an“) meist nicht.
Unterscheidung: Retained vs. LWT (Last Will and Testament)
Die LWT ist eine Nachricht, die der Broker automatisch sendet, wenn ein Client unerwartet die Verbindung verliert. Sie kann optional ebenfalls retained sein.
- Löschen einer bereits veröffentlichten LWT (falls retained): Genau wie oben – leere retained Payload auf die LWT-Topic publishen.
- Verhindern künftiger LWT-Nachrichten: Im Client die LWT-Konfiguration anpassen oder Verbindungen sauber schließen; außerdem LWT ohne
retainkonfigurieren, wenn sie nicht persistieren soll.
Häufige Fehler
- Falsche Topic: Die Löschung wirkt nur auf exakt dieselbe Topic.
- Ohne Retain gelöscht: Eine leere nicht-retained Nachricht löscht nichts.
- Mehrere Quellen: Ein anderes System veröffentlicht die Nachricht erneut retained. Ursache identifizieren und dort das Retain-Flag entfernen.
Kurze Checkliste
mosquitto_substarten und prüfen, ob beim Abo sofort eine Nachricht kommt.- Mit
mosquitto_pub -r -nauf die exakte Topic leere Payload senden. - Nochmals abonnieren und verifizieren, dass nichts retained kommt.
- In Sender-Clients Retain-Flag für Steuer-Themen deaktivieren.
Beispiele mit Platzhaltern
# Platzhalter ersetzen:
# <broker> = Hostname/IP des Brokers
# <user> / <pass> = Zugangsdaten (falls gesetzt)
# 'dein/topic' = exakte Topic der alten retained Nachricht
mosquitto_pub -h mqtt.example.lan -u haus -P geheim -t 'haus/wohnzimmer/licht/set' -r -n
mosquitto_sub -v -h mqtt.example.lan -t 'haus/wohnzimmer/licht/set'
Sicherheit: Nutze nach Möglichkeit TLS am Broker (Port 8883) und Accounts mit eng zugeschnittenen Berechtigungen (ACLs), damit nicht versehentlich auf falsche Topics geschrieben wird.
Lenovo - Thinkpad
Fn+F8 (WLAN-rfkill) deaktivieren – Lenovo ThinkPad
Ziel: Das WLAN darf durch die Fn+F8-Taste nicht mehr per rfkill blockiert werden.
Umgebung
- Hardware: Lenovo ThinkPad
- OS: Debian 13
- Desktop: KDE Plasma (Wayland)
- Kernel-Treiber:
thinkpad_acpi
Lösung (Hotkey-Interface abschalten)
Deaktiviert das Hotkey-Input-Interface von thinkpad_acpi, sodass Fn+F8 kein rfkill mehr auslöst.
sudo tee /etc/modprobe.d/thinkpad-hotkey-off.conf >/dev/null <<'EOF'
options thinkpad_acpi hotkey=0
EOF
sudo modprobe -r thinkpad_acpi
sudo modprobe thinkpad_acpi
Optional: systemd-rfkill neutralisieren
Verhindert, dass beim Booten alte rfkill-Zustände wiederhergestellt werden.
sudo systemctl stop systemd-rfkill.service systemd-rfkill.socket
sudo systemctl mask systemd-rfkill.service systemd-rfkill.socket
sudo rm -f /var/lib/systemd/rfkill/*
Verifikation
- Alle Soft-Blocks aufheben:
rfkill unblock all
rfkill list
- Fn+F8 drücken und erneut prüfen:
rfkill list
Rollback
Hotkey-Interface wieder aktivieren:
sudo rm -f /etc/modprobe.d/thinkpad-hotkey-off.conf
sudo modprobe -r thinkpad_acpi
sudo modprobe thinkpad_acpi
Optional: systemd-rfkill wieder aktivieren:
sudo systemctl unmask systemd-rfkill.service systemd-rfkill.socket
sudo systemctl start systemd-rfkill.service systemd-rfkill.socket
Hinweise
- Durch
hotkey=0werden Events des Geräts „ThinkPad Extra Buttons“ nicht mehr bereitgestellt (einige Fn-Sondertasten können dadurch entfallen). - Hardware-Schalter/BIOS-Hard-Block (falls vorhanden) wirken weiterhin.
Linux - Tmux
tmux autostart (boot + Display)
tmux Orchestrator (boot + Display) – Installation auf neuem Server
Diese Anleitung richtet pro Benutzer einen systemd-Userdienst ein, der:
- beim Boot sofort
tm0startet (ohne DISPLAY), - anschließend in einer Schleife auf die Anzeige wartet (Xauth-Cookie), dann DISPLAY/XAUTH/XDG_RUNTIME_DIR in den tmux-Server injiziert,
- und danach die in
~/.config/tmux/autostart.confdefiniertendisplay|…-Sessions/Fenster vorbereitet/ausführt.
Der Orchestrator startet Kommandos in der bestehenden zsh, sodass Ctrl+C nur das Programm beendet. Ein cd … im Command wirkt persistent.
0) Voraussetzungen
sudo apt update
sudo apt install -y tmux zsh xauth x11-xserver-utils
# (optional) setxkbmap ist in x11-xserver-utils enthalten
Falls der Benutzer nicht jj heißt, ersetze ihn in den folgenden Befehlen entsprechend. Die Inhalte der Dateien bleiben gleich.
1) Benutzer jj einrichten
1.1 Linger aktivieren (User-Manager auch ohne Login)
sudo loginctl enable-linger jj
1.2 Verzeichnisse anlegen
sudo -u jj mkdir -p /home/jj/.config/systemd/user /home/jj/.config/tmux
1.3 Service-Datei (User-Unit)
/home/jj/.config/systemd/user/tmux-autostart.service
[Unit]
Description=Start/refresh tmux for jj (boot + wait for display, fixed socket)
[Service]
Type=simple
# Delay, bis /run/user/<uid> steht
ExecStartPre=/bin/sleep 10
# Sockets mit sicheren Rechten vorbereiten
ExecStartPre=/usr/bin/install -d -m 0700 -o %u -g %u %t
ExecStartPre=/usr/bin/install -d -m 0700 -o %u -g %u %t/tmux-%u
# alten Default-Socket ggf. entfernen (sauberer Start)
ExecStartPre=/usr/bin/env bash -c 'test -S "%t/tmux-%u/default" && rm -f "%t/tmux-%u/default" || true'
Environment=PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
Environment=TMUX_TMPDIR=%t
Environment=TMUX=
UMask=0077
KillMode=process
ExecStart=%h/.config/tmux/orchestrator.sh
[Install]
WantedBy=default.target
1.4 Orchestrator-Skript (fixer Socket, persistentes cd, :0 nutzen)
/home/jj/.config/tmux/orchestrator.sh
#!/usr/bin/env bash
# ~/.config/tmux/orchestrator.sh (jj) – fixed socket /run/user/<uid>/tmux-<uid>/default
set -euo pipefail
unset TMUX
CONF="$HOME/.config/tmux/autostart.conf"
TMUX_BIN="$(command -v tmux)"
ZSH_BIN="$(command -v zsh || echo /usr/bin/zsh)"
UIDNUM="$(id -u)"
RUNDIR="${XDG_RUNTIME_DIR:-/run/user/${UIDNUM}}"
SOCKDIR="$RUNDIR/tmux-${UIDNUM}"
SOCK="$SOCKDIR/default"
umask 077
install -d -m 0700 -o "$UIDNUM" -g "$UIDNUM" "$RUNDIR" >/dev/null 2>&1 || true
install -d -m 0700 -o "$UIDNUM" -g "$UIDNUM" "$SOCKDIR" >/dev/null 2>&1 || true
export TMUX_TMPDIR="$RUNDIR"
export PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:$PATH"
TMUXS=(-S "$SOCK")
log() { printf '[tmux-auto] %s\n' "$*" >&2; }
command -v "$TMUX_BIN" >/dev/null 2>&1 || { log "missing tmux"; exit 127; }
ensure_session() {
local s="$1"
if ! "$TMUX_BIN" "${TMUXS[@]}" has-session -t "$s" 2>/dev/null; then
"$TMUX_BIN" "${TMUXS[@]}" new-session -d -s "$s" "$ZSH_BIN -l"
sleep 0.1
"$TMUX_BIN" "${TMUXS[@]}" send-keys -t "$s" "cd $HOME" C-m
log "created session $s"
fi
}
ensure_window() {
local s="$1" w="$2"
if ! "$TMUX_BIN" "${TMUXS[@]}" list-windows -t "$s" -F '#W' 2>/dev/null | grep -Fxq -- "$w"; then
"$TMUX_BIN" "${TMUXS[@]}" new-window -t "$s" -n "$w" "$ZSH_BIN -l"
sleep 0.05
"$TMUX_BIN" "${TMUXS[@]}" send-keys -t "$s:$w" "cd $HOME" C-m
log "created window $s:$w"
fi
}
run_in_window_shell() {
local tgt="$1" cmd="$2"
if printf '%s' "$cmd" | grep -Eq '^[[:space:]]*cd[[:space:]]+'; then
"$TMUX_BIN" "${TMUXS[@]}" send-keys -t "$tgt" "$cmd" C-m
else
"$TMUX_BIN" "${TMUXS[@]}" send-keys -t "$tgt" "bash -lc '$cmd'" C-m
fi
log "started $tgt -> $cmd"
}
harden_tmux_server() {
"$TMUX_BIN" "${TMUXS[@]}" set -g remain-on-exit on >/dev/null
"$TMUX_BIN" "${TMUXS[@]}" set -g exit-empty off >/dev/null
"$TMUX_BIN" "${TMUXS[@]}" set -g detach-on-destroy off >/dev/null
}
run_phase_boot() {
ensure_session tm0
harden_tmux_server
[[ -f "$CONF" ]] || return 0
awk -F '|' '/^[[:space:]]*#/ || /^[[:space:]]*$/ {next} $1=="boot"{print}' "$CONF" |
while IFS='|' read -r _p s w cmd; do
s="${s:-tm0}"; ensure_session "$s"
if [ -z "${cmd:-}" ]; then [ -n "${w:-}" ] && ensure_window "$s" "$w"; continue; fi
if [ "$s" = "tm0" ]; then
[ -n "${w:-}" ] && "$TMUX_BIN" "${TMUXS[@]}" rename-window -t tm0:0 "$w" 2>/dev/null || true
run_in_window_shell "tm0:0" "$cmd"
else
if [ -n "${w:-}" ]; then
ensure_window "$s" "$w"; run_in_window_shell "$s:$w" "$cmd"
else
run_in_window_shell "$s:0" "$cmd" # :0 wiederverwenden
fi
fi
done
}
wait_for_display_and_inject() {
local xauth disp
log "waiting for display (xauth cookie in $RUNDIR)…"
while true; do
xauth="$(ls -t "$RUNDIR"/xauth_* 2>/dev/null | head -n1 || true)"
if [ -n "${xauth:-}" ] && [ -s "$xauth" ]; then
disp="$(xauth -f "$xauth" list 2>/dev/null | awk '{ if (match($0,/unix:([0-9]+)/)) {n=substr($0,RSTART+5,RLENGTH-5); print ":" n; exit} if (match($0,/:([0-9]+)/)) {n=substr($0,RSTART+1,RLENGTH-1); print ":" n; exit} }')"
if [ -n "${disp:-}" ]; then
"$TMUX_BIN" "${TMUXS[@]}" set-environment -g XAUTHORITY "$xauth"
"$TMUX_BIN" "${TMUXS[@]}" set-environment -g DISPLAY "$disp"
"$TMUX_BIN" "${TMUXS[@]}" set-environment -g XDG_RUNTIME_DIR "$RUNDIR"
export XAUTHORITY="$xauth" DISPLAY="$disp" XDG_RUNTIME_DIR="$RUNDIR"
log "injected DISPLAY=$disp, XAUTHORITY=$xauth"
return 0
fi
fi
sleep 2
done
}
set_xkb_for_xwayland() {
command -v setxkbmap >/dev/null 2>&1 || return 0
local cur_layout cur_variant
cur_layout="$(setxkbmap -query 2>/dev/null | awk '/^layout:/ {print $2}')"
cur_variant="$(setxkbmap -query 2>/dev/null | awk '/^variant:/ {print $2}')"
if [ "$cur_layout" != "de" ] || [ "${cur_variant:-}" != "nodeadkeys" ]; then
setxkbmap -layout de -variant nodeadkeys 2>/dev/null || true
log "setxkbmap de nodeadkeys for Xwayland clients"
fi
}
run_phase_display() {
[[ -f "$CONF" ]] || return 0
awk -F '|' '/^[[:space:]]*#/ || /^[[:space:]]*$/ {next} $1=="display"{print}' "$CONF" |
while IFS='|' read -r _p s w cmd; do
s="${s:-tm0}"; ensure_session "$s"
if [ -z "${w:-}" ]; then w=""; fi
if [ -z "${cmd:-}" ]; then
if [ -n "$w" ]; then ensure_window "$s" "$w"; fi
continue
fi
if [ -n "$w" ]; then
ensure_window "$s" "$w"; run_in_window_shell "$s:$w" "$cmd"
else
run_in_window_shell "$s:0" "$cmd"
fi
done
}
log "start (boot phase)"; run_phase_boot
log "wait/display phase"; wait_for_display_and_inject
set_xkb_for_xwayland
run_phase_display
log "done"; exit 0
1.5 Beispiel-Config
/home/jj/.config/tmux/autostart.conf
# phase|session|window|command
# BOOT: sofort in tm0:0 ausführen
boot|tm0|AI|cd /home/jj/Test_Lab/Camera/; source /home/jj/Test_Lab/Camera/.venv/bin/activate && python3 /home/jj/Test_Lab/Camera/Version_0.8__capture.py
# DISPLAY: Sessions vorbereiten/Ordner setzen
display|tm12||cd /home/jj/OpenVPN/Schneider.land
display|tm5||
1.6 Rechte & Start
sudo -u jj chmod 0755 /home/jj/.config/tmux/orchestrator.sh
sudo -u jj systemctl --user daemon-reload
sudo -u jj systemctl --user enable --now tmux-autostart.service
1.7 Test
# direkt nach Aktivierung
sudo -u jj tmux -S /run/user/1000/tmux-1000/default ls
# nach Login (GUI): display-Phase sollte gelaufen sein
sudo -u jj tmux ls
2) Optional: root identisch als User-Unit
2.1 Linger & Verzeichnisse
sudo loginctl enable-linger root
sudo mkdir -p /root/.config/systemd/user /root/.config/tmux
2.2 Service-Datei
/root/.config/systemd/user/tmux-autostart.service
[Unit]
Description=Start/refresh tmux for root (boot + wait for display, fixed socket)
[Service]
Type=simple
ExecStartPre=/bin/sleep 10
ExecStartPre=/usr/bin/install -d -m 0700 -o root -g root /run/user/0
ExecStartPre=/usr/bin/install -d -m 0700 -o root -g root /run/user/0/tmux-0
ExecStartPre=/usr/bin/env bash -c 'test -S "/run/user/0/tmux-0/default" && rm -f "/run/user/0/tmux-0/default" || true'
Environment=PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
Environment=TMUX_TMPDIR=%t
Environment=TMUX=
UMask=0077
KillMode=process
ExecStart=%h/.config/tmux/orchestrator.sh
[Install]
WantedBy=default.target
2.3 Orchestrator-Skript (root, fester Socket + Boot-:0-Fix)
/root/.config/tmux/orchestrator.sh
#!/usr/bin/env bash
# /root/.config/tmux/orchestrator.sh – fixed socket /run/user/0/tmux-0/default
set -euo pipefail
unset TMUX
CONF="/root/.config/tmux/autostart.conf"
TMUX_BIN="$(command -v tmux)"
ZSH_BIN="$(command -v zsh || echo /usr/bin/zsh)"
RUNDIR="/run/user/0"
SOCKDIR="$RUNDIR/tmux-0"
SOCK="$SOCKDIR/default"
umask 077
install -d -m 0700 -o root -g root "$RUNDIR" >/dev/null 2>&1 || true
install -d -m 0700 -o root -g root "$SOCKDIR" >/dev/null 2>&1 || true
export TMUX_TMPDIR="$RUNDIR"
export PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:$PATH"
TMUXS=(-S "$SOCK")
log() { printf '[tmux-root] %s\n' "$*" >&2; }
command -v "$TMUX_BIN" >/dev/null 2>&1 || { log "missing tmux"; exit 127; }
ensure_session() {
local s="$1"
if ! "$TMUX_BIN" "${TMUXS[@]}" has-session -t "$s" 2>/dev/null; then
"$TMUX_BIN" "${TMUXS[@]}" new-session -d -s "$s" "$ZSH_BIN -l"
sleep 0.1
"$TMUX_BIN" "${TMUXS[@]}" send-keys -t "$s" "cd /root" C-m
log "created session $s"
fi
}
ensure_window() {
local s="$1" w="$2"
if ! "$TMUX_BIN" "${TMUXS[@]}" list-windows -t "$s" -F '#W' 2>/dev/null | grep -Fxq -- "$w"; then
"$TMUX_BIN" "${TMUXS[@]}" new-window -t "$s" -n "$w" "$ZSH_BIN -l"
sleep 0.05
"$TMUX_BIN" "${TMUXS[@]}" send-keys -t "$s:$w" "cd /root" C-m
log "created window $s:$w"
fi
}
run_in_window_shell() {
local tgt="$1" cmd="$2"
if printf '%s' "$cmd" | grep -Eq '^[[:space:]]*cd[[:space:]]+'; then
"$TMUX_BIN" "${TMUXS[@]}" send-keys -t "$tgt" "$cmd" C-m
else
"$TMUX_BIN" "${TMUXS[@]}" send-keys -t "$tgt" "bash -lc '$cmd'" C-m
fi
log "started $tgt -> $cmd"
}
harden_tmux() {
"$TMUX_BIN" "${TMUXS[@]}" set -g remain-on-exit on >/dev/null
"$TMUX_BIN" "${TMUXS[@]}" set -g exit-empty off >/dev/null
"$TMUX_BIN" "${TMUXS[@]}" set -g detach-on-destroy off >/dev/null
}
run_phase_boot() {
ensure_session tm0
harden_tmux
[[ -f "$CONF" ]] || return 0
awk -F '|' '/^[[:space:]]*#/ || /^[[:space:]]*$/ {next} $1=="boot"{print}' "$CONF" |
while IFS='|' read -r _p s w cmd; do
s="${s:-tm0}"; ensure_session "$s"
if [ -z "${cmd:-}" ]; then [ -n "${w:-}" ] && ensure_window "$s" "$w"; continue; fi
if [ "$s" = "tm0" ]; then
[ -n "${w:-}" ] && "$TMUX_BIN" "${TMUXS[@]}" rename-window -t tm0:0 "$w" 2>/dev/null || true
run_in_window_shell "tm0:0" "$cmd"
else
if [ -n "${w:-}" ]; then
ensure_window "$s" "$w"; run_in_window_shell "$s:$w" "$cmd"
else
run_in_window_shell "$s:0" "$cmd" # :0 wiederverwenden (kein "auto")
fi
fi
done
}
find_latest_xauth() { ls -t /run/user/*/xauth_* 2>/dev/null | head -n1 || true; }
wait_for_display_and_inject() {
local xauth disp cookie_dir
log "waiting for display (any /run/user/*/xauth_*)…"
while true; do
xauth="$(find_latest_xauth)"
if [ -n "${xauth:-}" ] && [ -s "$xauth" ]; then
disp="$(xauth -f "$xauth" list 2>/dev/null | awk '{ if (match($0,/unix:([0-9]+)/)) {n=substr($0,RSTART+5,RLENGTH-5); print ":" n; exit} if (match($0,/:([0-9]+)/)) {n=substr($0,RSTART+1,RLENGTH-1); print ":" n; exit} }')"
if [ -n "${disp:-}" ]; then
cookie_dir="$(dirname "$xauth")"
"$TMUX_BIN" "${TMUXS[@]}" set-environment -g XAUTHORITY "$xauth"
"$TMUX_BIN" "${TMUXS[@]}" set-environment -g DISPLAY "$disp"
"$TMUX_BIN" "${TMUXS[@]}" set-environment -g XDG_RUNTIME_DIR "$cookie_dir"
export XAUTHORITY="$xauth" DISPLAY="$disp" XDG_RUNTIME_DIR="$cookie_dir"
log "injected DISPLAY=$disp, XAUTHORITY=$xauth, XDG_RUNTIME_DIR=$cookie_dir"
return 0
fi
fi
sleep 2
done
}
set_xkb_for_xwayland() {
command -v setxkbmap >/dev/null 2>&1 || return 0
local cur_layout cur_variant
cur_layout="$(setxkbmap -query 2>/dev/null | awk '/^layout:/ {print $2}')"
cur_variant="$(setxkbmap -query 2>/dev/null | awk '/^variant:/ {print $2}')"
if [ "$cur_layout" != "de" ] || [ "${cur_variant:-}" != "nodeadkeys" ]; then
setxkbmap -layout de -variant nodeadkeys 2>/dev/null || true
log "setxkbmap de nodeadkeys"
fi
}
run_phase_display() {
[[ -f "$CONF" ]] || return 0
awk -F '|' '/^[[:space:]]*#/ || /^[[:space:]]*$/ {next} $1=="display"{print}' "$CONF" |
while IFS='|' read -r _p s w cmd; do
s="${s:-tm0}"; ensure_session "$s"
if [ -z "${w:-}" ]; then w=""; fi
if [ -z "${cmd:-}" ]; then
if [ -n "$w" ]; then ensure_window "$s" "$w"; fi
continue
fi
if [ -n "$w" ]; then
ensure_window "$s" "$w"; run_in_window_shell "$s:$w" "$cmd"
else
run_in_window_shell "$s:0" "$cmd"
fi
done
}
log "start (boot phase)"; run_phase_boot
log "wait/display phase"; wait_for_display_and_inject
set_xkb_for_xwayland
run_phase_display
log "done"; exit 0
2.4 Beispiel-Config (root)
/root/.config/tmux/autostart.conf
# phase|session|window|command
boot|tm11||cd /etc/JJ_SystemMetric/; source /etc/JJ_SystemMetric/.venv/bin/activate && python3 /etc/JJ_SystemMetric/Version_0.19__Start_SystemMetric.py
boot|tm12||cd /home/jj/OpenVPN/Schneider.land
boot|tm13||cd /home/jj/Cronjob/ntfy/; python3 /home/jj/Cronjob/ntfy/Version_0.13__ntfy.py
2.5 Rechte & Start
sudo chmod 0755 /root/.config/tmux/orchestrator.sh
sudo systemctl --user daemon-reload
sudo systemctl --user enable --now tmux-autostart.service
# prüfen:
sudo tmux -S /run/user/0/tmux-0/default ls
3) Nutzung & Beispiele
- Nur Verzeichnis setzen:
display|tm12||cd /pfad(Fenster:0bleibt, kein zweites Fenster) - Fenster benennen:
display|tm8|vpn|cd /home/jj/OpenVPN/Schneider.land - Direkt Programm starten:
display|tm11|metric|cd /etc/JJ_SystemMetric/; source .venv/bin/activate && python3 run.py
4) Troubleshooting
- jj: kein Socket:
sudo -u jj tmux -S /run/user/1000/tmux-1000/default ls– sofern leer:journalctl --user -u tmux-autostart.service -n100 -o cat - root: unsafe permissions: wird durch die Unit via
install -d -m 0700behoben. Manuell:chmod 0700 /run/user/0 /run/user/0/tmux-0 - Reset aller Sessions (jj):
sudo -u jj tmux -S /run/user/1000/tmux-1000/default kill-server || true - Reset aller Sessions (root):
sudo tmux -S /run/user/0/tmux-0/default kill-server || true
5) Sicherheitshinweis (root → User-Display)
Root nutzt das Xauth-Cookie der eingeloggten Nutzersitzung, um X/Wayland-Apps an diese Session anzubinden. Das ist üblich, aber beachte die Sicherheitsimplikationen (root erhält Display-Zugriff). Kein xhost + nötig.
6) Deinstallation
# jj
sudo -u jj systemctl --user disable --now tmux-autostart.service
sudo rm -f /home/jj/.config/systemd/user/tmux-autostart.service /home/jj/.config/tmux/orchestrator.sh
# root
sudo systemctl --user disable --now tmux-autostart.service
sudo rm -f /root/.config/systemd/user/tmux-autostart.service /root/.config/tmux/orchestrator.sh
Linux - Angemeldete User
Diese Anleitung zeigt, wie man auf einem Debian-Server:
- aktive Logins anzeigt,
- die Art der Anmeldung erkennt (z. B. SSH, TTY),
- und Benutzer-Sessions gezielt trennt („kicken“).
su -).1. Aktive Benutzer anzeigen
1.1 Schnellübersicht mit who
Der Befehl who zeigt, wer aktuell eingeloggt ist.
who
Typische Ausgabe:
user1 pts/0 2025-12-02 10:15 (192.168.1.10)
user2 pts/1 2025-12-02 10:20 (10.0.0.5)
- user1 / user2: Benutzername
- pts/0, pts/1: Terminal (Pseudo-Terminal, meistens SSH)
- Datum/Uhrzeit: Zeitpunkt der Anmeldung
- IP/Hostname: Quelle der Verbindung
1.2 Detailansicht mit w
w liefert zusätzlich, was die Benutzer gerade tun.
w
Typische Ausgabe (Beispiel gekürzt):
10:25:01 up 10 days, 3:12, 2 users, load average: 0.00, 0.01, 0.05
USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT
user1 pts/0 192.168.1.10 10:15 2:00 0.01s 0.01s -bash
user2 pts/1 10.0.0.5 10:20 0.00s 0.02s 0.00s sshd: user2@pts/1
1.3 Nur Benutzernamen mit users
Wenn nur eine schnelle Liste der angemeldeten Benutzer benötigt wird:
users
2. Anmelde-Historie anzeigen
2.1 Letzte Logins mit last
last liest /var/log/wtmp und zeigt vergangene Logins und Logouts.
last
Beispielausgabe:
user1 pts/0 192.168.1.10 Tue Dec 2 10:15 still logged in
user2 pts/1 10.0.0.5 Tue Dec 2 10:20 - 10:30 (00:10)
reboot system boot 5.10.0-xx Mon Dec 1 09:00 still running
Mit zusätzlicher Anzeige der IP/Hostname am Ende:
last -a
2.2 Übersicht über alle Benutzer mit lastlog
Alle Benutzer und deren letzten Login:
lastlog
Damit lassen sich z. B. inaktive Accounts erkennen.
3. SSH-Logins über Logdateien prüfen
SSH-Anmeldungen werden auf Debian typischerweise in /var/log/auth.log protokolliert.
3.1 Aktuelle SSH-Sessions und Logins anzeigen
Nur die Zeilen mit geöffneten Sessions anzeigen:
grep "session opened for user" /var/log/auth.log
Nur fehlgeschlagene SSH-Logins anzeigen:
grep "Failed password" /var/log/auth.log
3.2 Live-Monitoring von SSH-Anmeldungen
Neue SSH-Einträge fortlaufend beobachten:
tail -f /var/log/auth.log
Oder mit journalctl (bei systemd):
journalctl -u ssh -f
4. Benutzer-Sessions gezielt trennen („kicken“)
4.1 Session über Terminal (TTY/PTS) beenden
1. Zuerst das Terminal des Benutzers ermitteln, z. B. mit who:
who
Beispiel:
user1 pts/0 2025-12-02 10:15 (192.168.1.10)
Hier ist das Terminal pts/0.
2. Session über dieses Terminal beenden:
pkill -KILL -t pts/0
-KILL: sendet das SIGKILL-Signal (sofortiges Beenden)-t pts/0: Ziel ist das Terminalpts/0
Nach diesem Befehl wird der Benutzer user1 von diesem Terminal abgemeldet.
4.2 Session über loginctl beenden (systemd)
Auf systemd-basierten Systemen (aktuelles Debian) können Sessions mit loginctl verwaltet werden.
4.2.1 Sessions anzeigen
loginctl list-sessions
Beispielausgabe:
SESSION UID USER SEAT TTY
2 1000 user1 pts/0
3 1001 user2 pts/1
4.2.2 Einzelne Session beenden
Um z. B. Session 2 zu beenden:
loginctl terminate-session 2
4.2.3 Alle Sessions eines Benutzers beenden
Um alle Sessions des Benutzers user1 zu beenden:
loginctl kill-user user1
5. Welche Art von Anmeldung liegt vor?
Über die Ausgabe von w, who und die Logs lässt sich die Art der Anmeldung erkennen:
- SSH: TTY beginnt meist mit
pts/und FROM ist eine IP/Hostname. - Lokale Konsole: TTY wie
tty1, FROM oft leer oder:. - Andere Dienste: z. B. SFTP, je nach Konfiguration teilweise nur in Logs sichtbar.
Über die Logdatei /var/log/auth.log sieht man zudem genau:
- Von welcher IP ein Login kommt,
- ob der Login erfolgreich war,
- wann eine Session geöffnet oder geschlossen wurde.
6. Praxis-Beispiele
6.1 Alle aktuell eingeloggten Benutzer anzeigen
who
w
6.2 Historie der Logins eines bestimmten Benutzers
Beispielsweise für den Benutzer user1:
last user1
6.3 Alle fehlgeschlagenen SSH-Logins anzeigen
grep "Failed password" /var/log/auth.log
6.4 Bestimmten SSH-Benutzer sofort trennen
Beispiel: user1 ist auf pts/0 eingeloggt.
who
pkill -KILL -t pts/0
7. Zusammenfassung
who,w,users: aktuelle Loginslast,lastlog: Login-Historie/var/log/auth.logundjournalctl -u ssh: Details zu SSH-Loginspkill -KILL -t <tty>: einzelne Session über Terminal beendenloginctl terminate-session/loginctl kill-user: Sessions über systemd verwalten
Mit diesen Befehlen lassen sich Benutzeraktivitäten auf einem Debian-Server nachvollziehen und bei Bedarf Sessions gezielt trennen.
Linux - VNC/RDP
Debian 13 + XRDP + KDE Plasma (X11) – Basic Setup
- KDE Plasma mit Wayland für die lokale Anmeldung auf der VM installieren.
- XRDP einrichten und sich anschließend per
xfreerdp3mit der VM verbinden.
Anleitung 1 ausklappen: KDE Plasma Wayland auf Debian 13 installieren
Anleitung 1: KDE Plasma Wayland auf Debian 13 installieren
Diese Anleitung installiert KDE Plasma mit Wayland-Unterstützung für die lokale Anmeldung an der VM.
sudo verwendet.1. Paketquellen aktualisieren
apt update
2. KDE Plasma mit Wayland-Unterstützung und Display-Manager installieren
apt install -y plasma-desktop plasma-workspace sddm dbus-x11 kwin-x11
plasma-workspace-wayland nicht mehr separat verwendet. Die benötigten Wayland-Komponenten sind über plasma-workspace abgedeckt.plasma-desktop installiert eine relativ schlanke KDE-Plasma-Umgebung. Wer später ein größeres KDE-Setup möchte, kann zusätzlich kde-standard oder kde-full installieren.3. SDDM aktivieren
SDDM ist der Login-Manager für die grafische Anmeldung.
systemctl enable sddm
4. Grafischen Startmodus aktivieren
systemctl set-default graphical.target
5. System neu starten
reboot
6. Bei KDE Plasma Wayland anmelden
Nach dem Neustart erscheint der grafische Login-Bildschirm.
Wähle dort vor dem Login als Sitzung:
Plasma (Wayland)
Anleitung 2 ausklappen: Per XRDP und xfreerdp3 auf die VM zugreifen
Anleitung 2: Per XRDP und xfreerdp3 auf die VM zugreifen
Diese Anleitung richtet XRDP auf der VM ein und zeigt danach die Verbindung mit xfreerdp3 vom Client aus.
1. XRDP und Xorg-Backend installieren
Auf der VM als root ausführen:
apt update
apt install -y xrdp xorgxrdp dbus-x11
plasma-desktop und plasma-workspace hier nicht erneut installiert werden.2. XRDP-Startscript für KDE Plasma X11 setzen
Bearbeite die Datei:
/etc/xrdp/startwm.sh
Ersetze den kompletten Inhalt durch:
#!/bin/sh
unset DBUS_SESSION_BUS_ADDRESS
unset XDG_RUNTIME_DIR
export XDG_SESSION_TYPE=x11
export KDE_FULL_SESSION=true
export QT_QPA_PLATFORM=xcb
export QT_QUICK_BACKEND=software
export LIBGL_ALWAYS_SOFTWARE=1
export KWIN_COMPOSE=N
export KWIN_NO_COMPOSITING=1
exec dbus-run-session -- startplasma-x11
3. Startscript ausführbar machen
chmod +x /etc/xrdp/startwm.sh
4. XRDP-Dienste aktivieren und starten
systemctl enable --now xrdp xrdp-sesman
5. IP-Adresse der VM anzeigen
Auf der VM ausführen:
hostname -I
Merke dir die passende IP-Adresse der VM. Diese wird später bei xfreerdp3 als SERVER-IP verwendet.
6. Benutzer für die RDP-Anmeldung verwenden
jj.Falls noch kein normaler Benutzer vorhanden ist, kann einer angelegt werden:
adduser jj
7. FreeRDP-Client installieren
Auf dem Linux-Client ausführen, von dem aus du dich zur VM verbinden möchtest:
apt update
apt install -y freerdp3-x11
8. Verbindung zur VM herstellen
Auf dem Client ausführen:
xfreerdp3 /v:SERVER-IP:3389 /u:jj /d:. /dynamic-resolution /clipboard /cert:tofu
Beispiel:
xfreerdp3 /v:192.168.178.50:3389 /u:jj /d:. /dynamic-resolution /clipboard /cert:tofu
9. Bedeutung der wichtigsten Optionen
/v:SERVER-IP:3389verbindet sich mit der VM auf Port3389./u:jjverwendet den Benutzerjj./d:.bedeutet: keine Domain verwenden./dynamic-resolutionpasst die Auflösung beim Vergrößern oder Verkleinern des Fensters an./clipboardaktiviert Copy/Paste zwischen Client und RDP-Sitzung./cert:tofumerkt sich das Zertifikat beim ersten Verbindungsaufbau.
10. Security-Basics
3389 sollte nur im lokalen Netzwerk, über VPN oder über einen sicheren Tunnel erreichbar sein.- Kein Root-Login per RDP.
- Starke Passwörter verwenden.
- Port
3389nicht öffentlich ins Internet freigeben. - Wenn möglich nur Zugriff aus dem internen Netz erlauben.
- System regelmäßig aktualisieren.
11. Typische Stolpersteine
XRDP zeigt keinen KDE-Desktop
Prüfe, ob die Dienste laufen:
systemctl status xrdp
systemctl status xrdp-sesman
Keine Fensterleisten oder Fenster lassen sich nicht verschieben
Dann läuft KWin wahrscheinlich nicht sauber oder Compositing stört die XRDP-Sitzung.
Das Startscript aus dieser Anleitung deaktiviert Compositing bereits für die XRDP-Sitzung:
export KWIN_COMPOSE=N
export KWIN_NO_COMPOSITING=1
Danach XRDP neu starten:
systemctl restart xrdp xrdp-sesman
Panel ist schwarz oder Transparenzen sehen kaputt aus
Das kann durch deaktiviertes Compositing passieren. Für XRDP ist das meist der stabilere Weg.
Mögliche Lösung:
- Panel auf undurchsichtig stellen.
- Ein Theme ohne starke Transparenzen verwenden.
- XRDP-Sitzung weiterhin als X11 laufen lassen.
Zusammenfassung
- Lokale Anmeldung: KDE Plasma Wayland über SDDM.
- Remote-Zugriff per XRDP: KDE Plasma X11 über
startplasma-x11. - Client: Verbindung mit
xfreerdp3.
Linux Server
Linux - ZRAM
Linux - ZRAM Config
Ziel: ZRAM als schnellen Swap einrichten (komprimierter RAM statt SSD/HDD), passende Größe für 2 GB bis 128 GB RAM wählen, Prioritäten korrekt setzen, Latenz/CPU-Last sauber austarieren, Verifikation & Monitoring verstehen.
Voraussetzung: Die Installations-/Systemänderungsbefehle erfordern Root-Rechte (z. B. via Root-Shell). Reine Anzeige-/Monitoring-Befehle funktionieren auch als normaler Nutzer.
Inhalt
- Grundidee: Was ist ZRAM und wofür nutzt man es?
- Quick-Check: Ist ZRAM aktiv und sinnvoll priorisiert?
- Sizing: Empfehlungen von 2 GB bis 128 GB RAM
- Kompressions-Algorithmen:
lz4vs.zstd(und warum) - Installation (Debian/Ubuntu)
- Konfiguration: systemd-zram-generator (empfohlen)
- Konfiguration: zram-tools (Alternative)
- VM-/Kernel-Tuning: warum diese sysctl-Werte?
- Disk-Swap: wann, warum, Priorität
- Verifizieren & Monitoring (inkl. PSI)
- Rollback: wie man es sauber rückgängig macht
Grundidee: Was ist ZRAM und wofür nutzt man es?
- ZRAM erstellt ein Blockdevice im RAM (z. B.
/dev/zram0), das komprimiert wird und als Swap dienen kann. - Warum? Wenn RAM knapp wird, landen selten genutzte Speicherseiten im Swap. Mit ZRAM passiert das im RAM (schnell), statt auf SSD/HDD (langsam, verschleißfördernd).
- Trade-off: Kompression braucht CPU. Je nach Workload ist weniger CPU-Last wichtiger als maximale Kompression.
Merke: ZRAM ist ein Puffer gegen Speicherpeaks und OOM, kein Ersatz für realistischen RAM-Bedarf.
Quick-Check: Ist ZRAM aktiv und sinnvoll priorisiert?
Kommandos
swapon --show
free -h
zramctl
cat /sys/block/zram0/mm_stat
cat /proc/pressure/memory
Warum genau diese Befehle?
swapon --show- Zeigt aktive Swap-Geräte (ZRAM und ggf. Disk-Swap), inkl. Größe, Nutzung und Priorität. Wichtigster Punkt: ZRAM sollte eine höhere Priorität haben als Disk-Swap, damit zuerst der schnelle komprimierte RAM genutzt wird.
free -h- Gibt eine grobe Übersicht über RAM/Swap. Besonders relevant ist verfügbar: das ist die Menge RAM, die ohne massiven Stress freigemacht werden kann (Cache wird dabei mitgedacht). Unterschied zu swapon:
freezeigt Gesamtbild,swaponzeigt Swap-Details. zramctl- Zeigt ZRAM-spezifische Infos: Algorithmus, virtuelle Disksize, sowie wieviel unkomprimierte Daten im ZRAM liegen und wieviel realer RAM dafür belegt wird. Unterschied zu free:
freesieht nur „Swap belegt“,zramctlzeigt die Kompressionswirkung. cat /sys/block/zram0/mm_stat- Detail-Statistiken aus dem Kernel: u. a. wieviel Daten im ZRAM liegen und wie effektiv komprimiert wird. Gut, um einzuschätzen, ob z. B.
zstdwirklich einen Vorteil bringt oder nur CPU verbrennt. cat /proc/pressure/memory- PSI (Pressure Stall Information) zeigt, ob Prozesse messbar auf Speicher warten mussten. Warum das wichtig ist: Ruckler, Audio-Aussetzer und „alles zäh“ korrelieren oft eher mit PSI als mit „Swap ist voll“.
Sizing: Empfehlungen von 2 GB bis 128 GB RAM
Regel: Wenig RAM → aggressiver (mehr ZRAM), viel RAM → moderater (ZRAM als Sicherheitsnetz). Ziel ist weniger OOM und weniger Disk-Swap, nicht „unendlich Tabs durch Kompression“.
| RAM | ZRAM-Größe (Richtwert) | Warum gerade so? | Typische Nutzung |
|---|---|---|---|
| 2 GB | 75–100% (1.5–2 GB) | Ohne Puffer kommt es schnell zu OOM. ZRAM schafft Luft, ohne Disk-I/O. | Minimal-Desktop, kleine Server, VMs |
| 4 GB | 75–100% (3–4 GB) | Hier bringt ZRAM oft den größten „Feeling“-Gewinn: weniger harte Memory-Kanten. | Browser/Office/kleine Tools |
| 8 GB | ~75% (6 GB) | Genug, um Peaks abzufedern, ohne zu viel in Swap zu driften. | Allround-Desktop |
| 16 GB | 60–75% (10–12 GB) | Guter Sweet Spot: ZRAM ist Reserve, aber RAM bleibt Hauptarbeitsfläche. | IDE/Browser/leichte VMs |
| 32 GB | 50–75% (16–24 GB) | Bei Tab/IDE/Meetings hilft mehr ZRAM, Disk-Swap zu vermeiden. | Heavy Desktop/Workstation |
| 64 GB | 40–50% (24–32 GB) | Mehr RAM → ZRAM wird seltener gebraucht, sollte aber Peaks fangen. | Builds, VMs, Containers |
| 128 GB | 25–40% (32–48 GB) | ZRAM als Sicherheitsnetz. Zu groß kann „Swap-Gewohnheiten“ fördern. | Große Workstations/Server |
Merke: ZRAM „Disksize“ ist virtuell. Realer RAM wird erst belegt, wenn Seiten wirklich im ZRAM landen. Trotzdem beeinflusst großer ZRAM die Swap-Strategie des Systems, deshalb bei sehr viel RAM moderater bleiben.
Kompressions-Algorithmen: lz4 vs. zstd
| Algorithmus | Stärke | Schwäche | Wann nehmen? |
|---|---|---|---|
lz4 |
Sehr niedrige CPU-Last, geringe Latenz | Weniger Kompression (mehr RAM-Verbrauch pro Swap-Seite) | Meetings/Audio/Low-Latency wichtig, schwächere CPU, Desktop „smooth“ |
zstd |
Sehr gute Kompression (mehr „virtueller RAM“) | Höhere CPU-Last als lz4 | Viele Daten/Tabs/IDE/VMs und CPU ist nicht der Engpass |
Merke: Wenn PSI/Audio-Ruckler dein Problem sind, ist lz4 oft die bessere Wahl. Wenn OOM/disk-swap dein Problem sind, bringt zstd oft mehr Nutzwert.
Installation (Debian & Ubuntu)
Option A (empfohlen): systemd-zram-generator
apt update
apt install -y systemd-zram-generator
apt update- Aktualisiert Paketlisten. Unterschied zu install: ohne frische Listen kann
aptalte Versionen/Abhängigkeiten sehen oder Pakete nicht finden. apt install -y systemd-zram-generator- Installiert den Generator, der beim Booten ZRAM-Devices nach Konfig erzeugt. Warum das bevorzugt ist: saubere systemd-Integration, klare Konfigdatei, gut wartbar. Das
-ybeantwortet die Rückfrage automatisch (nützlich für Copy/Paste, weniger nützlich für Menschen, die gern überraschende Dinge abbrechen).
Option B (Alternative): zram-tools
apt update
apt install -y zram-tools
apt install -y zram-tools- Installiert ein klassisches Setup-Skript/Service für ZRAM-Swap. Unterschied zu Option A: funktioniert oft okay, aber weniger flexibel und weniger „systemd-nativ“.
Konfiguration: systemd-zram-generator (empfohlen)
Datei: /etc/systemd/zram-generator.conf
Konfig-Snippets nach RAM-Klasse
2–4 GB RAM (maximaler Puffer, geringe CPU-Last)
[zram0]
zram-size = ram * 1.0
compression-algorithm = lz4
swap-priority = 100
Warum: Bei Low-RAM ist OOM die größte Gefahr. lz4 hält CPU-Latenz klein, während 100% ZRAM die Überlebenschancen erhöht.
8–16 GB RAM (Allround)
[zram0]
zram-size = ram * 0.75
compression-algorithm = zstd
swap-priority = 100
Warum: 75% ist ein guter Kompromiss. zstd holt mehr Effekt aus dem ZRAM heraus, weil hier oft viele ähnliche Seiten anfallen (Browser/IDE).
32 GB RAM (Heavy Desktop/Workstation)
[zram0]
zram-size = ram * 0.60
compression-algorithm = zstd
swap-priority = 100
Warum: Genug ZRAM als Reserve, aber nicht so viel, dass das System „Swap ist ja da“ als Einladung versteht.
64–128 GB RAM (Sicherheitsnetz, Latenz wichtiger)
[zram0]
zram-size = ram * 0.35
compression-algorithm = lz4
swap-priority = 100
Warum: Bei viel RAM sind harte Peaks seltener. Wenn doch, willst du glatte Latenz statt maximale Ratio. Daher moderater Size + lz4.
Konfig anwenden
systemctl daemon-reload
systemctl restart systemd-zram-setup@zram0.service
systemctl daemon-reload- Lädt systemd-Konfiguration neu ein. Warum: systemd merkt sich Units/Generator-Ergebnisse; ohne Reload kann eine Änderung wirkungslos bleiben. Unterschied zu restart: Reload aktualisiert systemd selbst, Restart startet nur den Dienst neu.
systemctl restart systemd-zram-setup@zram0.service- Initialisiert/konfiguriert
zram0neu. Warum: Wendet neue ZRAM-Größe/Algorithmus an, ohne Neustart. Wenn die Unit anders heißt:systemctl list-units --type=service --allnutzen und im Pager nach „zram“ suchen.
Konfiguration: zram-tools (Alternative)
Datei: /etc/default/zramswap
Beispiele (mit Begründung)
# 2 GB RAM
ALGO=lz4
PERCENT=100
PRIORITY=100
# 8 GB RAM
# ALGO=zstd
# PERCENT=75
# PRIORITY=100
# 32 GB RAM
# ALGO=zstd
# PERCENT=60
# PRIORITY=100
# 128 GB RAM
# ALGO=lz4
# PERCENT=35
# PRIORITY=100
ALGO- Legt den Kompressionsalgorithmus fest.
lz4ist latenzfreundlicher,zstdkomprimiert besser. Unterschied: CPU vs. Kompressionsrate (siehe Tabelle oben). PERCENT- Prozentualer Anteil des RAM, der als ZRAM-Disksize verwendet wird. Warum: Steuert, wie viel „Reserve“ du hast. Unterschied zu systemd-zram-generator: Dort nutzt man meist Formeln (
ram * 0.75) statt Prozent-Integer. PRIORITY- Swap-Priorität für ZRAM. Warum: ZRAM soll vor Disk-Swap drankommen. Priorität ist der zentrale Mechanismus, um die Reihenfolge zu erzwingen.
Konfig anwenden
systemctl restart zramswap.service
systemctl restart zramswap.service- Startet den ZRAM-Swap-Dienst neu, damit
ALGO/PERCENT/PRIORITYneu gesetzt werden. Unterschied zudaemon-reload: hier wird nur der Service neu gestartet, nicht systemd selbst.
VM-/Kernel-Tuning: warum diese sysctl-Werte?
Datei: /etc/sysctl.d/99-zram-tuning.conf
Empfohlene Werte (Desktop/Allround)
vm.swappiness=100
vm.page-cluster=0
vm.vfs_cache_pressure=50
vm.dirty_background_ratio=5
vm.dirty_ratio=15
Warum genau diese Werte?
vm.swappiness=100- Erlaubt dem Kernel, eher zu swappen. Warum sinnvoll mit ZRAM: Swap ist hier schnell, weil er im RAM liegt. Unterschied zu klassischem Disk-Swap: Bei SSD/HDD wäre ein hoher Wert oft fühlbar langsamer.
vm.page-cluster=0- Beeinflusst, wie viele Swap-Seiten auf einmal read-ahead geladen werden. Warum 0: Bei ZRAM ist Read-ahead oft kein Gewinn und kann Latenzspitzen erzeugen, weil unnötig viel dekomprimiert wird.
vm.vfs_cache_pressure=50- Steuert, wie aggressiv der Kernel Dentry/Inode-Caches verwirft. Warum niedriger: Desktop-Workloads profitieren davon, wenn Metadaten-Caches länger bleiben (Dateibrowser, IDE, viele kleine Files).
vm.dirty_background_ratio=5undvm.dirty_ratio=15- Steuert, wie viel „dirty“ (noch nicht auf Disk geschriebener) Cache erlaubt ist, bevor Writeback startet bzw. blockiert. Warum niedriger: verhindert große, plötzliche Schreib-Spikes, die Audio/Video und Interaktivität stören können. Unterschied: background startet früher sanften Writeback, dirty_ratio ist der harte Deckel.
Aktivieren
sysctl --system
sysctl --system- Lädt alle sysctl-Konfigurationen neu (u. a. aus
/etc/sysctl.d/). Unterschied zu Neustart: wirkt sofort, ohne Boot.
Disk-Swap: wann, warum, Priorität
- Warum Disk-Swap behalten? Als letzte Rettung bei extremen Peaks oder Memory-Leaks. ZRAM kann voll laufen.
- Warum Disk-Swap niedrig priorisieren? Damit zuerst ZRAM genutzt wird (schneller, weniger I/O, weniger Verschleiß).
- Hibernate: Wenn du Hibernate nutzen willst, brauchst du Swap auf Disk in passender Größe. ZRAM ist flüchtig.
Priorität für Disk-Swap via /etc/fstab (Beispiel)
# Beispiel-Zeile (Device/UUID an dein System anpassen):
/dev/dm-2 none swap sw,pri=-2 0 0
Warum: pri=-2 sorgt dafür, dass Disk-Swap erst genutzt wird, wenn ZRAM nicht reicht. Unterschied zu Default: ohne explizite Prio kann die Reihenfolge je nach Setup weniger klar sein.
Verifizieren & Monitoring (inkl. PSI)
Kommandos
swapon --show
zramctl
free -h
cat /proc/pressure/memory
Wie interpretiert man das?
- ZRAM benutzt, Disk-Swap 0: Idealfall. Das bedeutet: schneller Swap-Puffer wird genutzt, Disk bleibt ruhig.
- ZRAM voll + Disk-Swap steigt: ZRAM zu klein oder Workload zu speicherhungrig. Dann Disk-Swap als Notfall aktiv, aber das System kann zäher werden.
- PSI memory steigt (avg10/60/300): Messbare Memory-Stalls. Das korreliert oft direkt mit „Ruckeln“. Dann sind Algorithmus (
lz4) undpage-cluster=0oft wichtiger als noch mehr ZRAM-Größe.
Rollback: wie man es sauber rückgängig macht
systemd-zram-generator
# Konfig entfernen oder auskommentieren:
# /etc/systemd/zram-generator.conf
systemctl daemon-reload
# Danach Neustart oder erneutes Initialisieren, je nach Setup/Unit-Namen.
Warum: Entfernst du die Generator-Konfig, wird beim nächsten Setup kein ZRAM mehr erstellt. Unterschied zu „swapoff“: hier wird die Ursache (Auto-Setup) entfernt, nicht nur temporär deaktiviert.
zram-tools
systemctl disable --now zramswap.service
systemctl disable --now zramswap.service--nowstoppt sofort,disableverhindert Autostart beim Boot. Unterschied zustop:stopist nur temporär,disableist dauerhaft.
WireGuard
WireGuard auf Server und Client einrichten
Diese Anleitung beschreibt die Installation und Grundkonfiguration von WireGuard auf einem Debian-Server und einem Debian-Client. Das Beispiel verwendet einen WireGuard-Server auf UDP Port 443 und das interne VPN-Netz 172.31.255.224/27.
Verwendete Beispielwerte
- Öffentliche IPv4 des Servers:
DEINE_VPS_IP - WireGuard-Port:
443/UDP - VPN-Subnetz:
172.31.255.224/27 - Server-IP im Tunnel:
172.31.255.254/27 - Client 1 im Tunnel:
172.31.255.253/32
1. WireGuard auf dem Server installieren
Auf dem Server werden die benötigten Pakete installiert und das Verzeichnis für die Konfiguration vorbereitet.
apt update
apt install -y wireguard-tools
install -d -m 700 /etc/wireguard
cd /etc/wireguard
umask 077
2. Schlüssel auf dem Server erzeugen
Der Server benötigt ein Schlüsselpaar. Zusätzlich wird für jeden Client ein eigener PresharedKey erzeugt.
wg genkey | tee server.key | wg pubkey | tee server.pub >/dev/null
wg genpsk | tee client1.psk >/dev/null
chmod 600 /etc/wireguard/server.key /etc/wireguard/client1.psk
chmod 644 /etc/wireguard/server.pub
3. Server-Konfiguration erstellen
Die Datei /etc/wireguard/wg0.conf wird auf dem Server angelegt.
nano /etc/wireguard/wg0.conf
Beispielinhalt:
[Interface]
Address = 172.31.255.254/27
ListenPort = 443
PrivateKey = SERVER_PRIVATE_KEY
SaveConfig = false
# Client 1
[Peer]
PublicKey = CLIENT1_PUBLIC_KEY
PresharedKey = CLIENT1_PRESHARED_KEY
AllowedIPs = 172.31.255.253/32
Dabei müssen die Platzhalter ersetzt werden:
SERVER_PRIVATE_KEYmit dem Inhalt von/etc/wireguard/server.keyCLIENT1_PUBLIC_KEYmit dem Public Key des ClientsCLIENT1_PRESHARED_KEYmit dem Inhalt von/etc/wireguard/client1.psk
Für jeden weiteren Client wird ein zusätzlicher [Peer]-Block mit eigener Client-IP, eigenem Public Key und eigenem Preshared Key ergänzt. Beispiel:
# Client 2
[Peer]
PublicKey = CLIENT2_PUBLIC_KEY
PresharedKey = CLIENT2_PRESHARED_KEY
AllowedIPs = 172.31.255.252/32
4. WireGuard-Port in der Firewall freigeben
Damit Clients den Server erreichen können, muss der verwendete UDP-Port offen sein. In diesem Beispiel ist das 443/UDP.
- Server:
443/UDPeingehend erlauben - Client: keine eingehende Freigabe nötig
- Wichtig: Wenn beim Hoster eine zusätzliche Firewall aktiv ist, muss dort ebenfalls
443/UDPerlaubt werden
5. WireGuard auf dem Server starten
Nach dem Speichern der Konfiguration wird das Interface gestartet und beim Booten aktiviert.
systemctl enable --now wg-quick@wg0
systemctl status wg-quick@wg0 --no-pager
wg show
Falls die Konfigurationsdatei später geändert wird, muss der Dienst neu geladen werden:
systemctl restart wg-quick@wg0
wg show
6. WireGuard auf dem Client installieren
Auch auf dem Client wird zunächst WireGuard installiert und das Konfigurationsverzeichnis angelegt.
apt update
apt install -y wireguard-tools
install -d -m 700 /etc/wireguard
cd /etc/wireguard
umask 077
7. Schlüssel auf dem Client erzeugen
Der Client erzeugt sein eigenes Schlüsselpaar lokal. Der Private Key bleibt nur auf dem Client.
wg genkey | tee client1.key | wg pubkey | tee client1.pub >/dev/null
chmod 600 /etc/wireguard/client1.key
chmod 644 /etc/wireguard/client1.pub
Der Public Key des Clients kann angezeigt werden mit:
cat /etc/wireguard/client1.pub
Dieser Public Key wird anschließend in die Server-Konfiguration im passenden [Peer]-Block eingetragen.
8. Client-Konfiguration erstellen
Die Datei /etc/wireguard/wg0.conf auf dem Client anlegen:
nano /etc/wireguard/wg0.conf
Beispielinhalt für Client 1:
[Interface]
Address = 172.31.255.253/32
PrivateKey = CLIENT1_PRIVATE_KEY
[Peer]
PublicKey = SERVER_PUBLIC_KEY
PresharedKey = CLIENT1_PRESHARED_KEY
Endpoint = DEINE_VPS_IP:443
AllowedIPs = 172.31.255.254/32
PersistentKeepalive = 25
Platzhalter ersetzen:
CLIENT1_PRIVATE_KEYmit dem Inhalt von/etc/wireguard/client1.keySERVER_PUBLIC_KEYmit dem Inhalt von/etc/wireguard/server.pubCLIENT1_PRESHARED_KEYmit dem Preshared Key aus/etc/wireguard/client1.pskvom ServerDEINE_VPS_IPmit der öffentlichen IPv4-Adresse des Servers
In diesem Beispiel erlaubt AllowedIPs = 172.31.255.254/32 nur den Zugriff auf die Tunnel-IP des Servers. Der gesamte Internetverkehr des Clients wird dadurch nicht automatisch über WireGuard geleitet.
9. Verbindung auf dem Client starten
Zum Testen wird das Interface zunächst manuell gestartet.
wg-quick up wg0
Status prüfen:
wg show
ip addr show wg0
ping -c 3 172.31.255.254
Verbindung wieder beenden:
wg-quick down wg0
Wenn alles funktioniert, kann WireGuard dauerhaft aktiviert werden:
systemctl enable --now wg-quick@wg0
systemctl status wg-quick@wg0 --no-pager
wg show
10. Weitere Clients hinzufügen
Für jeden weiteren Client werden dieselben Schritte wiederholt:
- Auf dem Client eigenes Schlüsselpaar erzeugen
- Auf dem Server einen eigenen
PresharedKeyerzeugen - Auf dem Server einen neuen
[Peer]-Block anlegen - Dem Client eine eigene feste Tunnel-IP geben
- Server-Dienst nach Änderungen neu starten
Beispiel für Client 2:
- Client 2 IP:
172.31.255.252/32 - Server Peer AllowedIPs:
172.31.255.252/32
11. Typische Fehlerquellen
- Server-Konfiguration geändert, aber
systemctl restart wg-quick@wg0vergessen - Falsche Tunnel-IP angepingt
- Falscher oder vertauschter Public/Private Key
- Falscher oder fehlender
PresharedKey 443/UDPbeim Hoster oder auf dem Server nicht freigegeben- Falsche öffentliche IPv4 im
Endpoint
12. Kurzfassung
- Server installieren und Schlüssel erzeugen
- Server-Config mit
[Interface]und[Peer]erstellen 443/UDPfreigeben- Server mit
wg-quick@wg0starten - Client installieren und eigenes Schlüsselpaar erzeugen
- Client-Config mit Server-Public-Key, Preshared Key und
Endpointerstellen - Client mit
wg-quick up wg0starten und Verbindung testen
ATOM (Alter Code-Editor)
Atom: Kotlin-Dateien (.kt) mit Syntax-Highlighting öffnen
Diese Anleitung zeigt, wie Atom Kotlin-Dateien mit der Endung .kt und .kts als Kotlin erkennt und Syntax-Highlighting aktiviert.
Problem
Die Paket-Suche in Atom funktioniert nicht mehr zuverlässig. Beim Suchen nach language-kotlin erscheint zum Beispiel:
Unexpected token < in JSON at position 0
Das liegt daran, dass Atom keine Paketdaten mehr bekommt, sondern eine HTML-Seite. Atom wurde eingestellt, deshalb funktioniert die Paketverwaltung nicht mehr sauber.
Voraussetzung
Für diese Anleitung muss git bereits installiert sein.
Das kann mit folgendem Befehl geprüft werden:
git --version
Wenn eine Versionsnummer angezeigt wird, ist git vorhanden.
Lösung
Das Kotlin-Sprachpaket wird manuell in den Atom-Paketordner des eigenen Benutzers installiert.
Atom-Paketordner anlegen
mkdir -p "$HOME/.atom/packages"
Kotlin-Sprachpaket herunterladen
git clone --depth 1 https://github.com/alexmt/atom-kotlin-language.git "$HOME/.atom/packages/language-kotlin"
Falls die Meldung erscheint, dass der Zielordner bereits existiert, wurde das Paket vermutlich schon heruntergeladen.
Der Paketordner sollte danach hier liegen:
$HOME/.atom/packages/language-kotlin
Dateizuordnung in Atom setzen
Damit Atom Dateien mit .kt und .kts sicher als Kotlin erkennt, muss die Atom-Konfiguration angepasst werden.
Die Datei befindet sich hier:
$HOME/.atom/config.cson
Im vorhandenen Bereich core wird customFileTypes ergänzt.
Beispiel
"*":
core:
closeDeletedFileTabs: true
telemetryConsent: "no"
customFileTypes:
"source.kotlin": [
"kt"
"kts"
]
editor:
fontSize: 15
showIndentGuide: true
showInvisibles: true
"exception-reporting":
userId: "22758505-7925-41c0-a70b-cb47b5f1678a"
welcome:
showOnStartup: false
Wichtig: Es darf kein zweiter core:-Block angelegt werden. Die Zeilen müssen unter dem bereits vorhandenen core:-Block eingefügt werden.
Atom neu starten
Nach der Änderung Atom vollständig schließen und neu öffnen.
Danach eine .kt-Datei öffnen. Unten rechts in Atom sollte dann als Sprache Kotlin angezeigt werden.
Kontrolle
Folgende Dinge sollten vorhanden sein:
- Der Ordner
$HOME/.atom/packages/language-kotlinexistiert. - In
$HOME/.atom/config.csonistcustomFileTypesuntercoreeingetragen. - Atom wurde nach der Änderung neu gestartet.
- Eine Datei mit der Endung
.ktwird als Kotlin erkannt.
Hinweis
Atom wird nicht mehr aktiv weiterentwickelt. Für neue Projekte ist ein gepflegter Editor wie Visual Studio Code, Kate oder IntelliJ IDEA sinnvoller. Für bestehende Systeme kann diese Lösung aber weiterhin ausreichen.
Linux - Proxmox
Proxmox VE 9 auf verschlüsseltem Debian 13 mit Dropbear-Remote-Unlock installieren
Diese Anleitung beschreibt die Installation von Proxmox VE 9 auf einem bereits installierten Debian 13 System mit verschlüsseltem Root-Dateisystem via LUKS. Das System wird vor dem Boot per dropbear-initramfs über SSH entsperrt. Zusätzlich wird ein zweiter verschlüsselter lokaler Storage für VM-Disks und ISO-Dateien eingerichtet.
Ausgangslage in diesem Beispiel:
- Debian 13 Trixie ist bereits installiert.
- Root liegt auf LUKS + LVM.
/bootund/boot/efisind unverschlüsselt.dropbear-initramfsfunktioniert bereits.- Der Server wird als
rootadministriert. - Hostname:
byte-me - Management-IP:
10.100.3.13
1. Bestehende Partitionierung prüfen
lsblk
df -h
uname -r
Beispielhafte Zielstruktur für das Systemlaufwerk:
nvme0n1
├─nvme0n1p1 /boot/efi
├─nvme0n1p2 /boot
└─nvme0n1p3 crypto_LUKS
└─nvme0n1p3_crypt
├─broken--vg-root /
└─broken--vg-swap_1 [SWAP]
Wichtig: /boot ist bei verschlüsselten Debian-Installationen oft klein. Proxmox-Kernel und Initramfs-Dateien können sehr groß werden. Vor der Installation sollte ausreichend Platz geschaffen werden.
2. Alten Debian-Kernel bereinigen
Aktuell laufenden Kernel prüfen:
uname -r
Installierte Kerneldateien prüfen:
ls -lh /boot
dpkg -l 'linux-image*' 'linux-headers*' | awk '/^ii|^rc/ {print $1, $2, $3}'
Wenn mehrere alte Kernel vorhanden sind, zuerst in den neuesten Debian-Kernel booten und danach alte Kernel entfernen.
Beispiel:
apt purge linux-image-6.12.85+deb13-amd64
apt autoremove
update-grub
df -h /boot
Falls das Paket anders heißt, den Besitzer der Kerneldatei ermitteln:
dpkg -S /boot/vmlinuz-6.12.85+deb13-amd64
Dann das exakt passende Paket entfernen, zum Beispiel:
apt purge linux-image-6.12.85+deb13-amd64-unsigned
3. Proxmox Repository einrichten
Benötigte Werkzeuge installieren:
apt install -y wget ca-certificates
Proxmox-Keyring für Debian 13 / Trixie herunterladen:
wget https://enterprise.proxmox.com/debian/proxmox-archive-keyring-trixie.gpg -O /usr/share/keyrings/proxmox-archive-keyring.gpg
Hash prüfen:
sha256sum /usr/share/keyrings/proxmox-archive-keyring.gpg
Erwarteter Hash:
136673be77aba35dcce385b28737689ad64fd785a797e57897589aed08db6e45 /usr/share/keyrings/proxmox-archive-keyring.gpg
Repository-Datei anlegen:
cat > /etc/apt/sources.list.d/proxmox.sources <<'EOF'
Types: deb
URIs: http://download.proxmox.com/debian/pve
Suites: trixie
Components: pve-no-subscription
Signed-By: /usr/share/keyrings/proxmox-archive-keyring.gpg
EOF
Paketlisten aktualisieren:
apt update
4. Proxmox-Kernel installieren
Zuerst nur den Proxmox-Kernel installieren, noch nicht das komplette Proxmox-Paket:
apt install proxmox-default-kernel
Danach GRUB prüfen:
update-grub
Erwartet wird ein Eintrag ähnlich zu:
Found linux image: /boot/vmlinuz-7.0.2-2-pve
Found initrd image: /boot/initrd.img-7.0.2-2-pve
5. Initramfs-Größe bei kleinem /boot reduzieren
Bei kleinem /boot kann der Proxmox-Initramfs zu groß werden. In diesem Setup wurde die Kompression von zstd auf xz geändert.
Datei öffnen:
nano /etc/initramfs-tools/initramfs.conf
Diese Zeile ändern:
COMPRESS=zstd
zu:
COMPRESS=xz
MODULES=most wurde bewusst beibehalten, damit Netzwerk- und Storage-Treiber für Dropbear/LUKS möglichst robust im Initramfs enthalten bleiben.
Proxmox-Initramfs neu bauen:
update-initramfs -c -k 7.0.2-2-pve
Prüfen:
df -h /boot
ls -lh /boot/initrd.img-7.0.2-2-pve
6. In den Proxmox-Kernel booten
reboot
Nach dem Reboot wie gewohnt per Dropbear entsperren.
Danach prüfen:
uname -r
Erwartet:
7.0.2-2-pve
7. Debian-Kernel entfernen
Nachdem der Proxmox-Kernel erfolgreich gebootet wurde, können die Debian-Kernel entfernt werden. Das schafft Platz in /boot und verhindert spätere Initramfs-Probleme.
Paketnamen ermitteln:
dpkg -S /boot/vmlinuz-6.12.86+deb13-amd64
Falls Debian-Headers den Kernel wieder installieren wollen, Kernel und Headers zusammen entfernen:
apt purge linux-image-6.12.86+deb13-amd64-unsigned linux-headers-6.12.86+deb13-amd64 linux-headers-6.12.86+deb13-common linux-headers-amd64
Danach Proxmox-Initramfs erneut bauen:
update-initramfs -c -k 7.0.2-2-pve
update-grub
df -h /boot
8. ZFS-DKMS entfernen und Proxmox-ZFS verwenden
Falls Debian-ZFS bereits installiert war, insbesondere zfs-dkms, sollte zfs-dkms entfernt werden. Proxmox nutzt eigene Kernel und passende ZFS-Pakete.
ZFS-Pakete prüfen:
dpkg -l 'zfs*' 'spl*' | awk '/^ii|^rc/ {print $1, $2, $3}'
zfs-dkms entfernen:
apt purge zfs-dkms
Falls dabei zfsutils-linux und zfs-zed entfernt wurden, diese aus dem Proxmox-Repository wieder installieren:
apt install zfsutils-linux zfs-zed
Prüfen:
dpkg -l 'zfs*' 'proxmox*' 'pve*' | awk '/^ii|^rc/ {print $1, $2, $3}'
Gewünscht:
ii proxmox-default-kernel ...
ii proxmox-kernel-7.0 ...
ii pve-firmware ...
ii zfs-zed ...
ii zfsutils-linux ...
Nicht gewünscht:
ii zfs-dkms ...
9. Proxmox VE installieren
apt install proxmox-ve postfix open-iscsi chrony
Bei der Postfix-Abfrage kann für einen normalen Proxmox-Host gewählt werden:
Local only
Entfernungen während der Installation sind normal:
exim4-*wird durchpostfixersetzt.ifupdownwird durchifupdown2ersetzt.systemd-timesyncdwird durchchronyersetzt.
10. Hostname-Auflösung für Proxmox korrigieren
Proxmox benötigt, dass der Hostname auf eine echte Nicht-Loopback-IP zeigt. Wenn pve-cluster nicht startet und im Journal steht:
Unable to resolve node name 'byte-me' to a non-loopback IP address
dann muss /etc/hosts angepasst werden.
Datei öffnen:
nano /etc/hosts
Beispiel:
127.0.0.1 localhost
10.100.3.13 byte-me.localdomain byte-me
# The following lines are desirable for IPv6 capable hosts
::1 localhost ip6-localhost ip6-loopback
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
Wichtig: Der Hostname byte-me darf nicht auf 127.0.0.1 oder 127.0.1.1 zeigen.
Prüfen:
hostname
hostname -f
getent hosts byte-me
Erwartung:
byte-me
byte-me.localdomain
10.100.3.13 byte-me.localdomain byte-me
Proxmox-Dienste neu starten:
systemctl reset-failed pve-cluster
systemctl restart pve-cluster
systemctl restart pvedaemon pveproxy pvestatd
Status prüfen:
systemctl status pve-cluster pvedaemon pveproxy pvestatd --no-pager
Erwartung:
pve-cluster active
pvedaemon active
pveproxy active
pvestatd active
Weboberfläche:
https://10.100.3.13:8006/
Verschlüsselten lokalen VM-Storage einrichten
Zusätzlich wurde eine zweite NVMe als verschlüsselter Storage für VMs und ISO-Dateien eingerichtet. In diesem Beispiel:
/dev/nvme1n1
Achtung: Die folgenden Schritte löschen die Zielplatte. Nicht auf dem Systemlaufwerk ausführen.
11. Zielplatte prüfen
lsblk -o NAME,SIZE,TYPE,FSTYPE,MOUNTPOINTS,MODEL
wipefs -n /dev/nvme1n1
Beispiel:
nvme1n1 953,9G disk SKHynix_HFS001TEJ9X162N
12. Partition erstellen
fdisk /dev/nvme1n1
In fdisk:
g
n
1
y
w
Danach prüfen:
lsblk -o NAME,SIZE,TYPE,FSTYPE,MOUNTPOINTS,MODEL /dev/nvme1n1
Erwartung:
nvme1n1 953,9G disk
└─nvme1n1p1 953,9G part
13. LUKS2 sicher formatieren
cryptsetup luksFormat \
--type luks2 \
--label crypt-vmstore \
--cipher aes-xts-plain64 \
--key-size 512 \
--hash sha512 \
--pbkdf argon2id \
--iter-time 5000 \
--verify-passphrase \
/dev/nvme1n1p1
Eine lange Passphrase verwenden. Keine kurzen Passwörter, keine Projektnamen, keine Tastaturmuster.
14. LUKS öffnen
In diesem Beispiel wurde der Mapper exploding_disk genannt.
cryptsetup open /dev/nvme1n1p1 exploding_disk
Prüfen:
lsblk /dev/nvme1n1p1
Erwartung:
nvme1n1p1
└─exploding_disk
15. LUKS-Header sichern
Ein LUKS-Header-Backup ist wichtig. Wenn der Header beschädigt wird, sind die Daten sonst praktisch verloren.
mkdir -p /root/luks-header-backups
chmod 700 /root/luks-header-backups
cryptsetup luksHeaderBackup /dev/nvme1n1p1 \
--header-backup-file /root/luks-header-backups/nvme1n1p1-crypt-vmstore-header.img
chmod 400 /root/luks-header-backups/nvme1n1p1-crypt-vmstore-header.img
Dieses Header-Backup sollte zusätzlich extern und sicher verschlüsselt gesichert werden. Ohne passenden Header und ohne Passphrase sind die Daten nicht wiederherstellbar.
16. LVM auf dem entschlüsselten Device erstellen
pvcreate /dev/mapper/exploding_disk
vgcreate vg_vmstore /dev/mapper/exploding_disk
Prüfen:
vgs
pvs
Erwartung:
VG VSize VFree
vg_vmstore 953,85g 953,85g
17. LVM-thin für VM-Disks erstellen
lvcreate -L 850G -T vg_vmstore/vmdata
Prüfen:
lvs
Beispiel:
LV VG Attr LSize
vmdata vg_vmstore twi-a-tz-- 850,00g
18. ISO-Storage erstellen
lvcreate -L 60G -n iso vg_vmstore
mkfs.ext4 -L pve-iso /dev/vg_vmstore/iso
mkdir -p /mnt/pve/iso-store
UUID anzeigen:
blkid /dev/vg_vmstore/iso
Beispiel:
/dev/vg_vmstore/iso: LABEL="pve-iso" UUID="0f1496f7-d7ad-4e97-9243-cff799d44e5e" BLOCK_SIZE="4096" TYPE="ext4"
19. ISO-Storage in /etc/fstab eintragen
nano /etc/fstab
Eintrag ergänzen:
UUID=0f1496f7-d7ad-4e97-9243-cff799d44e5e /mnt/pve/iso-store ext4 defaults,noatime 0 2
Systemd neu laden und Mount testen:
systemctl daemon-reload
mount -a
df -h /mnt/pve/iso-store
20. Storage in Proxmox eintragen
LVM-thin für VM- und Container-Disks:
pvesm add lvmthin vmstore \
--vgname vg_vmstore \
--thinpool vmdata \
--content images,rootdir
Directory-Storage für ISOs und Container-Templates:
pvesm add dir iso-store \
--path /mnt/pve/iso-store \
--content iso,vztmpl
Status prüfen:
pvesm status
Beispiel:
Name Type Status Total (KiB) Used (KiB) Available (KiB) %
iso-store dir active 61611820 2084 58447624 0.00%
local dir active 477545328 154494456 298719404 32.35%
vmstore lvmthin active 891289600 0 891289600 0.00%
Optional: Automatisches Entsperren des zweiten LUKS-Storage
Ein Keyfile auf dem verschlüsselten Root-Dateisystem ist komfortabel, reduziert aber die Trennung der Sicherheitsstufen. Ohne Keyfile braucht ein Angreifer bei Diebstahl beider Platten Root-Passphrase und Storage-Passphrase. Mit Keyfile reicht die Root-Passphrase, weil danach das Keyfile verfügbar ist.
Variante A: Maximale Trennung
Kein Keyfile verwenden. Nach jedem Boot manuell entsperren:
cryptsetup open /dev/nvme1n1p1 exploding_disk
vgchange -ay vg_vmstore
mount -a
VM-Autostart für VMs auf diesem Storage sollte dann deaktiviert werden, weil der Storage nach dem Boot zunächst fehlt.
Variante B: Komfortabler Auto-Unlock nach Root-Unlock
Keyfile auf verschlüsseltem Root-Dateisystem erstellen:
mkdir -p /root/luks-keys
chmod 700 /root/luks-keys
dd if=/dev/random of=/root/luks-keys/exploding_disk.key bs=64 count=1
chmod 400 /root/luks-keys/exploding_disk.key
Keyfile zu LUKS hinzufügen:
cryptsetup luksAddKey /dev/nvme1n1p1 /root/luks-keys/exploding_disk.key
LUKS-UUID anzeigen:
blkid /dev/nvme1n1p1
/etc/crypttab bearbeiten:
nano /etc/crypttab
Eintrag ergänzen:
exploding_disk UUID=DEINE-LUKS-UUID-HIER /root/luks-keys/exploding_disk.key luks
Systemd neu laden:
systemctl daemon-reload
Ceph-Zukunftsplanung
Für später geplante drei Proxmox-Nodes mit Ceph gilt:
- Die aktuell lokal genutzte NVMe muss später für Ceph gelöscht werden.
- VMs müssen vorher vom lokalen Storage auf Ceph migriert werden.
- Ceph-OSDs sollten später direkt über Proxmox/Ceph mit Encryption erstellt werden.
- Nicht vorher manuell LUKS + LVM bauen und dann Ceph darüberlegen.
Geplanter späterer Ablauf:
1. PVE 2 und PVE 3 installieren
2. Cluster erstellen
3. Dediziertes 10G-Netz für Ceph konfigurieren
4. Ceph installieren
5. Auf allen Nodes freie NVMe als verschlüsselte Ceph-OSD einrichten
6. Ceph-Pool erstellen
7. VM-Storage auf Ceph RBD anlegen
8. VMs vom lokalen vmstore auf Ceph migrieren
9. Lokalen LUKS/LVM-Storage auf nvme1n1 entfernen
10. nvme1n1 als Ceph-OSD neu verwenden
Mit nur einem Node ist Ceph nicht sinnvoll redundant. Für produktive Ceph-Nutzung sollten mindestens drei Proxmox-Nodes vorhanden sein.
Wichtige Checks nach der Einrichtung
dpkg --audit
df -h /boot
uname -r
pvesm status
lsblk -o NAME,SIZE,TYPE,FSTYPE,MOUNTPOINTS
vgs
lvs
systemctl status pve-cluster pvedaemon pveproxy pvestatd --no-pager
Erwartung:
Kernel: 7.0.2-2-pve
/boot nicht voll
pve-cluster active
pvedaemon active
pveproxy active
pvestatd active
vmstore active
iso-store active
Zusammenfassung
- Debian 13 mit LUKS-Root und Dropbear-Remote-Unlock wurde als Basis verwendet.
- Proxmox VE 9 wurde auf Debian installiert.
- Der Proxmox-Kernel wurde zuerst einzeln installiert und getestet.
/boot-Probleme wurden durch Entfernen alter Debian-Kernel undCOMPRESS=xzbehoben.zfs-dkmswurde entfernt und Proxmox-ZFS verwendet.- Hostname-Auflösung wurde für
pve-clusterkorrigiert. - Eine zweite NVMe wurde mit LUKS2 verschlüsselt.
- Darauf wurde LVM-thin für VM-Disks eingerichtet.
- Ein ext4-LV wurde als ISO-/Template-Storage eingebunden.
- Späterer Ceph-Betrieb ist möglich, erfordert aber Migration und Neuanlage der Disk als Ceph-OSD.
Neue Seite
Proxmox iSCSI SAN mit tgt und LVM
Diese Dokumentation beschreibt die bisher eingerichtete iSCSI-SAN-Konfiguration mit tgt auf der SAN-Seite und dem ersten Proxmox-Node pve_1.
1. Ziel der Konfiguration
Es wurde ein iSCSI-Target auf der SAN-Seite bereitgestellt und auf dem ersten Proxmox-Node als Shared-LVM-Storage eingebunden.
Der Aufbau ist:
tgt SAN
└─ iSCSI Target: iqn.2026-02-25.linux.proxmox.pve:cleopatra
└─ LUN: /dev/mapper/cleopatra
└─ pve_1 sieht LUN als /dev/sda
└─ /dev/sda1 als LVM Physical Volume
└─ VG: vg_vmstore
└─ Proxmox Storage: lvm-cleopatra
2. Namensschema
| Objekt | Name | Beschreibung |
|---|---|---|
| SAN-Host | big-bunda |
Server mit tgt als iSCSI-Target-Dienst |
| Erster Proxmox-Node | pve_1 / byte-me |
Erster Proxmox-VE-Node, der das iSCSI-LUN nutzt |
| iSCSI Portal | 10.99.255.1:3260 |
IP-Adresse und Port des iSCSI-Targets |
| iSCSI Target IQN | iqn.2026-02-25.linux.proxmox.pve:cleopatra |
Eindeutiger iSCSI-Targetname für den Storage Cleopatra |
| tgt Backing Store | /dev/mapper/cleopatra |
Blockdevice, das vom tgt-Target als LUN exportiert wird |
| Proxmox iSCSI Storage-ID | iscsi-cleopatra |
Proxmox-Eintrag für die reine iSCSI-Verbindung |
| LVM Volume Group | vg_vmstore |
LVM-VG auf der iSCSI-LUN |
| Proxmox LVM Storage-ID | lvm-cleopatra |
Nutzbarer VM-Storage in Proxmox |
3. Wichtige Entscheidung: Warum zwei Proxmox-Storage-Einträge?
In Proxmox gibt es zwei Einträge, weil iSCSI und LVM zwei verschiedene Schichten sind.
iscsi-cleopatra = Verbindung zum iSCSI-Target
lvm-cleopatra = eigentlicher VM-Storage auf der LVM Volume Group
Der iSCSI-Eintrag selbst hat content none, weil Proxmox dort keine VM-Disks direkt ablegt. Die eigentlichen VM-Disks werden später auf lvm-cleopatra erstellt.
4. tgt SAN-Konfiguration
Auf dem SAN-Host big-bunda wird tgt als iSCSI-Target-Daemon genutzt. Das exportierte Blockdevice ist:
/dev/mapper/cleopatra
Beispiel für die tgt-Konfiguration:
<target iqn.2026-02-25.linux.proxmox.pve:cleopatra>
driver iscsi
<backing-store /dev/mapper/cleopatra>
lun 1
device-type disk
vendor_id "linux"
product_id "iscsi disk"
product_rev "0001"
scsi_sn "cleopatra-lun1"
write-cache off
</backing-store>
# zugriff nur für erlaubte proxmox-nodes
initiator-address 10.99.255.X
# initiator-iqn von pve_1 / byte-me
# prüfen auf dem pve-node mit:
# cat /etc/iscsi/initiatorname.iscsi
initiator-name iqn.1993-08.org.debian:01:1ebae4d041e
# mutual chap
# incominguser = initiator authentifiziert sich beim target
# outgoinguser = target authentifiziert sich beim initiator
incominguser pve-byteme "SECRET_NICHT_IN_DOKU_EINTRAGEN"
outgoinguser tgt-cleopatra "ANDERES_SECRET_NICHT_IN_DOKU_EINTRAGEN"
</target>
Wichtig: Die CHAP-Secrets dürfen nicht identisch sein. Für incominguser und outgoinguser müssen unterschiedliche Passwörter verwendet werden.
Für dieses Setup wurden kurze, kompatible CHAP-Secrets verwendet, da längere Secrets im konkreten tgt/Open-iSCSI-Stack Probleme verursachen können. Empfohlen sind zufällige Secrets mit 12 bis 16 Zeichen.
openssl rand -hex 8
5. Proxmox pve_1 / byte-me: iSCSI-Verbindung
Auf dem ersten Proxmox-Node wurde das Target über das Portal 10.99.255.1 eingebunden.
Proxmox-Storage-Eintrag:
iscsi: iscsi-cleopatra
portal 10.99.255.1
target iqn.2026-02-25.linux.proxmox.pve:cleopatra
content none
Das iSCSI-LUN ist auf pve_1 sichtbar als:
/dev/sda
Der stabile Gerätepfad lautet:
/dev/disk/by-path/ip-10.99.255.1:3260-iscsi-iqn.2026-02-25.linux.proxmox.pve:cleopatra-lun-1
6. Entfernen des alten VMFS-Datastores
Auf dem iSCSI-LUN befand sich vorher ein VMware VMFS6-Dateisystem. Dieses wurde entfernt, da die Daten nicht mehr benötigt wurden.
Vorheriger Zustand:
sda
└─sda1 VMFS_volume_member 6
Verwendete Befehle:
lun="/dev/disk/by-path/ip-10.99.255.1:3260-iscsi-iqn.2026-02-25.linux.proxmox.pve:cleopatra-lun-1"
findmnt "$lun"
findmnt "${lun}-part1"
wipefs -a "${lun}-part1"
wipefs -a "$lun"
partprobe "$lun"
udevadm settle
Achtung: Diese Befehle löschen Dateisystem- und Partitionssignaturen. Sie dürfen nur verwendet werden, wenn die Daten auf der LUN wirklich gelöscht werden dürfen.
7. Neue GPT-Partition für LVM
Nach dem Entfernen der VMFS-Signaturen wurde eine neue GPT-Partitionstabelle mit einer LVM-Partition erstellt.
parted -s "$lun" mklabel gpt
parted -s "$lun" mkpart primary 1MiB 100%
parted -s "$lun" set 1 lvm on
partprobe "$lun"
udevadm settle
Danach war die LUN sauber vorbereitet:
NAME FSTYPE FSVER LABEL UUID FSAVAIL FSUSE% MOUNTPOINTS
sda
└─sda1
8. LVM auf iSCSI erstellen
Auf der neuen Partition wurde ein LVM Physical Volume und danach eine Volume Group erstellt.
pvcreate "${lun}-part1"
vgcreate vg_vmstore "${lun}-part1"
Ergebnis:
PV VG Fmt Attr PSize PFree
/dev/sda1 vg_vmstore lvm2 a-- <6,99t <6,99t
VG #PV #LV #SN Attr VSize VFree
vg_vmstore 1 0 0 wz--n- <6,99t <6,99t
Wichtig für weitere Nodes: pvcreate und vgcreate wurden nur einmal auf pve_1 ausgeführt. Auf weiteren Proxmox-Nodes darf das nicht erneut ausgeführt werden. Weitere Nodes sollen die bestehende VG nur erkennen.
9. Proxmox LVM Storage
Der Proxmox-LVM-Storage wurde als shared Storage angelegt.
pvesm add lvm lvm-cleopatra \
--vgname vg_vmstore \
--content images,rootdir \
--shared 1
Finaler Proxmox-Storage-Eintrag:
lvm: lvm-cleopatra
vgname vg_vmstore
content images,rootdir
shared 1
Damit ist lvm-cleopatra der nutzbare Storage für VM-Disks und Container-Rootdisks.
10. Aktueller Proxmox-Status
Aktueller Status auf pve_1:
Name Type Status Total (KiB) Used (KiB) Available (KiB) %
iscsi-cleopatra iscsi active 0 0 0 0.00%
lvm-cleopatra lvm active 7503060992 0 7503060992 0.00%
Dass iscsi-cleopatra eine Größe von 0 zeigt, ist normal. Dieser Eintrag ist nur die Verbindung zum iSCSI-Target. Die nutzbare Kapazität wird bei lvm-cleopatra angezeigt.
11. Finaler Aufbau in Proxmox
iscsi: iscsi-cleopatra
portal 10.99.255.1
target iqn.2026-02-25.linux.proxmox.pve:cleopatra
content none
lvm: lvm-cleopatra
vgname vg_vmstore
content images,rootdir
shared 1
12. Hinweise für spätere Proxmox-Nodes
Bei weiteren Proxmox-Nodes muss nur die iSCSI-Verbindung eingerichtet werden. Die LVM-Struktur existiert bereits.
Auf jedem weiteren Node prüfen:
cat /etc/iscsi/initiatorname.iscsi
pvesm status
pvs
vgs
Jeder Node braucht einen eigenen eindeutigen Initiator-IQN. Dieser muss auf der SAN-Seite in der tgt-Konfiguration als initiator-name erlaubt werden.
Nicht erneut ausführen:
pvcreate
vgcreate
wipefs
parted mklabel
Diese Befehle würden die bestehende LVM-Struktur beziehungsweise die Daten auf dem Shared Storage beschädigen. Storage verzeiht so etwas nicht, es merkt sich das nur in Form von Datenverlust.
13. Sicherheitsregeln
- iSCSI nur über das dedizierte Storage-Netz betreiben.
- Port
3260/tcpnur für autorisierte Proxmox-Nodes erlauben. - Pro Node einen eigenen Initiator-IQN verwenden.
- Auf dem tgt-Target sowohl
initiator-addressals auchinitiator-namesetzen. - Mutual CHAP verwenden.
incominguserundoutgoingusermit unterschiedlichen Secrets konfigurieren.- Keine echten CHAP-Secrets in BookStack dokumentieren.
- Für mehrere Nodes klassisches
lvmverwenden, nichtlvmthin.
14. Optionales späteres Cleanup
Aktuell heißt die LVM Volume Group noch:
vg_vmstore
Für ein konsequentes Namensschema könnte sie später optional umbenannt werden:
vgrename vg_vmstore vg_cleopatra
pvesm set lvm-cleopatra --vgname vg_cleopatra
Danach wäre das Schema vollständig konsistent:
iscsi-cleopatra
lvm-cleopatra
vg_cleopatra
Dieser Schritt ist optional. Der Storage funktioniert bereits mit vg_vmstore.
15. Kurzfassung
SAN big-bunda:
Target: iqn.2026-02-25.linux.proxmox.pve:cleopatra
Backing Store: /dev/mapper/cleopatra
Portal: 10.99.255.1:3260
Auth: Mutual CHAP
ACL: initiator-address + initiator-name
Proxmox pve_1 / byte-me:
iSCSI Storage: iscsi-cleopatra
LVM VG: vg_vmstore
Proxmox VM Storage: lvm-cleopatra
Shared: ja
Content: images,rootdir
Proxmox - VMs von einem ausgefallenen Proxmox-Host übernehmen
Wenn ein Proxmox-Host im Cluster ausgefallen bzw. offline ist, können die darauf registrierten VMs einem anderen Host zugeordnet und dort gestartet werden, sofern deren Storage weiterhin erreichbar ist.
Wichtig: Der ausgefallene Host muss wirklich ausgeschaltet bzw. vom Cluster getrennt sein. Er darf nicht gleichzeitig wieder starten, während seine VMs bereits auf einem anderen Host laufen. Andernfalls besteht die Gefahr von gleichzeitig laufenden VMs und beschädigten Dateisystemen.
Storage beachten: Liegen die VM-Festplatten ausschließlich auf dem lokalen Storage des ausgefallenen Hosts, können die VMs nicht einfach auf einem anderen Host gestartet werden. Die folgende Vorgehensweise setzt voraus, dass die benötigten VM-Datenträger vom Ziel-Host erreichbar sind, beispielsweise über Ceph, NFS oder anderes Shared Storage.
VMs des ausgefallenen Hosts anzeigen
Die VM-Konfigurationen des ausgefallenen Hosts befinden sich im Proxmox Cluster Filesystem und können direkt angezeigt werden:
ls -1 /etc/pve/nodes/<AUSGEFALLENER-HOST>/qemu-server/
Beispiel:
ls -1 /etc/pve/nodes/pve01/qemu-server/
Die Ausgabe enthält die VM-Konfigurationen anhand ihrer VM-ID:
101.conf
102.conf
103.conf
104.conf
Alle VMs auf einen anderen Host übernehmen
Um alle VMs des ausgefallenen Hosts dem Ziel-Host zuzuordnen, werden deren Konfigurationsdateien in das Verzeichnis des Ziel-Hosts verschoben:
mv /etc/pve/nodes/<AUSGEFALLENER-HOST>/qemu-server/*.conf /etc/pve/nodes/<ZIEL-HOST>/qemu-server/
Beispiel:
mv /etc/pve/nodes/pve01/qemu-server/*.conf /etc/pve/nodes/pve02/qemu-server/
Die VMs erscheinen anschließend in Proxmox unter dem neuen Host. Dabei werden nur die VM-Konfigurationen verschoben. Die eigentlichen VM-Datenträger bleiben auf dem vorhandenen Storage.
Einzelne VM übernehmen
Soll nur eine bestimmte VM übernommen werden, kann deren Konfigurationsdatei einzeln verschoben werden:
mv /etc/pve/nodes/<AUSGEFALLENER-HOST>/qemu-server/<VMID>.conf /etc/pve/nodes/<ZIEL-HOST>/qemu-server/
Beispiel:
mv /etc/pve/nodes/pve01/qemu-server/101.conf /etc/pve/nodes/pve02/qemu-server/
VMs starten
Nach der Übernahme können die benötigten VMs über die Proxmox-Weboberfläche oder über die Shell gestartet werden:
qm start <VMID>
Beispiel:
qm start 101
Bei HA-verwalteten VMs
VMs, die durch Proxmox HA verwaltet werden, sollten nicht manuell über das Cluster-Dateisystem verschoben werden. In diesem Fall übernimmt Proxmox HA die Wiederherstellung und den Neustart der VM auf einem verfügbaren Cluster-Node.
Nach der Übernahme prüfen
Vor dem Start größerer VM-Mengen sollte geprüft werden, ob Storage und Netzwerk auf dem Ziel-Host korrekt verfügbar sind.
qm status <VMID>
Zusätzlich sollte kontrolliert werden, ob alle in der VM-Konfiguration verwendeten Storages auf dem Ziel-Host verfügbar sind.
Proxmox VE ohne Subscription: kostenlose Repositories nutzen und Subscription-Hinweis ausblenden
Proxmox VE 9: No-Subscription-Popup deaktivieren
Fix
Betroffene Datei:
/usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js
Datei öffnen:
nano /usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js
Mit Strg + W nach folgendem Text suchen:
checked_command: function (orig_cmd)
Den vollständigen checked_command-Block löschen und an exakt derselben Position durch diesen Block ersetzen. Die vorhandene Einrückung beibehalten:
checked_command: function (orig_cmd) {
orig_cmd();
},
Wichtig: Der komplette bisherige Inhalt der Funktion wird entfernt. Es bleibt kein alter Subscription-Code unterhalb von orig_cmd() stehen.
Danach speichern, Nano schließen und pveproxy neu starten:
systemctl restart pveproxy
Anschließend die Proxmox-Weboberfläche mit Strg + F5 neu laden.
Quick-Befehl
Wenn du die Datei nicht manuell bearbeiten willst, als root direkt in der Terminal-Session ausführen:
python3 -c '
from pathlib import Path
import re, shutil
p = Path("/usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js")
s = p.read_text()
m = re.search(r"^([ \t]*)checked_command:\s*function\s*\(orig_cmd\)\s*\{", s, re.M)
if not m:
raise SystemExit("FEHLER: checked_command wurde nicht gefunden")
indent = m.group(1)
start = m.start()
brace = s.find("{", m.start())
depth = 0
end = None
for i in range(brace, len(s)):
if s[i] == "{":
depth += 1
elif s[i] == "}":
depth -= 1
if depth == 0:
end = i + 1
break
if end is None:
raise SystemExit("FEHLER: Ende von checked_command wurde nicht gefunden")
if end >= len(s) or s[end] != ",":
raise SystemExit("FEHLER: Abschließendes Komma von checked_command wurde nicht gefunden")
end += 1
replacement = (
f"{indent}checked_command: function (orig_cmd) {{\n"
f"{indent} orig_cmd();\n"
f"{indent}}},"
)
if s[start:end] == replacement:
print("Patch ist bereits sauber gesetzt")
else:
shutil.copy2(p, str(p) + ".bak")
p.write_text(s[:start] + replacement + s[end:])
print("Patch angewendet; Backup: " + str(p) + ".bak")
' && systemctl restart pveproxy && systemctl is-active pveproxy
Der Befehl übernimmt die vorhandene Einrückung der checked_command-Zeile und ersetzt den vollständigen Funktionsblock. Danach steht der Block an derselben Position wie vorher und ist sauber wie folgt eingerückt:
checked_command: function (orig_cmd) {
orig_cmd();
},
Der alte Subscription-Code wird vollständig entfernt. Wenn tatsächlich eine Änderung vorgenommen wird, wird die vorherige Datei als proxmoxlib.js.bak gesichert.
Wenn am Ende active ausgegeben wird, läuft pveproxy wieder.
Änderung rückgängig machen
cp -a /usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js.bak /usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js && systemctl restart pveproxy && systemctl is-active pveproxy
Nach Updates
Ein Update von proxmox-widget-toolkit kann proxmoxlib.js ersetzen. Wenn das Popup danach wieder erscheint, den Quick-Befehl erneut ausführen. Vor einem erneuten tatsächlichen Patch wird die dann aktuelle Paketversion wieder als .bak gesichert.
Dienst installation
OpenVPN - Server
OpenVPN Site-to-Site Server für Phoenix-Contact-Router: zwei sichere Serverprofile
Stand: 27. Mai 2026
Ziel dieses Dokuments: Es beschreibt zwei getrennte OpenVPN-Serverinstanzen auf einem Linux-Server.
- modern.conf: maximal gehärtet für aktuelle OpenVPN-Clients.
- compat.conf: weiterhin sehr sicher, aber bewusst kompatibler für ältere Industrie-/Phoenix-Contact-Geräte.
Beide Varianten sind für geroutete Site-to-Site-Tunnel gedacht. Das ist für dein Szenario richtig: Ein Phoenix-Contact-Router verbindet sich als OpenVPN-Client, teilt sein lokales LAN über den Tunnel und erreicht umgekehrt das zentrale LAN.
1. Quellen und Grundannahmen
Dieses Dokument orientiert sich vor allem an der offiziellen OpenVPN-2.6-Dokumentation, der OpenVPN-Hardening-Dokumentation, der OpenVPN-Dokumentation zu client-spezifischen Regeln und Easy-RSA. Wikipedia wird nur für die allgemeine Einordnung von OpenVPN als TLS-basiertes VPN über UDP/TCP erwähnt. Produktiv relevante Optionen werden aus der OpenVPN-Dokumentation abgeleitet, weil Wikipedia nicht deine Firewall administriert. Zum Glück.
| Quelle | Wofür sie hier verwendet wird |
|---|---|
| OpenVPN 2.6 Manual | Direktiven wie server, data-ciphers, tls-groups, tls-crypt-v2, ccd-exclusive, iroute, keepalive, explicit-exit-notify. |
| OpenVPN Hardening Wiki | Begründung für tls-version-min 1.2 und allgemeine TLS-Härtung. |
| OpenVPN Client-Specific Rules | Nutzung von client-config-dir, festen Client-IP-Adressen und Firewall-Policy je Client. |
| OpenVPN Compression Wiki | Begründung, warum Kompression deaktiviert bleibt. |
| Easy-RSA Dokumentation | PKI-, CA-, Zertifikats- und CRL-Erstellung. |
| Wikipedia: OpenVPN | Allgemeine Einordnung: OpenVPN ist ein freies VPN über verschlüsselte TLS-Verbindungen und kann UDP oder TCP verwenden. |
2. Zielbild
Wir bauen kein Layer-2-Bridging mit TAP. Wir bauen geroutete Layer-3-Tunnel mit TUN. Das ist stabiler, besser kontrollierbar und für Site-to-Site-Netze sauberer.
Zentrales LAN:
10.10.0.0/24
OpenVPN modern:
Instanz: modern.conf
Port: UDP/1194
TUN-Interface: tun0
VPN-Netz: 10.255.0.0/24
Beispielclient: phoenix-modern-werk1
Client-VPN-IP: 10.255.0.10
LAN hinter Client:192.168.101.0/24
OpenVPN kompatibel:
Instanz: compat.conf
Port: UDP/1195
TUN-Interface: tun1
VPN-Netz: 10.254.0.0/24
Beispielclient: phoenix-legacy-werk1
Client-VPN-IP: 10.254.0.10
LAN hinter Client:192.168.201.0/24
Wichtig: Die LAN-Netze hinter den Phoenix-Geräten müssen eindeutig sein. Zwei Standorte mit demselben Netz, etwa zweimal 192.168.0.0/24, machen sauberes Routing unmöglich. Dann brauchst du 1:1-NAT oder eine Umnummerierung. Umnummerierung ist meistens die bessere Lösung, auch wenn Menschen dabei gern so tun, als wäre ein IP-Plan eine Naturkatastrophe.
3. Warum zwei getrennte OpenVPN-Instanzen?
Eine einzelne OpenVPN-Instanz kann theoretisch moderne und ältere Clients bedienen. Praktisch verwässerst du damit die starke Konfiguration, weil du Legacy-Fallbacks zulässt. Besser ist die Trennung:
| Instanz | Ziel | Sicherheitsentscheidung |
|---|---|---|
modern.conf |
Neue Clients mit aktueller OpenVPN-/TLS-Unterstützung. | Starke Kurvengruppen, AEAD-Cipher, tls-crypt-v2, keine CBC-Fallbacks. |
compat.conf |
Ältere Phoenix-/Industrieclients, die moderne Optionen nicht zuverlässig können. | Weiterhin TLS 1.2+, Zertifikate, CRL, tls-auth, keine Kompression, aber zusätzlicher CBC-Fallback. |
Wenn du zwei öffentliche IP-Adressen hast, kannst du beide Instanzen auf Port 1194 betreiben und jeweils an eine andere IP binden. Wenn du nur eine öffentliche IP hast, müssen die Ports verschieden sein. Dieses Dokument nutzt daher 1194 für modern und 1195 für kompatibel.
4. Sicherheitsprinzipien
- Ein Zertifikat pro Standort. Kein Zertifikat wird mehrfach verwendet.
- Ein Common Name pro Standort. Der Dateiname in
ccdentspricht genau dem Common Name des Zertifikats. - Ein Standortnetz pro Zertifikat. Das wird mit
iroutegebunden. ccd-exclusive. Clients ohne CCD-Datei werden abgewiesen.- Keine Kompression. Kompression in verschlüsselten Tunneln ist ein historischer Fußtritt in Richtung Sicherheitsproblem.
- CRL aktiv. Verlorene Geräte werden über Zertifikatssperrlisten entfernt.
- Keine überlappenden Netze. Routing braucht Eindeutigkeit. Überraschend, ich weiß.
- Firewall erzwingt die Policy. OpenVPN routet, die Firewall entscheidet.
- CA-Key nicht dauerhaft auf dem VPN-Server. Idealerweise liegt die CA auf einer separaten Admin-Maschine.
5. Installation auf Debian/Ubuntu
Die folgenden Befehle sind für Debian/Ubuntu-artige Systeme geschrieben. Bei RHEL/Rocky/Alma sind Paketmanager und Gruppennamen anders. Das Konzept bleibt gleich.
sudo apt update
sudo apt install -y openvpn easy-rsa nftables
sudo systemctl enable --now nftables
5.1 Befehl-für-Befehl-Erklärung
| Befehl | Was macht er? | Warum so? | Alternativen |
|---|---|---|---|
sudo apt update |
Aktualisiert die lokale Paketliste des Systems. | Ohne aktuelle Paketliste installiert apt eventuell alte oder nicht auffindbare Pakete. |
apt-get update ist die ältere, skriptfreundliche Variante. Auf RHEL-Systemen wäre es z. B. dnf makecache. |
sudo apt install -y openvpn easy-rsa nftables |
Installiert OpenVPN, Easy-RSA und nftables. | openvpn ist der VPN-Dienst, easy-rsa erzeugt Zertifikate und CRLs, nftables stellt die Firewall. |
Statt nftables könntest du iptables, ufw oder eine externe Firewall verwenden. Für Server ist nftables heute die sauberere Wahl. |
sudo systemctl enable --now nftables |
Aktiviert nftables dauerhaft und startet es sofort. | enable sorgt für Start beim Booten, --now startet den Dienst direkt. |
Man kann Firewallregeln auch über ein zentrales Firewall-System setzen. Lokal ist trotzdem sinnvoll, weil ein VPN-Server niemals blind vertrauen sollte. |
6. Verzeichnisstruktur anlegen
sudo install -d -m 750 /etc/openvpn/server/modern
sudo install -d -m 750 /etc/openvpn/server/modern/ccd
sudo install -d -m 750 /etc/openvpn/server/compat
sudo install -d -m 750 /etc/openvpn/server/compat/ccd
| Befehl | Was macht er? | Warum so? | Alternativen |
|---|---|---|---|
sudo install -d -m 750 /etc/openvpn/server/modern |
Legt das Verzeichnis für die moderne Instanz an. | install -d erstellt ein Verzeichnis. -m 750 setzt Rechte: Besitzer darf alles, Gruppe darf lesen/betreten, andere dürfen nichts. |
mkdir -p plus chmod geht auch, ist aber ein Befehl mehr. Weil wir hier angeblich Ordnung wollen, nutzen wir install. |
sudo install -d -m 750 /etc/openvpn/server/modern/ccd |
Legt das CCD-Verzeichnis der modernen Instanz an. | Hier liegen später Dateien wie phoenix-modern-werk1. OpenVPN liest daraus feste IPs und iroute-Einträge. |
Man könnte ccd auch woanders speichern, aber unterhalb der Instanz bleibt es verständlich. |
sudo install -d -m 750 /etc/openvpn/server/compat |
Legt das Verzeichnis für die kompatible Instanz an. | Trennung verhindert, dass Schlüssel, CRLs oder CCD-Dateien versehentlich zwischen modern und legacy vermischt werden. | Eine gemeinsame Struktur wäre möglich, aber schlechter auditierbar. |
sudo install -d -m 750 /etc/openvpn/server/compat/ccd |
Legt das CCD-Verzeichnis der kompatiblen Instanz an. | Auch ältere Geräte bekommen feste Zuordnungen über CN, feste VPN-IP und entferntes LAN. | Keine gute Alternative, wenn du pro Zertifikat ein Netz sauber binden willst. |
7. PKI-Strategie
Für die sauberste Trennung nutzt jede Instanz ihre eigene PKI:
~/easy-rsa-modernfür moderne Clients.~/easy-rsa-compatfür ältere Clients.
Das ist administrativ etwas mehr Arbeit, aber sicherer. Wenn ein Legacy-Bereich kompromittiert wird, ist der moderne Bereich nicht automatisch dieselbe Vertrauensdomäne. Man könnte eine gemeinsame Root-CA mit getrennten Intermediate-CAs bauen. Für viele kleinere Betriebsumgebungen sind zwei getrennte Easy-RSA-PKIs einfacher.
8. Moderne PKI erstellen
make-cadir ~/easy-rsa-modern
cd ~/easy-rsa-modern
./easyrsa init-pki
./easyrsa build-ca
./easyrsa build-server-full modern-server nopass
./easyrsa build-client-full phoenix-modern-werk1 nopass
./easyrsa gen-crl
8.1 Erklärung der Befehle
| Befehl | Was macht er? | Warum so? | Optionen / Alternativen |
|---|---|---|---|
make-cadir ~/easy-rsa-modern |
Erstellt ein Arbeitsverzeichnis mit Easy-RSA-Dateien. | Die PKI wird getrennt von der Systemkonfiguration vorbereitet. Das ist übersichtlicher und reduziert versehentliches Überschreiben. | Du kannst auch ein anderes Verzeichnis nehmen, z. B. /root/easy-rsa-modern. Idealerweise liegt die CA aber nicht dauerhaft auf dem VPN-Server. |
cd ~/easy-rsa-modern |
Wechselt in das neue Easy-RSA-Verzeichnis. | Die nächsten Befehle müssen im Easy-RSA-Verzeichnis ausgeführt werden. | Mit absoluten Pfaden geht es auch, ist aber unleserlicher. |
./easyrsa init-pki |
Initialisiert die PKI-Struktur unter pki/. |
Erzeugt Verzeichnisse und Datenbanken für Zertifikate, Schlüssel und Seriennummern. | init-pki löscht/initialisiert die PKI. Auf produktiven CAs also nicht gedankenlos wiederholen. Menschen lieben destruktive Befehle mit harmlosen Namen. |
./easyrsa build-ca |
Erzeugt die Certificate Authority. | Die CA signiert später Server- und Client-Zertifikate. Der private CA-Key ist das wichtigste Geheimnis. | build-ca nopass wäre möglich, ist aber für eine CA nicht empfehlenswert. Eine CA sollte mit Passwort geschützt sein. |
./easyrsa build-server-full modern-server nopass |
Erzeugt und signiert ein Serverzertifikat mit Namen modern-server. |
nopass sorgt dafür, dass OpenVPN beim Dienststart kein Passwort interaktiv abfragen muss. |
Ohne nopass wird der private Schlüssel verschlüsselt. Das ist sicherer, aber für automatischen Serverstart unpraktisch. Alternativ kann man mit askpass arbeiten. |
./easyrsa build-client-full phoenix-modern-werk1 nopass |
Erzeugt ein Clientzertifikat für den Standort phoenix-modern-werk1. |
Der Name wird zum Common Name und muss später exakt als CCD-Dateiname verwendet werden. | Für Benutzerlaptops wäre ein passwortgeschützter Key besser. Für Phoenix-Router ist nopass oft nötig, weil das Gerät beim Booten kein Passwort eintippen kann. |
./easyrsa gen-crl |
Erzeugt die Zertifikatssperrliste crl.pem. |
OpenVPN prüft damit, ob ein Clientzertifikat gesperrt wurde. | Nach jedem revoke musst du gen-crl erneut ausführen und die neue CRL auf den Server kopieren. |
9. Moderne PKI-Dateien auf den Server kopieren
sudo install -m 644 pki/ca.crt /etc/openvpn/server/modern/pki-ca.crt
sudo install -m 644 pki/issued/modern-server.crt /etc/openvpn/server/modern/modern-server.crt
sudo install -m 600 pki/private/modern-server.key /etc/openvpn/server/modern/modern-server.key
sudo install -m 644 pki/crl.pem /etc/openvpn/server/modern/crl.pem
sudo install -d -m 750 /etc/openvpn/server/modern/pki
sudo install -d -m 750 /etc/openvpn/server/modern/pki/issued
sudo install -d -m 700 /etc/openvpn/server/modern/pki/private
sudo cp pki/ca.crt /etc/openvpn/server/modern/pki/ca.crt
sudo cp pki/issued/modern-server.crt /etc/openvpn/server/modern/pki/issued/modern-server.crt
sudo cp pki/private/modern-server.key /etc/openvpn/server/modern/pki/private/modern-server.key
sudo cp pki/crl.pem /etc/openvpn/server/modern/crl.pem
sudo chown -R root:root /etc/openvpn/server/modern
sudo chmod 600 /etc/openvpn/server/modern/pki/private/modern-server.key
sudo chmod 644 /etc/openvpn/server/modern/crl.pem
Hinweis: In der Praxis brauchst du die ersten vier install-Zeilen nicht, wenn du direkt die strukturierte Variante darunter verwendest. Ich zeige sie trotzdem, weil install -m verständlich macht, dass Dateirechte kein Deko-Element sind. Für die eigentliche Dokumentation ist die strukturierte Variante mit pki/ca.crt, pki/issued und pki/private die relevante.
9.1 Erklärung der wichtigsten Kopierbefehle
| Befehl | Was macht er? | Warum so? | Optionen / Alternativen |
|---|---|---|---|
sudo install -d -m 750 .../pki |
Erstellt ein PKI-Unterverzeichnis für die Instanz. | Die Pfade in modern.conf sind dadurch klar und getrennt. |
Du könntest die Dateien direkt unter /etc/openvpn/server/modern ablegen, aber Unterordner sind sauberer. |
sudo install -d -m 700 .../pki/private |
Erstellt das private Schlüsselverzeichnis mit strengeren Rechten. | Private Schlüssel sollen nicht von normalen Benutzern lesbar sein. | 750 wäre möglich, aber 700 ist konservativer. |
sudo cp pki/ca.crt ... |
Kopiert das öffentliche CA-Zertifikat. | Der Server braucht die CA, um Clientzertifikate zu prüfen. | Die CA-Datei ist öffentlich. Sie ist nicht geheim. Der CA-Key ist geheim und gehört nicht hierher. |
sudo cp pki/issued/modern-server.crt ... |
Kopiert das Serverzertifikat. | OpenVPN präsentiert dieses Zertifikat den Clients. | Der Name ist frei wählbar, muss aber zur Config passen. |
sudo cp pki/private/modern-server.key ... |
Kopiert den privaten Server-Key. | Ohne privaten Schlüssel kann der Server sein Zertifikat nicht nutzen. | Der Key muss geschützt werden. Verlust oder Diebstahl bedeutet: Serverzertifikat neu erzeugen und altes sperren. |
sudo cp pki/crl.pem ... |
Kopiert die CRL. | OpenVPN kann gesperrte Clientzertifikate ablehnen. | Die CRL muss erneuert werden, nachdem Zertifikate widerrufen wurden. |
sudo chown -R root:root ... |
Setzt root als Besitzer. | Systemkonfiguration soll nicht normalen Benutzern gehören. | Je nach Distribution kann eine OpenVPN-Gruppe genutzt werden. Das sollte bewusst passieren, nicht zufällig. |
sudo chmod 600 ...modern-server.key |
Nur root darf den privaten Schlüssel lesen/schreiben. | Minimiert Risiko durch lokale Benutzer. | Wenn OpenVPN nach dem Start Rechte abgibt, liest es den Key vorher. 600 ist daher meistens korrekt. |
sudo chmod 644 ...crl.pem |
Macht die CRL für den OpenVPN-Prozess lesbar. | Nach Rechteabgabe an nobody muss OpenVPN die CRL weiterhin lesen können. |
640 root:nogroup ist restriktiver, setzt aber korrekte Gruppe voraus. |
10. Moderne TLS-Crypt-v2-Schlüssel erzeugen
sudo openvpn --genkey tls-crypt-v2-server /etc/openvpn/server/modern/tc2-server.key
sudo openvpn --tls-crypt-v2 /etc/openvpn/server/modern/tc2-server.key --genkey tls-crypt-v2-client /etc/openvpn/server/modern/phoenix-modern-werk1-tc2.key
sudo chmod 600 /etc/openvpn/server/modern/tc2-server.key
sudo chmod 600 /etc/openvpn/server/modern/phoenix-modern-werk1-tc2.key
| Befehl | Was macht er? | Warum so? | Optionen / Alternativen |
|---|---|---|---|
openvpn --genkey tls-crypt-v2-server ... |
Erzeugt den serverseitigen Schlüssel für tls-crypt-v2. |
tls-crypt-v2 schützt den TLS-Kontrollkanal und erlaubt client-spezifische Schlüssel. |
tls-crypt ist kompatibler, nutzt aber einen gemeinsamen statischen Schlüssel. tls-auth ist noch kompatibler, schützt aber nicht die Vertraulichkeit des Kontrollkanals. |
openvpn --tls-crypt-v2 ... --genkey tls-crypt-v2-client ... |
Erzeugt einen client-spezifischen tls-crypt-v2-Schlüssel. |
Jeder Client bekommt einen eigenen Zusatzschlüssel. Das passt zur Idee: ein Zertifikat, ein Standort, ein Schlüssel. | Du kannst optionale Metadaten in Clientkeys einbetten. Für eine klare Betriebsdokumentation reicht der einfache Weg. |
chmod 600 ... |
Schränkt den Zugriff auf die Schlüsseldateien ein. | TLS-Crypt-Schlüssel sind geheim. Wer sie hat, kommt zwar ohne Zertifikat nicht rein, aber er reduziert deine Schutzschicht. | 640 mit dedizierter Gruppe ist möglich, wenn du sauber mit Gruppenrechten arbeitest. |
11. Moderne OpenVPN-Serverkonfiguration
Datei:
/etc/openvpn/server/modern.conf
port 1194
proto udp4
dev tun0
topology subnet
server 10.255.0.0 255.255.255.0
client-config-dir /etc/openvpn/server/modern/ccd
ccd-exclusive
route 192.168.101.0 255.255.255.0
ca /etc/openvpn/server/modern/pki/ca.crt
cert /etc/openvpn/server/modern/pki/issued/modern-server.crt
key /etc/openvpn/server/modern/pki/private/modern-server.key
dh none
tls-groups X25519:secp256r1:X448:secp384r1
tls-server
remote-cert-tls client
verify-client-cert require
tls-version-min 1.2
data-ciphers AES-256-GCM:CHACHA20-POLY1305:AES-128-GCM
auth SHA256
tls-cert-profile preferred
tls-crypt-v2 /etc/openvpn/server/modern/tc2-server.key
allow-compression no
crl-verify /etc/openvpn/server/modern/crl.pem
keepalive 10 60
explicit-exit-notify 1
persist-key
persist-tun
user nobody
group nogroup
verb 3
11.1 Jede Zeile der modernen Konfiguration erklärt
| Zeile | Was macht sie? | Warum diese Wahl? | Alternativen / Hinweise |
|---|---|---|---|
port 1194 |
OpenVPN lauscht auf UDP-Port 1194. | 1194 ist der offiziell/typisch verwendete OpenVPN-Port. Im betrieblichen Umfeld ist der Default sinnvoll, weil Firewalls, Doku und Monitoring dadurch klar bleiben. | Du könntest den Port ändern, etwa auf 443 oder 11940, um den Dienst etwas zu verschleiern. Das ist aber keine echte Sicherheit und führt im Betrieb gern zu Verwirrung. |
proto udp4 |
Nutzt UDP über IPv4 als Transportprotokoll. | UDP ist für VPN-Tunnel meist besser als TCP, weil TCP-over-TCP bei Paketverlust schlecht performt. udp4 erzwingt IPv4. |
Alternativen: udp für IPv4/IPv6 je nach System, tcp-server für TCP, tcp4-server für TCP nur IPv4. TCP nur verwenden, wenn UDP nicht möglich ist. |
dev tun0 |
Erstellt oder nutzt das TUN-Interface tun0. |
TUN ist Layer 3 und ideal für Routing zwischen Netzen. Der feste Name erleichtert Firewallregeln. | Alternative: dev tun lässt OpenVPN automatisch wählen. dev tap wäre Layer-2-Bridging und für dieses Site-to-Site-Konzept nicht empfehlenswert. |
topology subnet |
Vergibt Client-IP-Adressen wie in einem normalen Subnetz. | Damit kann ein Client z. B. 10.255.0.10/24 bekommen. Das ist verständlicher als alte /30-Paarungen. |
Alternative: topology net30 für sehr alte Clients. Für moderne und die meisten industriellen Geräte ist subnet sinnvoller. |
server 10.255.0.0 255.255.255.0 |
Aktiviert Servermodus und definiert das VPN-Transfernetz. | Der Server bekommt üblicherweise 10.255.0.1, Clients erhalten Adressen aus 10.255.0.0/24. Dieses Netz ist nur für den Tunnel. |
Du kannst jedes private, nicht überlappende Netz verwenden, z. B. 10.8.0.0/24. Wichtig ist: keine Überschneidung mit LANs. |
client-config-dir /etc/openvpn/server/modern/ccd |
Aktiviert client-spezifische Konfigurationsdateien. | Jeder Standort bekommt eine Datei mit seinem Common Name. Darin stehen feste VPN-IP und iroute. |
Der Pfad ist frei wählbar. Trennung je Instanz verhindert Fehlzuordnungen. |
ccd-exclusive |
Nur Clients mit vorhandener CCD-Datei dürfen verbinden. | Das ist für Site-to-Site wichtig: Kein Zertifikat soll ohne explizite Netzzuordnung online gehen. | Ohne diese Option könnten gültige Zertifikate ohne definierte Policy verbinden. Das ist für Betriebsnetze unsauber. |
route 192.168.101.0 255.255.255.0 |
Fügt auf Serverseite eine Route zum entfernten Standortnetz hinzu. | Der Linux-Kernel gibt Pakete zu diesem Netz an OpenVPN. OpenVPN braucht zusätzlich das passende iroute in der CCD-Datei. |
Für jeden Standort kommt eine weitere route-Zeile dazu. Bei vielen Standorten kann Routenmanagement über Scripts oder Konfigurationsmanagement erfolgen. |
ca .../ca.crt |
Pfad zum CA-Zertifikat. | Damit prüft der Server, ob Clientzertifikate von der richtigen CA signiert wurden. | Die CA-Datei ist öffentlich. Der private CA-Key darf nicht auf den VPN-Server. |
cert .../modern-server.crt |
Pfad zum Serverzertifikat. | Der Server weist sich damit gegenüber Clients aus. | Der Name ist frei, muss aber mit der Datei existieren. |
key .../modern-server.key |
Pfad zum privaten Server-Schlüssel. | Der private Schlüssel gehört zum Serverzertifikat und muss geheim bleiben. | Rechte: üblicherweise 600 root:root. |
dh none |
Deaktiviert klassische statische DH-Parameter. | Wir nutzen moderne elliptische Gruppen über tls-groups. Das ist für neue Clients zeitgemäßer. |
Für Legacy-Clients kann stattdessen dh /pfad/dh.pem nötig sein. Genau darum gibt es die zweite Instanz. |
tls-groups X25519:secp256r1:X448:secp384r1 |
Legt erlaubte TLS-Gruppen/Kurven in Prioritätsreihenfolge fest. | X25519 ist eine moderne Standardwahl. secp256r1 ist sehr kompatibel. X448 und secp384r1 bieten weitere starke Optionen. | Alternative: Option weglassen und Bibliotheksdefaults nutzen. Oder ecdh-curve prime256v1 für ältere Clients, aber das ist weniger modern. |
tls-server |
Setzt diese Instanz explizit in die TLS-Serverrolle. | Im Servermodus meist implizit, aber lesbar und eindeutig. | Normalerweise reicht server .... Explizit schadet hier nicht. |
remote-cert-tls client |
Prüft, ob die Gegenstelle ein Client-Zertifikat verwendet. | Verhindert, dass Zertifikate mit falscher Rolle akzeptiert werden. | Nicht weglassen. Alternativ gibt es spezifischere Prüfungen über verify-x509-name, die zusätzlich genutzt werden können. |
verify-client-cert require |
Erzwingt ein gültiges Clientzertifikat. | Ohne gültiges Zertifikat keine Verbindung. Das ist zentral für Site-to-Site. | Der Default ist in vielen Fällen bereits require, aber explizit dokumentiert ist besser. |
tls-version-min 1.2 |
Erlaubt nur TLS 1.2 oder höher. | TLS 1.0/1.1 gehören nicht mehr in ein neues betriebliches VPN. | Noch härter wäre TLS 1.3-only, aber das bricht viele Clients. Für OpenVPN-Umgebungen ist TLS 1.2+ der realistische harte Mindeststandard. |
data-ciphers AES-256-GCM:CHACHA20-POLY1305:AES-128-GCM |
Liste erlaubter Datenkanal-Cipher. | Nur moderne AEAD-Cipher. Kein CBC-Fallback in der modernen Instanz. | Du könntest AES-128-GCM vor CHACHA20-POLY1305 setzen, wenn AES-Hardwarebeschleunigung erwartet wird. Wichtig: kein BF-CBC. |
auth SHA256 |
Setzt SHA-256 als HMAC-Digest für relevante Kontroll-/Nicht-AEAD-Fälle. | SHA-256 ist ein robuster Standard. Bei AEAD-Ciphers ist der Datenkanal bereits integriert authentifiziert. | Alternativen: SHA384 oder SHA512. SHA1 nicht neu verwenden. |
tls-cert-profile preferred |
Verlangt brauchbare Zertifikats-/Signaturalgorithmen. | Schiebt alte SHA1-/zu schwache Zertifikate aus dem Weg. | Bei sehr alten Geräten kann legacy nötig sein. In diesem Dokument bleiben auch ältere Geräte bei neu erzeugten Zertifikaten, daher preferred. |
tls-crypt-v2 .../tc2-server.key |
Aktiviert TLS-Crypt-v2 für den Kontrollkanal. | Beste Wahl für moderne Setups: client-spezifische Zusatzschlüssel, Schutz vor Scans und Müllpaketen. | Alternativen: tls-crypt oder tls-auth. Für Legacy nutzen wir bewusst tls-auth. |
allow-compression no |
Verbietet Kompression. | Kompression in verschlüsselten Tunneln erhöht Angriffsfläche und ist für Site-to-Site meist unnötig. | Nicht compress setzen. Auch nicht „nur testweise“, diese berühmten letzten Worte der IT. |
crl-verify .../crl.pem |
Aktiviert Prüfung der Zertifikatssperrliste. | Verlorene oder kompromittierte Clients können gesperrt werden. | Ohne CRL musst du im Ernstfall CA oder Serverpolicy gröber ändern. CRL ist Pflicht für sauberen Betrieb. |
keepalive 10 60 |
Sendet Keepalive-Pings und erkennt tote Verbindungen. | Gerade Mobilfunk-/Industrieverbindungen profitieren davon. | Alternative: manuell ping und ping-restart setzen. keepalive ist die einfache Form. |
explicit-exit-notify 1 |
Informiert UDP-Clients beim Serverstopp/Restart. | Clients reconnecten sauberer und schneller. | Nur für UDP sinnvoll. Bei TCP nicht verwenden. |
persist-key |
Liest Schlüssel bei internen Restarts nicht neu. | Hilft, wenn OpenVPN nach Start Rechte reduziert. | Weglassen ist möglich, aber weniger robust. |
persist-tun |
Hält das TUN-Interface bei Restarts offen. | Verhindert unnötiges Interface-Flapping und reduziert Routingstörungen. | Weglassen führt zu mehr Bewegung im Netzwerkstack. Betrieb mag keine Bewegung. |
user nobody |
OpenVPN läuft nach Initialisierung als Benutzer nobody. |
Reduziert Schaden bei Prozesskompromittierung. | Manche Distributionen nutzen einen dedizierten Benutzer wie openvpn. Das ist sogar besser, wenn vorhanden. |
group nogroup |
OpenVPN wechselt in die Gruppe nogroup. |
Passend zu nobody auf Debian/Ubuntu. |
Auf RHEL heißt die Gruppe oft nobody. Mit getent group nogroup prüfen. |
verb 3 |
Setzt das Log-Level auf normalen Betriebswert. | Genug Informationen für Betrieb, nicht zu viel Rauschen. | Für Fehlersuche kurzzeitig verb 4 oder verb 5. Nicht dauerhaft extrem hoch loggen. |
12. Moderne CCD-Datei für einen Phoenix-Standort
Datei:
/etc/openvpn/server/modern/ccd/phoenix-modern-werk1
ifconfig-push 10.255.0.10 255.255.255.0
iroute 192.168.101.0 255.255.255.0
push "route 10.10.0.0 255.255.255.0"
| Zeile | Was macht sie? | Warum diese Wahl? | Alternativen / Hinweise |
|---|---|---|---|
ifconfig-push 10.255.0.10 255.255.255.0 |
Weist diesem Client immer die feste VPN-IP 10.255.0.10 zu. |
Feste Tunnel-IP macht Firewallregeln, Logs und Betrieb nachvollziehbar. | Bei topology net30 wäre die Syntax anders: dann braucht man ein IP-Paar. Mit topology subnet ist diese Form korrekt. |
iroute 192.168.101.0 255.255.255.0 |
Sagt OpenVPN intern: Dieses entfernte LAN gehört zu genau diesem Client. | Das ist der Kern deines „ein Zertifikat = ein Netzwerk“-Modells. | Ohne iroute kennt der Linux-Kernel vielleicht die Route, aber OpenVPN weiß nicht, zu welchem Client das Paket soll. |
push "route 10.10.0.0 255.255.255.0" |
Sendet dem Client eine Route zum zentralen LAN. | Der Phoenix-Router weiß dadurch, dass 10.10.0.0/24 über den VPN-Tunnel erreichbar ist. |
Viele Industrieclients ignorieren Push-Routen oder konfigurieren Remote Networks im Webinterface. Dann diese Route dort manuell eintragen. |
13. Moderne Instanz aktivieren
sudo install -m 640 modern.conf /etc/openvpn/server/modern.conf
sudo openvpn --config /etc/openvpn/server/modern.conf --test-crypto
sudo systemctl enable --now openvpn-server@modern
sudo systemctl status openvpn-server@modern
| Befehl | Was macht er? | Warum so? | Optionen / Alternativen |
|---|---|---|---|
sudo install -m 640 modern.conf /etc/openvpn/server/modern.conf |
Kopiert die Konfigurationsdatei an den OpenVPN-Serverpfad. | 640 verhindert unnötige Lesbarkeit durch normale Benutzer. |
Du kannst auch direkt mit einem Editor in /etc/openvpn/server/modern.conf schreiben. |
sudo openvpn --config ... --test-crypto |
Testet kryptografische Optionen der Konfiguration. | Findet Fehler bei Ciphers, TLS-Gruppen oder Pfaden früher. | Zusätzlich sudo openvpn --config ... im Vordergrund starten, wenn du detaillierte Fehlermeldungen brauchst. |
sudo systemctl enable --now openvpn-server@modern |
Aktiviert und startet die systemd-Instanz modern. |
OpenVPN lädt dabei /etc/openvpn/server/modern.conf. |
Nur starten: systemctl start .... Nur Boot-Aktivierung: systemctl enable .... |
sudo systemctl status openvpn-server@modern |
Zeigt Dienststatus und letzte Logs. | Erste Prüfung, ob der Dienst läuft. | Detaillierter: journalctl -u openvpn-server@modern -f. |
14. Kompatible PKI erstellen
make-cadir ~/easy-rsa-compat
cd ~/easy-rsa-compat
./easyrsa init-pki
./easyrsa build-ca
./easyrsa build-server-full compat-server nopass
./easyrsa build-client-full phoenix-legacy-werk1 nopass
./easyrsa gen-crl
Die Befehle entsprechen der modernen PKI. Der wichtige Unterschied ist nicht Easy-RSA selbst, sondern die spätere OpenVPN-Konfiguration. Auch ältere Geräte sollen neue, saubere Zertifikate bekommen. Altgerät heißt nicht: altes SHA1-Zertifikat aus irgendeinem Export von 2014 behalten, nur weil es noch blinkt.
15. Kompatible PKI-Dateien kopieren
sudo install -d -m 750 /etc/openvpn/server/compat/pki
sudo install -d -m 750 /etc/openvpn/server/compat/pki/issued
sudo install -d -m 700 /etc/openvpn/server/compat/pki/private
sudo cp pki/ca.crt /etc/openvpn/server/compat/pki/ca.crt
sudo cp pki/issued/compat-server.crt /etc/openvpn/server/compat/pki/issued/compat-server.crt
sudo cp pki/private/compat-server.key /etc/openvpn/server/compat/pki/private/compat-server.key
sudo cp pki/crl.pem /etc/openvpn/server/compat/crl.pem
sudo chown -R root:root /etc/openvpn/server/compat
sudo chmod 600 /etc/openvpn/server/compat/pki/private/compat-server.key
sudo chmod 644 /etc/openvpn/server/compat/crl.pem
16. Kompatible TLS-Auth- und DH-Dateien erzeugen
sudo openvpn --genkey secret /etc/openvpn/server/compat/ta.key
sudo chmod 600 /etc/openvpn/server/compat/ta.key
sudo openssl dhparam -out /etc/openvpn/server/compat/dh.pem 3072
sudo chmod 644 /etc/openvpn/server/compat/dh.pem
| Befehl | Was macht er? | Warum so? | Optionen / Alternativen |
|---|---|---|---|
sudo openvpn --genkey secret .../ta.key |
Erzeugt einen statischen Schlüssel für tls-auth. |
tls-auth ist älter und breiter unterstützt als tls-crypt-v2. Es schützt den Kontrollkanal per HMAC gegen fremde Pakete. |
tls-crypt wäre besser, wenn das Altgerät es unterstützt. tls-crypt-v2 ist modern, aber auf älteren Appliances oft nicht verfügbar. |
sudo chmod 600 .../ta.key |
Beschränkt Zugriff auf den statischen Schlüssel. | Der Key ist geheim und wird auch auf dem Client gebraucht. | Bei Verteilung an Phoenix-Geräte sicher übertragen, z. B. per SFTP, nicht per E-Mail im Klartext, weil wir keine Museumsführung durch Sicherheitsfehler brauchen. |
sudo openssl dhparam -out .../dh.pem 3072 |
Erzeugt klassische Diffie-Hellman-Parameter mit 3072 Bit. | Das ist kompatibler als moderne ECDH-only-Konfigurationen und bleibt trotzdem stark genug für eine Legacy-Instanz. | 4096 ist möglich, aber langsamer. 2048 ist kompatibler/schneller, aber weniger großzügig bei der Sicherheitsmarge. |
sudo chmod 644 .../dh.pem |
Macht die DH-Parameter lesbar. | DH-Parameter sind nicht geheim; OpenVPN muss sie lesen können. | 640 mit passender Gruppe ist möglich. |
17. Kompatible OpenVPN-Serverkonfiguration
Datei:
/etc/openvpn/server/compat.conf
port 1195
proto udp4
dev tun1
topology subnet
server 10.254.0.0 255.255.255.0
client-config-dir /etc/openvpn/server/compat/ccd
ccd-exclusive
route 192.168.201.0 255.255.255.0
ca /etc/openvpn/server/compat/pki/ca.crt
cert /etc/openvpn/server/compat/pki/issued/compat-server.crt
key /etc/openvpn/server/compat/pki/private/compat-server.key
dh /etc/openvpn/server/compat/dh.pem
tls-server
remote-cert-tls client
verify-client-cert require
tls-version-min 1.2
data-ciphers AES-256-GCM:AES-128-GCM:AES-256-CBC
data-ciphers-fallback AES-256-CBC
cipher AES-256-CBC
auth SHA256
tls-cert-profile preferred
tls-auth /etc/openvpn/server/compat/ta.key 0
allow-compression no
crl-verify /etc/openvpn/server/compat/crl.pem
keepalive 10 60
explicit-exit-notify 1
persist-key
persist-tun
user nobody
group nogroup
verb 3
17.1 Jede Zeile der kompatiblen Konfiguration erklärt
| Zeile | Was macht sie? | Warum diese Wahl? | Alternativen / Hinweise |
|---|---|---|---|
port 1195 |
OpenVPN lauscht für die kompatible Instanz auf UDP-Port 1195. | Da 1194 bereits von modern.conf genutzt wird, braucht diese Instanz einen zweiten Port. |
Mit zwei öffentlichen IPs könnte auch diese Instanz Port 1194 nutzen, gebunden an eine andere IP. Auf einer IP müssen Ports verschieden sein. |
proto udp4 |
Nutzt UDP über IPv4. | Auch für Altgeräte ist UDP normalerweise zuverlässiger für VPN als TCP. | TCP ist möglich, wenn Firewalls UDP blockieren. Dann proto tcp4-server, aber nur als Notlösung. |
dev tun1 |
Nutzt ein eigenes TUN-Interface für die kompatible Instanz. | Getrennt von tun0, damit Firewallregeln klar zwischen modern und legacy unterscheiden können. |
Automatische Benennung mit dev tun ist bequemer, aber schlechter für eindeutige Firewallregeln. |
topology subnet |
Verwendet normales Subnetzmodell für Client-IP-Zuweisung. | Auch viele ältere Geräte kommen damit klar. Es macht CCDs lesbarer. | Wenn ein sehr alter Client Probleme macht, kann topology net30 nötig sein. Dann müssen ifconfig-push-Zeilen angepasst werden. |
server 10.254.0.0 255.255.255.0 |
Definiert das VPN-Transfernetz der kompatiblen Instanz. | Getrennt vom modernen Netz, damit Logs, Routen und Firewallregeln eindeutig bleiben. | Jedes private, nicht überlappende Netz ist möglich. Nicht dasselbe Netz wie bei modern verwenden. |
client-config-dir /etc/openvpn/server/compat/ccd |
Aktiviert CCD-Dateien für Legacy-Clients. | Auch ältere Geräte werden pro Common Name fest gebunden. | Pfad frei wählbar, aber pro Instanz getrennt halten. |
ccd-exclusive |
Nur Clients mit CCD-Datei dürfen verbinden. | Gerade im Legacy-Bereich willst du keine Überraschungsclients. | Weglassen wäre bequemer und schlechter. Bequemlichkeit ist der natürliche Feind des Audits. |
route 192.168.201.0 255.255.255.0 |
Serverroute zum Legacy-Standortnetz. | Der Kernel gibt Pakete zu diesem Netz an die OpenVPN-Instanz. | Für jeden Legacy-Standort eigene Route hinzufügen. |
ca .../ca.crt |
CA der kompatiblen PKI. | Getrennte Vertrauensdomäne für Legacy-Clients. | Du könntest eine gemeinsame CA nutzen, aber getrennt ist sauberer. |
cert .../compat-server.crt |
Serverzertifikat der kompatiblen Instanz. | Separates Zertifikat verhindert Vermischung mit modern. | Name frei wählbar, Datei muss existieren. |
key .../compat-server.key |
Privater Serverkey der kompatiblen Instanz. | Muss geheim bleiben. | Rechte restriktiv setzen. |
dh /etc/openvpn/server/compat/dh.pem |
Nutzt klassische Diffie-Hellman-Parameter. | Das ist für ältere Clients zuverlässiger als ECDH-only mit dh none. |
Moderner wäre dh none plus ecdh-curve oder tls-groups. Für Legacy ist klassische DH robuster. |
tls-server |
Setzt TLS-Serverrolle. | Eindeutige Rollenverteilung. | Meist durch server implizit. |
remote-cert-tls client |
Prüft Client-Zertifikatrolle. | Auch alte Geräte sollen korrekte Clientzertifikate nutzen. | Nicht weglassen. |
verify-client-cert require |
Erzwingt Clientzertifikate. | Ohne Zertifikat keine Verbindung. | Benutzer/Passwort zusätzlich möglich, aber für Router-Site-to-Site normalerweise nicht nötig. |
tls-version-min 1.2 |
Erlaubt TLS 1.2 oder höher. | Das ist die harte Untergrenze. TLS 1.0/1.1 wird nicht zugelassen. | Wenn ein Gerät nur TLS 1.0 kann, sollte es ersetzt oder isoliert werden. Eine produktive Betriebsverbindung mit TLS 1.0 ist keine „Kompatibilität“, sondern eine Altlast mit Netzwerkkabel. |
data-ciphers AES-256-GCM:AES-128-GCM:AES-256-CBC |
Erlaubt moderne GCM-Cipher und als letzten Fallback AES-256-CBC. | GCM bleibt bevorzugt. CBC wird nur zugelassen, damit ältere Clients ohne moderne Cipher-Aushandlung funktionieren. | Härter wäre ohne CBC. Genau das macht modern.conf. Schwächer wäre Blowfish/Camellia/3DES. Nicht verwenden. |
data-ciphers-fallback AES-256-CBC |
Fallback für Clients ohne moderne Data-Cipher-Negotiation. | Manche ältere OpenVPN-Clients können die neue Cipher-Aushandlung nicht sauber. Dieser Fallback hält sie kompatibel. | Nur setzen, wenn du solche Geräte wirklich brauchst. Nicht in der modernen Instanz verwenden. |
cipher AES-256-CBC |
Legacy-Hinweis für ältere Clients/Kompatibilität. | Ältere Clientkonfigurationen erwarten oft explizit cipher AES-256-CBC. In neueren OpenVPN-Versionen ist data-ciphers maßgeblich. |
Auf modernen Clients besser GCM nutzen. Diese Zeile ist bewusst Legacy-Futter. |
auth SHA256 |
HMAC-Digest SHA-256. | Für CBC und tls-auth relevant und sicherer als SHA1. |
SHA384/SHA512 möglich, aber SHA256 ist breit kompatibel und sicher. |
tls-cert-profile preferred |
Erzwingt moderne Zertifikatsqualität. | Wir erzeugen neue Zertifikate, also gibt es keinen Grund für schwache Zertifikate. | Falls ein Altgerät alte SHA1-Zertifikate zwingend braucht, wäre legacy möglich. Das ist hier bewusst nicht empfohlen. |
tls-auth .../ta.key 0 |
Aktiviert HMAC-Schutz für den TLS-Kontrollkanal. 0 ist die Server-Key-Direction. |
Sehr kompatibel und trotzdem nützlich gegen fremde Pakete/Scans. | Besser wäre tls-crypt, falls der Client es kann. tls-crypt-v2 ist die moderne Variante, aber weniger kompatibel. |
allow-compression no |
Verbietet Kompression. | Auch für Legacy bleibt Kompression aus. Kompatibilität ist kein Freifahrtschein für bekannte Angriffsflächen. | Nicht compress setzen. Wenn ein Altclient Kompression erzwingt, muss dessen Konfig angepasst werden. |
crl-verify .../crl.pem |
Prüft gesperrte Zertifikate. | Geräte können verloren gehen oder ausgemustert werden. CRL macht Sperrung sauber möglich. | CRL regelmäßig nach Widerruf erneuern. |
keepalive 10 60 |
Prüft Tunnel-Lebendigkeit. | Gerade Mobilfunkrouter brauchen robuste Reconnect-Erkennung. | Werte können erhöht werden, wenn instabile Mobilfunkstrecken sonst zu hektisch reconnecten. |
explicit-exit-notify 1 |
Informiert UDP-Clients beim Serverstopp. | Sauberere Reconnects. | Bei TCP nicht verwenden. |
persist-key |
Hält Key-Material über interne Restarts. | Hilft bei Dienste-Reconnects nach Rechteabgabe. | Weglassen selten sinnvoll. |
persist-tun |
Hält TUN-Interface offen. | Stabilere Routen und weniger Flapping. | Weglassen erzeugt mehr Interface-Bewegung. |
user nobody |
Reduziert Prozessrechte. | Besser als dauerhaft root. | Dedizierter OpenVPN-Benutzer ist noch sauberer, wenn Distribution ihn anbietet. |
group nogroup |
Reduziert Gruppenzugehörigkeit. | Debian/Ubuntu-kompatibel. | Auf anderen Distributionen prüfen. |
verb 3 |
Normales Log-Level. | Geeignet für Dauerbetrieb. | verb 4 zur Fehlersuche, danach zurück. |
18. Kompatible CCD-Datei für einen Phoenix-Standort
Datei:
/etc/openvpn/server/compat/ccd/phoenix-legacy-werk1
ifconfig-push 10.254.0.10 255.255.255.0
iroute 192.168.201.0 255.255.255.0
push "route 10.10.0.0 255.255.255.0"
| Zeile | Was macht sie? | Warum diese Wahl? | Alternativen / Hinweise |
|---|---|---|---|
ifconfig-push 10.254.0.10 255.255.255.0 |
Feste VPN-IP für den Legacy-Phoenix. | Logs und Firewallregeln bleiben eindeutig. | Bei net30 andere Syntax nötig. |
iroute 192.168.201.0 255.255.255.0 |
Bindet das entfernte Legacy-LAN an genau diesen Client. | Kern des Site-to-Site-Routings. | Pro Client nur die Netze eintragen, die wirklich hinter diesem Router liegen. |
push "route 10.10.0.0 255.255.255.0" |
Teilt dem Client die Route zum zentralen LAN mit. | Damit Rückverkehr sauber über den Tunnel geht. | Wenn das Phoenix-Gerät Push-Routen ignoriert, Route im Phoenix-Webinterface als Remote Network setzen. |
19. Kompatible Instanz aktivieren
sudo install -m 640 compat.conf /etc/openvpn/server/compat.conf
sudo openvpn --config /etc/openvpn/server/compat.conf --test-crypto
sudo systemctl enable --now openvpn-server@compat
sudo systemctl status openvpn-server@compat
20. IP-Forwarding aktivieren
echo 'net.ipv4.ip_forward=1' | sudo tee /etc/sysctl.d/99-openvpn-routing.conf
sudo sysctl --system
| Befehl | Was macht er? | Warum so? | Optionen / Alternativen |
|---|---|---|---|
echo ... | sudo tee ... |
Schreibt die Kernel-Option für IPv4-Forwarding in eine persistente sysctl-Datei. | Der Server muss Pakete zwischen LAN und VPN weiterleiten dürfen. | Temporär ginge sudo sysctl -w net.ipv4.ip_forward=1, ist aber nach Reboot weg. |
sudo sysctl --system |
Lädt alle sysctl-Konfigurationen neu. | Die Änderung wird sofort aktiv, ohne Reboot. | sudo sysctl -p /etc/sysctl.d/99-openvpn-routing.conf lädt nur diese Datei. |
21. Firewall mit nftables
Datei:
/etc/nftables.conf
table inet filter {
chain input {
type filter hook input priority filter;
policy drop;
iif lo accept
ct state established,related accept
udp dport 1194 accept
udp dport 1195 accept
ip saddr 10.10.0.0/24 tcp dport 22 accept
}
chain forward {
type filter hook forward priority filter;
policy drop;
ct state established,related accept
iif "tun0" ip saddr 192.168.101.0/24 ip daddr 10.10.0.0/24 accept
oif "tun0" ip saddr 10.10.0.0/24 ip daddr 192.168.101.0/24 accept
iif "tun1" ip saddr 192.168.201.0/24 ip daddr 10.10.0.0/24 accept
oif "tun1" ip saddr 10.10.0.0/24 ip daddr 192.168.201.0/24 accept
}
}
21.1 Erklärung der Firewall-Regeln
| Regel | Was macht sie? | Warum so? | Optionen / Alternativen |
|---|---|---|---|
table inet filter |
Erstellt eine Tabelle für IPv4 und IPv6. | Auch wenn wir hier IPv4 routen, ist inet ein moderner Standard. |
table ip filter nur für IPv4 wäre auch möglich. |
chain input |
Regeln für Verkehr zum VPN-Server selbst. | Schützt den Serverdienst und Adminzugänge. | Input ist nicht Forwarding. Das wird gern verwechselt, weil Netzwerkbegriffe offenbar absichtlich Menschen ärgern. |
policy drop |
Standard: alles verwerfen, was nicht erlaubt ist. | Whitelist-Prinzip. Sicherer als nachträglich Dinge zu verbieten. | Für Testbetrieb kann accept helfen, produktiv ist drop besser. |
iif lo accept |
Erlaubt Loopback-Verkehr. | Lokale Prozesse brauchen Loopback. | Nicht entfernen. Viele Dienste erwarten das. |
ct state established,related accept |
Erlaubt Antworten zu bestehenden Verbindungen. | Ohne diese Regel würde selbst erlaubter Verkehr keine Rückantwort bekommen. | Connection Tracking ist Standard bei zustandsbehafteten Firewalls. |
udp dport 1194 accept |
Erlaubt moderne OpenVPN-Instanz. | Notwendig für modern.conf. |
Wenn du Port änderst, hier mitändern. |
udp dport 1195 accept |
Erlaubt kompatible OpenVPN-Instanz. | Notwendig für compat.conf. |
Bei zwei öffentlichen IPs und gleichem Port anders lösen. |
ip saddr 10.10.0.0/24 tcp dport 22 accept |
Erlaubt SSH nur aus dem zentralen LAN. | Adminzugang sollte nicht aus dem Internet offen sein. | Besser: dediziertes Adminnetz, Jump Host oder Out-of-band-Management. |
chain forward |
Regeln für weitergeleitete Pakete zwischen VPN und LAN. | Site-to-Site-Verkehr läuft durch Forwarding, nicht Input. | Hier liegt die eigentliche Zugriffskontrolle. |
iif "tun0" ip saddr 192.168.101.0/24 ip daddr 10.10.0.0/24 accept |
Erlaubt Verkehr vom modernen Phoenix-LAN ins zentrale LAN. | Nur das erwartete Quellnetz darf über tun0 kommen. |
Noch restriktiver: nur einzelne Zielhosts und Ports erlauben. |
oif "tun0" ip saddr 10.10.0.0/24 ip daddr 192.168.101.0/24 accept |
Erlaubt Rück-/Hinverkehr vom zentralen LAN zum modernen Phoenix-LAN. | Bidirektionaler Site-to-Site-Zugriff. | Für reine Fernwartung kann man Richtung und Ports stärker einschränken. |
iif "tun1" ... 192.168.201.0/24 ... |
Erlaubt Verkehr vom kompatiblen Phoenix-LAN ins zentrale LAN. | Legacy-Clients werden getrennt von modern behandelt. | Bei höherem Risiko Legacy nur zu einzelnen Wartungsservern zulassen. |
oif "tun1" ... 192.168.201.0/24 ... |
Erlaubt Verkehr vom zentralen LAN zum kompatiblen Phoenix-LAN. | Notwendig für bidirektionale Kommunikation. | Ports einschränken, wenn möglich. |
Regeln laden:
sudo nft -c -f /etc/nftables.conf
sudo systemctl reload nftables
sudo nft list ruleset
| Befehl | Was macht er? | Warum so? | Optionen / Alternativen |
|---|---|---|---|
sudo nft -c -f /etc/nftables.conf |
Prüft die Syntax, ohne Regeln zu laden. | Verhindert, dass du dich mit einer kaputten Firewall selbst aussperrst. | Immer vor Reload ausführen. Wirklich. |
sudo systemctl reload nftables |
Lädt die Firewallregeln neu. | Aktiviert die neue Policy. | restart geht auch, reload ist meist sauberer. |
sudo nft list ruleset |
Zeigt aktive nftables-Regeln. | Kontrolle, ob wirklich geladen wurde, was dokumentiert ist. | Für gezielte Analyse: nft list table inet filter. |
22. Rückrouten im zentralen LAN
Alle Systeme im zentralen LAN müssen wissen, wie sie die Phoenix-Netze erreichen. Am besten setzt du die Routen auf dem zentralen LAN-Gateway.
ip route add 192.168.101.0/24 via 10.10.0.5
ip route add 192.168.201.0/24 via 10.10.0.5
10.10.0.5 ist hier die LAN-IP des OpenVPN-Servers.
| Befehl | Was macht er? | Warum so? | Optionen / Alternativen |
|---|---|---|---|
ip route add 192.168.101.0/24 via 10.10.0.5 |
Sagt dem LAN-Gateway: Das moderne Phoenix-LAN erreichst du über den OpenVPN-Server. | Ohne Rückroute gehen Antworten ins Default-Gateway und verschwinden. | Wenn der OpenVPN-Server selbst das Default-Gateway des LANs ist, brauchst du diese Zusatzroute eventuell nicht. |
ip route add 192.168.201.0/24 via 10.10.0.5 |
Dasselbe für das kompatible Phoenix-LAN. | Jedes entfernte LAN braucht eine Route. | Bei vielen Standorten statische Routen zentral dokumentieren oder per Routingprotokoll lösen. |
23. Clientdateien für Phoenix-Geräte
23.1 Moderne Variante
Auf das Phoenix-Gerät bzw. in dessen OpenVPN-Client-Konfiguration gehören:
ca.crtphoenix-modern-werk1.crtphoenix-modern-werk1.keyphoenix-modern-werk1-tc2.keyfürtls-crypt-v2- Serveradresse/FQDN
- Port
1194 - UDP
- TUN/routed mode
- lokales Netz
192.168.101.0/24 - Remote-Netz
10.10.0.0/24
23.2 Kompatible Variante
ca.crtphoenix-legacy-werk1.crtphoenix-legacy-werk1.keyta.keyfürtls-auth- Key direction beim Client:
1 - Serveradresse/FQDN
- Port
1195 - UDP
- TUN/routed mode
- lokales Netz
192.168.201.0/24 - Remote-Netz
10.10.0.0/24
Kein NAT auf dem Phoenix aktivieren, wenn echte bidirektionale Site-to-Site-Kommunikation gewünscht ist. NAT nur verwenden, wenn Netze überlappen oder ein Gerät technisch nicht sauber routen kann. NAT macht Fehler nicht weg, es zieht ihnen nur eine Jacke an.
24. Zertifikat widerrufen
Wenn ein Gerät verloren geht, ausgetauscht oder kompromittiert wird:
cd ~/easy-rsa-modern
./easyrsa revoke phoenix-modern-werk1
./easyrsa gen-crl
sudo cp pki/crl.pem /etc/openvpn/server/modern/crl.pem
sudo systemctl reload openvpn-server@modern
Für die kompatible Instanz entsprechend:
cd ~/easy-rsa-compat
./easyrsa revoke phoenix-legacy-werk1
./easyrsa gen-crl
sudo cp pki/crl.pem /etc/openvpn/server/compat/crl.pem
sudo systemctl reload openvpn-server@compat
| Befehl | Was macht er? | Warum so? | Optionen / Alternativen |
|---|---|---|---|
./easyrsa revoke NAME |
Markiert das Zertifikat als widerrufen. | Das Zertifikat soll nicht mehr verbinden dürfen. | Name muss dem Zertifikatsnamen/Common Name entsprechen. |
./easyrsa gen-crl |
Erzeugt eine aktualisierte CRL. | OpenVPN liest nicht die Easy-RSA-Datenbank, sondern die CRL-Datei. | Nach jedem Widerruf erforderlich. |
sudo cp pki/crl.pem ... |
Kopiert die neue CRL in den OpenVPN-Pfad. | Nur dann nutzt der Server den neuen Sperrstand. | Mit Konfigurationsmanagement automatisieren, wenn viele Standorte existieren. |
sudo systemctl reload ... |
Lädt den OpenVPN-Dienst neu. | Damit die neue CRL verwendet wird. | Wenn Reload nicht reicht, restart. Kurze Unterbrechung beachten. |
25. Wichtige Tests
sudo openvpn --version
sudo openvpn --show-groups
sudo openvpn --show-ciphers
sudo openvpn --show-digests
journalctl -u openvpn-server@modern -f
journalctl -u openvpn-server@compat -f
ip addr show tun0
ip addr show tun1
ip route
ping 10.255.0.10
ping 192.168.101.1
ping 10.254.0.10
ping 192.168.201.1
| Befehl | Was prüft er? | Warum wichtig? |
|---|---|---|
openvpn --version |
OpenVPN-Version und verwendete Crypto-Bibliothek. | Optionen wie tls-groups hängen von Version und Bibliothek ab. |
openvpn --show-groups |
Verfügbare TLS-Gruppen/Kurven. | Wichtig für die moderne Instanz. |
openvpn --show-ciphers |
Verfügbare Datenkanal-Cipher. | Prüft, ob GCM/ChaCha20/CBC verfügbar sind. |
openvpn --show-digests |
Verfügbare HMAC-Digests. | Prüft SHA256-Unterstützung. |
journalctl -u ... -f |
Live-Logs der Instanz. | Beste erste Diagnose bei Verbindungsproblemen. |
ip addr show tun0/tun1 |
Existenz und IPs der Tunnelinterfaces. | Zeigt, ob OpenVPN Interface und Server-IP gesetzt hat. |
ip route |
Kernel-Routingtabelle. | Prüft, ob Routen zu entfernten LANs existieren. |
ping ... |
Basis-Erreichbarkeit. | Ping ist kein vollständiger Test, aber ein guter Anfang. Danach Porttests machen. |
26. Typische Fehlerbilder
| Symptom | Wahrscheinliche Ursache | Prüfung | Lösung |
|---|---|---|---|
| Client verbindet, LAN dahinter ist nicht erreichbar. | iroute fehlt oder falscher CCD-Dateiname. |
journalctl, CCD-Datei, Common Name prüfen. |
CCD-Datei exakt nach CN benennen und iroute setzen. |
| Server-LAN erreicht Phoenix, aber Antwort kommt nicht zurück. | Rückroute im zentralen Gateway oder Phoenix-LAN fehlt. | ip route auf Gateway/Phoenix prüfen. |
Route zum Gegennetz über OpenVPN/Phoenix setzen. |
| TLS-Handshake schlägt bei modern fehl. | Client unterstützt tls-crypt-v2, tls-groups oder Cipher nicht. |
Logs mit verb 4, Clientfähigkeiten prüfen. |
Gerät in kompatible Instanz verschieben. |
| Kompatibler Client verbindet nicht wegen Cipher. | Client nutzt anderen Legacy-Cipher. | Clientconfig prüfen: cipher. |
Client auf AES-256-CBC stellen. Keine Blowfish-Fallbacks neu einführen. |
| Clientzertifikat wird abgelehnt. | Falsche CA, CRL, Zertifikatsrolle oder Ablaufdatum. | openssl x509 -in client.crt -text -noout. |
Neues Zertifikat erzeugen und korrekt verteilen. |
OpenVPN startet nicht nach user nobody. |
Dateien nach Rechteabgabe nicht lesbar, oft CRL. | journalctl prüfen. |
CRL lesbar machen, z. B. chmod 644 crl.pem oder passende Gruppe setzen. |
27. Optionen, die bewusst nicht verwendet werden
| Option | Warum nicht? |
|---|---|
duplicate-cn |
Würde erlauben, dass mehrere Clients dasselbe Zertifikat nutzen. Das zerstört dein Modell „ein Zertifikat = ein Netzwerk“. Nicht verwenden. |
client-to-client |
Würde VPN-Clients untereinander sprechen lassen. Für zentrale Fernwartung meist unnötig und riskant. Nur aktivieren, wenn Standort-zu-Standort-Kommunikation ausdrücklich benötigt wird. |
push "redirect-gateway def1" |
Würde gesamten Internetverkehr des Clients über den VPN-Server schicken. Für Site-to-Site-Fernwartung unnötig. |
compress |
Kompression bleibt aus Sicherheitsgründen deaktiviert. |
compat-mode |
OpenVPN warnt, dass diese Option Defaults auf weniger empfohlene Werte zurücksetzen kann. Besser einzelne Kompatibilitätsoptionen bewusst setzen. |
cipher BF-CBC |
Blowfish/CBC ist historischer Altbestand und gehört nicht in neue Konfigurationen. |
tls-version-min 1.0 |
Für neue betriebliche Setups nicht mehr akzeptabel. Wenn ein Gerät das braucht, gehört es in ein stark isoliertes Migrationsprojekt, nicht in normale Produktion. |
28. Wann welche Instanz?
| Gerät/Client | Instanz | Begründung |
|---|---|---|
| Aktueller OpenVPN-Client 2.5/2.6, aktueller Linux-/Windows-Client, moderne Appliance. | modern.conf |
AEAD-Cipher, tls-crypt-v2, moderne Gruppen, keine Legacy-Fallbacks. |
| Phoenix-/Industriegerät mit Unterstützung für AES-GCM und tls-crypt-v2. | modern.conf |
Wenn getestet stabil: modern verwenden. |
| Phoenix-/Industriegerät mit älterem OpenVPN-Stack, kein tls-crypt-v2, eventuell nur AES-256-CBC. | compat.conf |
Weiterhin TLS 1.2+, Zertifikate, CRL und Firewall, aber mit Legacy-Fallback. |
| Gerät kann nur TLS 1.0, Blowfish oder Kompression. | Keine der beiden Instanzen ohne Sonderfreigabe. | Das ist nicht „älter“, das ist ein Sicherheitsproblem mit Gehäuse. Ersatz oder isolierte Übergangslösung planen. |
29. Betriebs-Checkliste
- Für jeden Standort eindeutiges LAN-Netz vergeben.
- Pro Standort eigenes Zertifikat erzeugen.
- Common Name exakt dokumentieren.
- CCD-Datei mit exakt gleichem Namen erstellen.
- Feste VPN-IP vergeben.
iroutefür das entfernte Standortnetz setzen.routein der Serverinstanz ergänzen.- Firewallregel für genau dieses Standortnetz ergänzen.
- Rückroute im zentralen LAN setzen.
- Phoenix-Firewall für VPN ↔ LAN konfigurieren.
- Keine Kompression.
- Kein
duplicate-cn. - CRL nach jedem Widerruf neu erzeugen und verteilen.
- Logs prüfen und Zertifikatsablauf überwachen.
30. Kurzfazit
modern.conf ist die Zielkonfiguration: stark, sauber und ohne Legacy-Ballast. compat.conf ist die pragmatische Betriebsvariante für ältere Phoenix-/Industrieclients: weiterhin kontrolliert, getrennt, mit Zertifikaten, CRL, Firewall und TLS 1.2+, aber mit bewusstem AES-256-CBC-Fallback und tls-auth.
Der entscheidende Sicherheitsgewinn entsteht nicht durch eine einzelne magische Zeile. Er entsteht durch die Kombination aus getrennter Instanz, eindeutiger PKI, ccd-exclusive, iroute, festen IPs, restriktiver Firewall, deaktivierter Kompression und sauberer Zertifikatssperrung. Kryptografie ist wichtig, aber Routingfehler und Copy-Paste-Zertifikate ruinieren dir den Tag meist schneller. Menschen nennen das dann „gewachsene Infrastruktur“.
AI
GSD mit GitHub Copilot in VS Code nutzen
Diese Anleitung beschreibt, wie GSD installiert und mit GitHub Copilot Chat in VS Code genutzt wird. Die Installation wird als root ausgeführt.
1. Was ist GSD?
GSD steht für Get Shit Done. Es ist ein Workflow-System für KI-gestützte Entwicklung. GSD ergänzt Tools wie GitHub Copilot Chat, Claude Code, Codex, Cursor oder ähnliche Coding-Assistenten um strukturierte Abläufe.
Ohne GSD arbeitet ein KI-Chat oft sehr frei: Man beschreibt ein Problem, bekommt Code zurück, testet etwas, korrigiert wieder, verliert Kontext und irgendwann weiß niemand mehr genau, was eigentlich gebaut werden sollte. Willkommen in der modernen Softwareentwicklung, jetzt mit noch mehr Chatfenstern.
GSD soll genau dieses Problem lösen. Es zwingt die KI in einen klareren Ablauf:
- Projekt oder Codebasis analysieren
- Ziele und Anforderungen erfassen
- Arbeit in Phasen zerlegen
- Aufgaben planen
- Änderungen schrittweise umsetzen
- Ergebnisse prüfen
- Fortschritt dokumentieren
Das Ziel ist nicht, dass die KI einfach wild Dateien ändert. Das Ziel ist ein nachvollziehbarer Entwicklungsprozess mit Planung, Status, Aufgaben und Prüfung.
2. Welches Problem löst GSD?
GSD hilft besonders bei diesen typischen Problemen:
- Kontextverlust: Die KI vergisst nach längeren Chats, worum es eigentlich ging.
- Planloses Coden: Änderungen werden gemacht, ohne dass vorher klar ist, was genau erreicht werden soll.
- Zu große Aufgaben: Ein Feature wird nicht in kleine, prüfbare Schritte zerlegt.
- Fehlende Nachvollziehbarkeit: Es ist später unklar, warum eine Änderung gemacht wurde.
- Schlechte Verifikation: Code wird erzeugt, aber nicht sauber geprüft.
GSD arbeitet deshalb mit Kommandos wie /gsd-new-project, /gsd-discuss-phase, /gsd-plan-phase, /gsd-execute-phase und /gsd-verify-work.
3. Voraussetzungen
Für die Installation werden benötigt:
- Debian oder ein ähnliches Linux-System
- Root-Zugriff
- Git
- Node.js 22 oder neuer
- npm
- VS Code mit GitHub Copilot Chat
Die folgenden Befehle werden als root ausgeführt.
4. Node.js und npm installieren
Zuerst werden die benötigten Pakete installiert:
apt-get update
apt-get install -y ca-certificates curl gnupg
Danach wird Node.js 22 eingerichtet:
curl -fsSL https://deb.nodesource.com/setup_22.x -o nodesource_setup.sh
bash nodesource_setup.sh
apt-get install -y nodejs
Anschließend prüfen:
node --version
npm --version
npx --version
git --version
Erwartet wird ungefähr:
node: Version 22 oder neuer
npm: Version 10 oder neuer
git: installiert
5. GSD global installieren
Damit die GSD-Hilfsprogramme dauerhaft verfügbar sind, wird GSD global installiert:
npm install -g @opengsd/get-shit-done-redux@latest
Danach prüfen:
which get-shit-done-redux
which gsd-sdk
gsd-sdk --help
Wichtig ist, dass gsd-sdk gefunden wird. Einige GSD-Workflows verwenden dieses Hilfsprogramm intern.
6. GSD in einem Projekt installieren
Nun in den gewünschten Projektordner wechseln:
cd /pfad/zum/projekt
Danach prüfen, ob es sich um ein Git-Projekt handelt:
git status
Anschließend GSD für GitHub Copilot lokal im Projekt installieren:
get-shit-done-redux --copilot --local --profile=core
Dadurch wird im Projekt ein Verzeichnis .github angelegt. Darin liegen unter anderem:
.github/copilot-instructions.md.github/skills/.github/get-shit-done/.github/gsd-file-manifest.json.github/gsd-install-state.json
Installation prüfen:
ls -la .github
find .github -maxdepth 3 -type f | sort
7. GSD-Dateien ins Git übernehmen
Wenn GSD dauerhaft Teil des Projekts sein soll, sollten die GSD-Dateien committed werden:
git status
git add .github
git commit -m "Add GSD Copilot workflow configuration"
Danach sind die Copilot-Anweisungen und GSD-Skills im Repository versioniert. Das ist sinnvoll, damit alle Beteiligten mit denselben KI-Regeln arbeiten.
8. GSD in VS Code testen
Das Projekt in VS Code öffnen. Danach GitHub Copilot Chat öffnen und folgenden Befehl senden:
/gsd-help
Wenn GSD korrekt erkannt wird, zeigt Copilot eine Übersicht der verfügbaren GSD-Kommandos an.
Für ein bestehendes Projekt ist danach dieser Befehl sinnvoll:
/gsd-map-codebase
Damit analysiert GSD die vorhandene Codebasis und kann spätere Aufgaben besser einordnen.
9. GSD für ein neues Projekt nutzen
Für ein neues Projekt wird zuerst ein leerer oder vorbereiteter Projektordner angelegt und als Git-Repository initialisiert:
mkdir mein-neues-projekt
cd mein-neues-projekt
git init
Danach GSD im Projekt installieren:
get-shit-done-redux --copilot --local --profile=core
Danach das Projekt in VS Code öffnen und in Copilot Chat starten mit:
/gsd-new-project
GSD fragt dann nach Ziel, Umfang, Anforderungen und gewünschter Struktur. Daraus erstellt es eine Projektbasis mit Planungsdokumenten und nächsten Arbeitsschritten.
10. Typischer Workflow mit GSD
Ein normaler GSD-Ablauf sieht so aus:
- Projekt oder Feature beschreiben
- Phase besprechen
- Phase planen
- Phase umsetzen lassen
- Ergebnis prüfen
- Fortschritt committen
- Nächste Phase bearbeiten
10.1 Projektstatus anzeigen
/gsd-progress
Zeigt, wo das Projekt steht und welche nächsten Schritte sinnvoll sind.
10.2 Eine Phase besprechen
/gsd-discuss-phase 1
Dieser Schritt dient dazu, Ziel, Annahmen, Risiken und offene Fragen der Phase zu klären.
10.3 Eine Phase planen
/gsd-plan-phase 1
GSD erstellt daraus einen konkreten Plan. Dieser Plan sollte geprüft werden, bevor die KI Änderungen am Projekt macht.
10.4 Eine Phase ausführen
/gsd-execute-phase 1
GSD setzt die geplanten Aufgaben um. Danach sollte immer geprüft werden, welche Dateien geändert wurden.
git status
git diff
10.5 Arbeit prüfen
/gsd-verify-work 1
Dieser Schritt prüft, ob die Phase wirklich abgeschlossen ist. Das ist wichtig, weil „Code wurde erzeugt“ nicht automatisch bedeutet, dass „Code funktioniert“. Eine Erkenntnis, für die die Menschheit offenbar erst KI gebraucht hat.
11. Todos mit GSD erstellen
Kleine Aufgaben, Ideen oder Backlog-Einträge können mit GSD erfasst werden.
Beispiel:
/gsd-capture Todo: Login-Seite validieren und Fehlermeldungen verbessern
Weitere Beispiele:
/gsd-capture Idee: Statusseite für VPN-Verbindungen ergänzen
/gsd-capture Bug: Formular speichert leere Werte ohne Fehlermeldung
/gsd-capture Backlog: Exportfunktion für Konfigurationsdaten ergänzen
Danach kann mit folgendem Befehl geprüft werden, was als Nächstes ansteht:
/gsd-progress
12. Todos abarbeiten lassen
Für kleine, klar begrenzte Aufgaben kann /gsd-quick genutzt werden:
/gsd-quick Setze den offenen Todo "Login-Seite validieren und Fehlermeldungen verbessern" um.
Für sehr kleine Änderungen eignet sich /gsd-fast:
/gsd-fast "Korrigiere den Tippfehler in der Überschrift der Startseite."
Für größere Aufgaben sollte eine eigene Phase genutzt werden:
/gsd-discuss-phase 2
/gsd-plan-phase 2
/gsd-execute-phase 2
/gsd-verify-work 2
Nach jeder Umsetzung prüfen:
git status
git diff
Wenn die Änderungen passen:
git add .
git commit -m "Implement planned GSD changes"
13. Sichere Arbeitsweise
GSD ist hilfreich, aber es bleibt ein KI-gestütztes Werkzeug. Deshalb sollte man es wie einen sehr schnellen Junior-Entwickler behandeln: produktiv, motiviert und gelegentlich komplett überzeugt von Unsinn.
Empfohlene Regeln:
- Vor jeder größeren Aufgabe erst planen lassen.
- Vor Änderungen immer klären, welche Dateien betroffen sind.
- Nach Änderungen immer
git statusundgit diffprüfen. - Nicht blind committen.
- Keine sensiblen Zugangsdaten in Prompts schreiben.
- Große Aufgaben in kleine Phasen zerlegen.
- Tests ausführen, wenn das Projekt Tests besitzt.
14. Nützliche GSD-Kommandos
| Kommando | Zweck |
|---|---|
/gsd-help |
Zeigt die GSD-Hilfe an. |
/gsd-map-codebase |
Analysiert eine bestehende Codebasis. |
/gsd-new-project |
Startet einen neuen GSD-Projektworkflow. |
/gsd-progress |
Zeigt aktuellen Stand und nächste Schritte. |
/gsd-capture |
Speichert Ideen, Todos, Bugs oder Backlog-Einträge. |
/gsd-discuss-phase <N> |
Bespricht Ziel und Rahmen einer Phase. |
/gsd-plan-phase <N> |
Erstellt einen konkreten Plan für eine Phase. |
/gsd-execute-phase <N> |
Setzt eine geplante Phase um. |
/gsd-verify-work <N> |
Prüft, ob die Arbeit korrekt abgeschlossen wurde. |
/gsd-quick |
Bearbeitet eine kleine Aufgabe mit GSD-Struktur. |
/gsd-fast |
Bearbeitet eine sehr kleine Änderung direkt. |
15. Beispiel: Kompletter Ablauf
Beispiel für ein neues Feature:
/gsd-capture Todo: Benutzerrollen im Adminbereich verbessern
/gsd-progress
/gsd-discuss-phase 1
/gsd-plan-phase 1
/gsd-execute-phase 1
/gsd-verify-work 1
Danach im Terminal prüfen:
git status
git diff
Wenn alles passt:
git add .
git commit -m "Improve admin user roles"
16. Zusammenfassung
GSD macht aus einem freien KI-Chat einen strukturierteren Entwicklungsprozess. Es hilft dabei, Anforderungen, Planung, Umsetzung, Todos und Prüfung sauberer zu organisieren.
Der wichtigste Start für bestehende Projekte:
/gsd-map-codebase
/gsd-progress
Der wichtigste Start für neue Projekte:
/gsd-new-project
Der wichtigste Sicherheitsgriff bleibt trotzdem:
git status
git diff
Denn auch mit GSD gilt: Vertrauen ist gut, Versionskontrolle ist besser.
Linux - Verschlüsselung
Linux - LUKS LVM - Dropbear-initramfs
Verschlüsseltes System per Dropbear-Initramfs über SSH entsperren
Diese Anleitung gilt für Debian/Ubuntu-Systeme mit initramfs-tools und einer verschlüsselten Root-Partition. Die erste Variante verwendet ein normales, ungetaggtes Netzwerkinterface. Die zweite Variante verwendet ein getaggtes IEEE-802.1Q-VLAN.
Vor dem Neustart: Konsolen- oder KVM/IPMI-Zugriff bereithalten. Eine falsche Interface-, IP-, Gateway- oder VLAN-Konfiguration kann den SSH-Zugriff während des Bootens verhindern. Die normale Passworteingabe an der Konsole bleibt der Rückfallweg.
Anleitung 1: Dropbear-Initramfs ohne VLAN einrichten
Voraussetzungen
- Die Root-Partition ist verschlüsselt und wird bereits beim Booten nach einer Passphrase fragen.
- Der Client kann das Servernetz während der Initramfs-Phase erreichen.
- Eine statische IP-Adresse, Netzmaske und ein Gateway sind bekannt.
- Die Befehle auf dem Server werden als
rootoder übersudoausgeführt.
1. Netzwerkinformationen ermitteln
Interface, IP-Adresse und Default-Gateway anzeigen:
ip -br address
ip route show defaultBeispiel:
Interface: enp4s0f0
IP-Adresse: 10.100.0.2
Netzmaske: 255.255.0.0
Gateway: 10.100.0.12. Pakete installieren
apt update
apt install -y dropbear-initramfs cryptsetup-initramfs3. Statische Initramfs-Netzwerkkonfiguration eintragen
Datei öffnen:
nano /etc/initramfs-tools/initramfs.confFolgende Werte ergänzen beziehungsweise vorhandene Werte ersetzen:
DEVICE=enp4s0f0
IP=10.100.0.2::10.100.0.1:255.255.0.0::enp4s0f0:noneAufbau der IP-Zeile:
IP=<Client-IP>:<Server-IP>:<Gateway>:<Netzmaske>:<Hostname>:<Interface>:<Autoconf>Bei einer statischen Adresse bleiben Server-IP und Hostname im Beispiel leer. none deaktiviert die automatische Konfiguration per DHCP.
4. Dropbear absichern und Port festlegen
Datei öffnen:
nano /etc/dropbear/initramfs/dropbear.confEmpfohlene Basiskonfiguration:
DROPBEAR_OPTIONS="-I 300 -j -k -s -p 2222"Option | Bedeutung |
|---|---|
| Inaktive Verbindung nach 300 Sekunden trennen |
| Lokales Port-Forwarding deaktivieren |
| Remote-Port-Forwarding deaktivieren |
| Passwortanmeldung deaktivieren; nur Schlüssel erlauben |
| Separaten SSH-Port für das Initramfs verwenden |
5. SSH-Schlüssel auf dem Client erzeugen
ssh-keygen -t ed25519 \
-f ~/.ssh/id_initramfs_unlock_System_1 \
-C "Initramfs unlock for System_1"Den öffentlichen Schlüssel anzeigen:
cat ~/.ssh/id_initramfs_unlock_System_1.pubDer private Schlüssel verbleibt ausschließlich auf dem Client. Nur die Datei mit der Endung .pub wird auf den Server übertragen.6. Öffentlichen Schlüssel auf dem Server hinterlegen
install -d -m 0700 /etc/dropbear/initramfs
nano /etc/dropbear/initramfs/authorized_keys
chmod 0600 /etc/dropbear/initramfs/authorized_keysIn authorized_keys steht der vollständige öffentliche Schlüssel in einer Zeile:
no-port-forwarding,no-agent-forwarding,no-X11-forwarding ssh-ed25519 AAAAC3... Initramfs unlock for System_1Ein zugelassener Schlüssel ermöglicht eine Root-Shell im Initramfs. Den privaten Schlüssel deshalb wie ein Administrationspasswort schützen und bei Verlust sofort aus authorized_keys entfernen.7. Initramfs neu erzeugen und Inhalt prüfen
update-initramfs -u -k all
lsinitramfs /boot/initrd.img-$(uname -r) | \
grep -E 'dropbear|authorized_keys|cryptroot-unlock'Die Ausgabe sollte unter anderem Dropbear, authorized_keys und cryptroot-unlock enthalten.
8. Komfortablen SSH-Zugriff auf dem Client einrichten
~/.ssh/config ergänzen:
Host System_1-unlock
HostName 10.100.0.2
User root
Port 2222
IdentityFile ~/.ssh/id_initramfs_unlock_System_1
IdentitiesOnly yes
PasswordAuthentication no
UserKnownHostsFile ~/.ssh/known_hosts.initramfsDie separate known_hosts-Datei verhindert Konflikte zwischen dem Host-Key des Initramfs und dem Host-Key des normal gestarteten SSH-Servers.
9. Neustarten und entsperren
rebootSobald der Server an der Festplattenabfrage wartet, vom Client verbinden:
ssh System_1-unlockIn der Initramfs-Shell:
cryptroot-unlockNach erfolgreicher Passworteingabe wird die SSH-Verbindung normalerweise beendet und der reguläre Bootvorgang fortgesetzt.
Fehlersuche
- Keine Verbindung: Interface-Name, IP, Netzmaske, Gateway, Switchport und Firewall prüfen.
- Netzwerkkarte fehlt: Den Treiber aus
basename "$(readlink -f /sys/class/net/enp4s0f0/device/driver/module)"in/etc/initramfs-tools/moduleseintragen und das Initramfs erneut bauen. - Konfiguration wird ignoriert: Mit
cat /proc/cmdlinenach einem vorhandenenip=-Bootparameter suchen. Dieser kann die Werte ausinitramfs.confüberschreiben. - SSH-Key wird abgelehnt: Eine vollständige Schlüsselzeile sowie Rechte
0700für das Verzeichnis und0600fürauthorized_keysprüfen. - Host-Key-Warnung: Den separaten Port und
UserKnownHostsFile ~/.ssh/known_hosts.initramfsverwenden.
Anleitung 2: Dropbear-Initramfs über Tagged VLAN einrichten
Voraussetzungen
- Der Switchport zum Server transportiert das gewünschte VLAN getaggt.
- Das VLAN ist auf allen beteiligten Trunks erlaubt.
- Die Root-Partition ist verschlüsselt und wird im Initramfs entsperrt.
- Das physische Parent-Interface, die VLAN-ID, IP-Adresse, Netzmaske und das Gateway sind bekannt.
Beispielwerte:
Parent-Interface: enp1s0
VLAN-ID: 40
VLAN-Interface: enp1s0.40
IP-Adresse: 10.15.32.253
Netzmaske: 255.255.248.0
Gateway: 10.15.39.254Die Initramfs-Netzwerkkonfiguration gilt nur während der frühen Bootphase. Das gestartete Betriebssystem muss das VLAN zusätzlich über Netplan, systemd-networkd oder /etc/network/interfaces konfigurieren.1. Pakete installieren
apt update
apt install -y dropbear-initramfs cryptsetup-initramfs iproute22. VLAN und statische Adresse konfigurieren
/etc/initramfs-tools/initramfs.conf öffnen:
nano /etc/initramfs-tools/initramfs.confFolgende Werte eintragen:
VLAN="enp1s0:40"
DEVICE=enp1s0.40
IP=10.15.32.253::10.15.39.254:255.255.248.0::enp1s0.40:noneDie Variable VLAN verwendet das Format Parent-Interface:VLAN-ID. Das folgende Skript ist nicht auf VLAN 40 festgelegt. Für VLAN 120 würde die Konfiguration beispielsweise so aussehen:
VLAN="enp1s0:120"
DEVICE=enp1s0.120Mehrere VLAN-Interfaces können ebenfalls vorbereitet werden:
VLAN="enp1s0:40 enp1s0:120"3. Benötigte Kernelmodule aufnehmen
Treiber des physischen Interfaces ermitteln:
basename "$(readlink -f /sys/class/net/enp1s0/device/driver/module)"In /etc/initramfs-tools/modules mindestens das VLAN-Modul ergänzen. Falls der Netzwerkkartentreiber nicht automatisch im Initramfs vorhanden ist, zusätzlich den zuvor ausgegebenen Modulnamen eintragen:
8021q
# Beispiel für einen NIC-Treiber:
# ixgbe4. Programm ip ins Initramfs kopieren
Datei /etc/initramfs-tools/hooks/vlan-ip erstellen:
nano /etc/initramfs-tools/hooks/vlan-ipInhalt:
#!/bin/sh
PREREQ=""
prereqs()
{
echo "$PREREQ"
}
case "$1" in
prereqs)
prereqs
exit 0
;;
esac
. /usr/share/initramfs-tools/hook-functions
IP_BIN="$(command -v ip || true)"
if [ ! -x "$IP_BIN" ]; then
echo "Fehler: ip aus dem Paket iproute2 wurde nicht gefunden" >&2
exit 1
fi
manual_add_modules 8021q
copy_exec "$IP_BIN"
exit 0chmod 0755 /etc/initramfs-tools/hooks/vlan-ip5. Generisches VLAN-Bootskript erstellen
Das VLAN muss existieren, bevor Dropbear das Netzwerk konfiguriert. Deshalb wird das Skript als init-premount/00-vlan installiert und nicht unter local-top.
install -d -m 0755 /etc/initramfs-tools/scripts/init-premount
nano /etc/initramfs-tools/scripts/init-premount/00-vlanInhalt:
#!/bin/sh
PREREQ=""
prereqs()
{
echo "$PREREQ"
}
case "$1" in
prereqs)
prereqs
exit 0
;;
esac
. /scripts/functions
. /conf/initramfs.conf
for config_file in /conf/conf.d/*.conf; do
[ -f "$config_file" ] && . "$config_file"
done
[ -n "${VLAN:-}" ] || exit 0
modprobe 8021q || {
log_failure_msg "VLAN-Modul 8021q konnte nicht geladen werden"
exit 1
}
for vlan_config in $VLAN; do
parent=${vlan_config%%:*}
vlan_id=${vlan_config#*:}
if [ "$parent" = "$vlan_config" ]; then
log_failure_msg "Ungueltige VLAN-Konfiguration: $vlan_config"
exit 1
fi
case "$vlan_id" in
''|*[!0-9]*)
log_failure_msg "Ungueltige VLAN-ID: $vlan_id"
exit 1
;;
esac
if [ "$vlan_id" -lt 1 ] || [ "$vlan_id" -gt 4094 ]; then
log_failure_msg "VLAN-ID ausserhalb 1 bis 4094: $vlan_id"
exit 1
fi
vlan_device="${parent}.${vlan_id}"
# Kurz auf das physische Interface warten.
attempts=0
while ! ip link show "$parent" >/dev/null 2>&1; do
attempts=$((attempts + 1))
if [ "$attempts" -ge 10 ]; then
log_failure_msg "Interface $parent wurde nicht gefunden"
exit 1
fi
sleep 1
done
ip link set "$parent" up || exit 1
if ! ip link show "$vlan_device" >/dev/null 2>&1; then
ip link add link "$parent" \
name "$vlan_device" \
type vlan id "$vlan_id" || exit 1
fi
ip link set "$vlan_device" up || exit 1
log_success_msg "VLAN-Interface $vlan_device wurde aktiviert"
done
exit 0chmod 0755 /etc/initramfs-tools/scripts/init-premount/00-vlan6. Dropbear konfigurieren
/etc/dropbear/initramfs/dropbear.conf:
DROPBEAR_OPTIONS="-I 300 -j -k -s -p 2222"7. SSH-Schlüssel erzeugen und eintragen
Auf dem Client:
ssh-keygen -t ed25519 \
-f ~/.ssh/id_initramfs_unlock_System_1 \
-C "Initramfs unlock for System_1"
cat ~/.ssh/id_initramfs_unlock_System_1.pubAuf dem Server:
install -d -m 0700 /etc/dropbear/initramfs
nano /etc/dropbear/initramfs/authorized_keys
chmod 0600 /etc/dropbear/initramfs/authorized_keysBeispielzeile:
no-port-forwarding,no-agent-forwarding,no-X11-forwarding ssh-ed25519 AAAAC3... Initramfs unlock for System_18. Initramfs bauen und prüfen
update-initramfs -u -k all
lsinitramfs /boot/initrd.img-$(uname -r) | \
grep -E '8021q|scripts/init-premount/00-vlan|/ip$|dropbear|authorized_keys|cryptroot-unlock'Optional kann die tatsächlich ins Initramfs übernommene Konfiguration kontrolliert werden:
lsinitramfs /boot/initrd.img-$(uname -r) conf/initramfs.conf9. Switch konfigurieren und prüfen
- VLAN 40 muss auf dem Serverport tagged beziehungsweise als erlaubtes Trunk-VLAN konfiguriert sein.
- VLAN 40 muss auf allen Uplinks zwischen Server und Client beziehungsweise Gateway erlaubt sein.
- Das Gateway
10.15.39.254muss im VLAN 40 liegen und erreichbar sein. - Die IP
10.15.32.253darf nicht gleichzeitig von einem anderen Gerät verwendet werden.
10. SSH-Zugriff auf dem Client einrichten
~/.ssh/config:
Host System_1-unlock
HostName 10.15.32.253
User root
Port 2222
IdentityFile ~/.ssh/id_initramfs_unlock_System_1
IdentitiesOnly yes
PasswordAuthentication no
UserKnownHostsFile ~/.ssh/known_hosts.initramfs11. Neustarten und entsperren
rebootVom Client verbinden:
ssh System_1-unlockDanach in der Initramfs-Shell:
cryptroot-unlockFehlersuche für Tagged VLAN
- Keine Pakete: Switchport auf Tagged/Trunk, erlaubte VLANs und VLAN-ID prüfen.
- Parent-Interface fehlt: Den Netzwerkkartentreiber in
/etc/initramfs-tools/modulesaufnehmen. ipfehlt: Den Hook prüfen und kontrollieren, obiproute2installiert ist.- VLAN-Interface fehlt: Mit
lsinitramfsprüfen, ob00-vlan,ipund8021qenthalten sind. - Falsches Interface wird verwendet: In
/proc/cmdlinenach einem altenip=...:enp1s0:nonesuchen. Ein Kernel-Bootparameter kanninitramfs.confüberschreiben. - Nach dem Entsperren kein Netzwerk: Das VLAN zusätzlich im regulären Betriebssystem konfigurieren; die Initramfs-Konfiguration wird nach dem Mounten des Root-Dateisystems nicht zur dauerhaften Netzwerkkonfiguration.