Der "Digital Independence Day" - der Tag, an
dem wir uns digital von Abhängigkeiten lösen und die Kontrolle
über unsere Daten zurückgewinnen wollen. Für mich bedeutet das
nicht nur ein abstraktes Konzept, sondern einen konkreten
Schritt: Mein eigener Server. Auf diesem kleinen
Rechenzentrum-Residenz möchte ich meine Webseiten, Anwendungen
und Daten selbst verwalten – frei von den Zwängen großer
Tech-Giganten.
Dieses Projekt ist mehr als nur Technik. Es ist ein
Ausdruck meiner persönlichen Unabhängigkeit im digitalen Raum.
In diesem Text teile ich mein Abenteuer mit euch: die
Herausforderungen der Serverkonfiguration, die Freude am eigenen
"Server-Knowhow" und natürlich die Befriedigung, den Digital
Independence Day jeden Tag aufs Neue zu leben."
Zuerst wird in meinem Fall mit Vmware Workstation eine
lokale Maschine aufgesetzt.
4 CPU Kerne, 4 GB Arbeitsspeicher und wichtig für den
späteren Server 2 Festplatten, da das System gleich auf ein RAID
1 vorbereitet werden soll.
So weiß man, dass alle nötigen Pakete installiert und
eingerichtet sind.
Im späteren Verlauf wird eine Web-Oberfläche installiert
– Virtualmin.
Damit werden die Domains, die auf dem Server laufen, und
die Benutzer erstellt und verwaltet.
Als Firewall kommt CSF Firewall zum Einsatz.
Die aktuelle Version von CSF und Virtualmin hatten mit
Debian 13 noch ein paar kleinere Probleme. Vor ein paar
Versionen hat Debian angefangen das Logsystem von klassischen
Logdateien unter /var/log auf Journal/SystemD umzustellen.
Anstatt jetzt Syslog auf einem aktuellen Debian nach zu
installieren und vor allem Dingen anpassen zu müssen, habe ich
mich dazu entschlossen in der VM mit Debian 9 anzufangen.
Und dann diese alte Version - die man auf keinen Fall in
einem Rechenzentrum laufen lassen sollte - auf die Debian
12 updaten. Das bekommt noch lange genug Updates, und ein Update
von 12 auf 13 sollte kein Problem sein.
Nachdem dieses Grundsystem dann auf Debian 12 geupdatet
wurde, haben wir eine virtuelle Maschine, die in einer RAID 1
Konfiguration läuft.
Wir haben Zugang per SSH.
Dann können wir die VM in ein TAR-Archiv einpacken, dazu
nutzen wir die SystemRescueCD Diese sind in der VM gebootet und
speichern die VM dann in einer Imagedatei. Dieses Image können
wir dann auf der Server übertragen.
Wir werden dann den Hetzner Server im Rescue Modus
booten.
Dort ein RAID-Verbund einrichten und Partitionen
anlegen.
Das Server Image, was zu Hause erstellt wurde, auf
diesen RAID Verbund entpacken.
Das System bootfähig machen und hoffen nix vergessen zu
haben!
Den Server neu starten und hoffentlich unser eigenes
Debian auf dem Hetzner Server im RZ installiert zu habeb.
Jetzt geht es an das Anpassen des Systems.
Also eigene Tools installieren, Sudo einrichten, die
Debian 12 Repositories einrichten, Grub anpassen, die
Bash-Autovervollständigung, IPv6 abschalten.
Der Server wird IPv4 only - im ersten Schritt.
IPv6 kommt später. Ich will mich im Moment noch nicht
mit zwei Protokollen gleichzeitig rumschlagen.
Dann wird ein Default Editor auf der Konsole festgelegt.
Beim Login sollen verschiedene Status-Informationen
angezeigt werden, welche Installation ist gebootet? Server oder
Rescue? Ist das RAID okay? Wir lassen uns mit Neofetch noch
zusätzliche Informationen zum System anzeigen.
Wir stellen die Datei "rc.local" wieder her. Eine Art
"old-school" autoexec.bat – nur für Linux. Nicht ganz so
konfortable wie SystemD Scripte, aber gut um nur schnell mal
einen Befehl beim Hochfahren ausführen zu lassen.
Es werden eigene Ordner für unsere eigenen Scripte
erstellt, verbessert die Übersicht.
Der SSH Dienst wird noch weiter abgesichert.
Steht dieses Grundsystem wird ein Backup erstellt und
das System zusätzlich auf einer 2. Partiton als Rescue-System in
Grub eingebunden.
Man kann dann über einen Befehl auf der Konsole einfach
das voreingerichtet Rescue-System hochfahren. Zwar bietet
Hetzner als Serverhoster auch ein Rescue System an, hier sind
aber die Einstellungen so gesetzt das sie für alle Benutzer
aller Server bei Hetzner passen müssen.
Ausserdem muss man sich immer in die Weboberfläche von
Hetzner einloggen um das Rescue System von Hetzner zu nutzen.
Bei unserem System reicht ein einfaches "sudo
reboot_to_rescue" und nach 2 Minuten ist das Rescue System
bereit um ein komplettes Systembackup zu machen. Das wäre zwar
auch aus dem laufenden Server System möglich, ist aber nicht
ganz so sauber.
Danach wird Virtualmin installiert.
Virtualmin ist eine Konfigurationsoberfläche für Web
Server. Es unterstützt Dienste wie Postfix, Apache, MySQL. Also
ein All-in-one-Tool.
Die Programme werden nicht nur installiert und
konfiguriert, sondern man kann damit auch die Domains erstellen.
Man erspart sich damit das manuelle Einrichten auf der Konsole.
Wenn man sich da mal vertippt.... das macht keinen Spaß.
Und ganz besonders das Einrichten, zum Beispiel von
Apache Server macht Virtualmin viel einfacher. Man kann nur noch
per HTTPS auf die Webseiten kommen, eine sichere Verschlüsselung
wird eingerichtet – HTTPS ist leider nicht mehr HTTPS! Stichwort
Cipher.
Alles, was Virtualmin macht, könnte man auch auf der
Konsole machen.
Es speichert alle Einstellungen in den
Konfigurationsdateien der entsprechenden Dienste.
Aber es geht halt sehr viel schneller. Wir werden die
dann immer wieder die Virtualmin-Konfiguration checken lassen –
von Virtualmin selbst!
Virtualmin wird auch die Systemzeit regelmäßig checken.
Das kann man individuell einstellen, ich setze die Zeit viermal
am Tag, also alle sechs Stunden.
Ist auf einem Privatserver jetzt nicht sooo wichtig, wir
sind ja kein Big Data Rechenzentrum.
Aber die korrekte Zeit ist aber doch wichtig z.B. Für
Email oder die Logfiles.
Eine PC Uhr läuft pro Tag ein paar Sekunden vor oder
zurück – sich also nur darauf zu verlassen... keine gute Idee.
Virtualmin wird uns automatisch informieren wenn es
Systemupdates geben sollte.
Systemupdates lasse ich grundsätzlich nicht automatisch
installieren. Ich möchte wissen wann da was warum installiert
worden ist.
Nachdem Virtualmin den Mailserver Postfix installiert
hat, werden wir da noch ein paar Einstellungen vornehmen. Zum
Beispiel die maximale Größe einer E-Mail, die angenommen wird.
Der FTP Server ProFTPd wird so eingestellt, dass
Benutzer nur in ihrem Home-Verzeichnis aktiv sein können. Sie
können also nicht auf die Daten anderer Nutzer zugreifen.
Der Zugriff auf die Virtualmin Oberfläche erfolgt über
Benutzername und Kennwort. Hier fügen wir noch eine zweite
Authentifikation hinzu, welche kompatibel zu Google
Authenticator ist... Mehr Sicherheit.
Wir werden Virtualmin so einstellen, dass es keine
unnötigen Module anzeigt, sondern nur, dass in der Oberfläche
angezeigt wird, was wir auch nutzen können und wollen.
Wir richten dann tägliche Backups von
Konfigurationsdateien ein. Virtualmin benutzt hier eigentlich
das Programm etckeeper. Es ist allerdings von der Oberfläche her
nicht so schön gelungen... (Hat es überhaupt eine?) wie ich
finde.
Ich nutze hier einfach ein Backup des Ordners /etc, was
einmal am Tag durchgeführt wird. Die Daten sind nicht sonderlich
gross, sind ja nur Konfigurationsdaten. Und wir werden noch
Email auf der Konsole einrichten.
Nachdem das Grundsystem dann steht, wird Virtualmin
vernünftig eingerichtet.
Wir brauchen einen Hostnamen in Virtualmin, der zum
Server passt. Dafür werden dann auch automatisch SSL-Zertifikate
erstellt - und vor allem wird dieser Domain Name, der Hostname,
als Default in Virtualmin gesetzt und die Zertifikate, die dort
erstellt werden, werden dann auch für Postfix, Dovecot, Apache
(Für die Domain hostname.domain.tld), VIrtualmin und MySQL zu
benutzt.
Nachdem das Grundsystem installiert wurde und Virtualmin
eingerichtet wurde, wird es Zeit das System NOCH WEITER
abzusichern.
Hier nutzen wir die CSF Firewall.
Das steht für "ConfigServer Security & Firewall".
Das Programm wurde bis Ende 2025 von einer englischen
One-Man-Firma geschrieben. Der Support wurde leider eingestellt.
Die Firma gibt es nicht mehr. Es ist jetzt ein
Community-Projekt.
Das ist halt das Schöne an Open Source. Die CSF-Firewall
nutze ich schon länger. Es ist nicht nur eine Firewall, die
Ports blockiert, sondern sie wertet auch Log-Files aus, sperrt
entsprechend nach Regeln bestimmte Angreifer.
Ist im Grunde genommen das, was "Fail2Ban" macht... Aber
mehr Optionen und dafür auch schwerter einzurichten.
In Virtualmin wird eine Web-Oberfläche für CSF
eingebaut. Es gibt eine grafische Log-Auswertung und wir werden
noch ein paar CSF Tools installieren, die ich selber geschrieben
habe.
Sie machen uns das Arbeiten mit der Firewall etwas
leichter.
Gerade am Anfang bekommt man von CSF viele Status-Mails
mit Diensten die laufen. Man will aber wahrscheinlich nicht
jeden Tag 1000 Mails haben, weil CSF alle 2 Minuten checkt, was
so los ist auf 127.0.0.1!
CSF wird bestimmte Dienste die unter bestimmten
Benutzern laufen "whitelisten", so dass CSF weiß Dienst darf
laufen und verschickt keine "Alarm Mail".
Da wir schon einen Server mit jeder Menge
Arbeitsspeicher und viel Festplatten Platz haben, installiere
ich zusätzlich noch Oracle VirtualBox, um auf dem Server auch
virtuelle Maschinen betreiben zu können.
Die Verwaltung dieser virtuellen Maschinen kann man
entweder über die Kommandozeile steuern, dazu gibt es ein
Skript, oder um es noch einfacher zu machen, wird auf dem System
noch PHPVirtualBox installiert.
Dann kann man das Ganze über eine grafische
Web-Oberfläche machen.
Wir danach an unsere eigenen Dienste zu installieren und
zu konfigurieren.
Da ist zum einen Syncthing, ein Programm, das es PCs
untereinander ermöglicht Daten zu synchronisieren und
abzugleichen - oder auch vom Handy.
Macht man Fotos auf dem Handy so werden diese
automatisch auf dem Server gespeichert.
Wir werden die Log-Dateien für Syncthing über Logrotate
verwalten lassen. Sodass die Log-Dateien nicht riesengroß
werden, man aber immer ein paar Tage zurückgehen kann und zu
schauen was da los ist, so wie es unter Linux auch üblich ist.
Das gleiche machen wir noch für rsyncd, den rsync
Dienst. rsync ist auch zum Datei synchronisieren hat allerdings
jetzt nicht unbedingt den Charme eines Syncthing Clients.
Vor allen Dingen kann Syncthing auf dem PC (Desktop)
immer im Hintergrund laufen. Rsync muss man immer aufrufen oder
per Script steuern.
Danach sollte der Server incl. seinem eigenen Rescue
System "Feature-Ready" sein...
Zeit den DID zu feiern...
z.B. mit NextCloud für Kontakte, Termine, Online
Besprechnungen..
Oder etwas kleiner und einfacher Baïkal oder Radicale
mit InfCloud als WebUI um schnell und einfach nur CardDAV
Einträge mit der FritzBox, dem Handy und Thunderbird syncron zu
halten?
Eigenen eigenen TeamSpeak Server als Ersatz für Discord!
Einen XMMP Server zum chatten mit Freunden auf der
ganzen Welt!
Eigener Mastodon Server...
Debian Version 0.01
### Grundlagen im RZ ###
#Festplatten mit Badblocks testen#
screen -S sda
Wenn nötig mdadm RAID anhalten
mdadm --stop /dev/md*
badblocks -svw -p 1 -b 4096 -c 65536 /dev/sda
screen -S sdb
badblocks -svw -p 1 -b 4096 -c 65536 /dev/sdb
Je nach Größe und Anzahl der Durchgänge kann das TAGE
dauern!
Nutze daher nur 2 Durchgänge, normal wären 5!
0.5% = 3min ~ 40h für 2x schreiben und 2x lesen!
#RAM testen#
Nachdem die HDDs Ok sind testen wir jetzt den
Arbeitsspeicher!
Hier ein kleines Script dafür!
#!/bin/bash
# Target configuration
target_user="root"
# Ensure memtester is installed
if ! command -v memtester >/dev/null; then
echo "Installiere memtester..."
sudo apt update && sudo apt
install -y memtester
fi
# Get free memory in MB (minus a small safety margin for
the OS)
free_mem=$(free -m | awk '/^Mem:/{print $4}')
test_mem=$((free_mem - 128))
if [ $test_mem -le 0 ]; then
echo "Fehler: Zu wenig freier
Speicher zum Testen."
exit 1
fi
echo "--- ECC RAM Belastungstest ---"
echo "Teste $test_mem MB in 2 Durchgängen..."
echo "Parallel dazu wird auf ECC-Fehlermeldungen
geprüft."
# Start background monitoring for ECC errors
(
while true; do
if [ -d
/sys/devices/system/edac/mc ]; then
for mc in /sys/devices/system/edac/mc/mc*; do
ce=$(cat "$mc/ce_count")
if [ "$ce" -gt 0 ]; then
echo "!!! ECC WARNING: $ce Correctable Errors detected on $(cat
$mc/mc_name) !!!"
fi
done
fi
sleep 5
done
) &
monitor_pid=$!
# Run memtester
if ! sudo memtester "${test_mem}M" 2; then
echo ""
echo "🟡 Warnung: Zugriff verweigert
/ Fehlende Rechte"
echo "Datei: memtester binary /
memory access"
echo ""
echo "Mögliche Lösung:"
echo "Bitte prüfe im Skript-Header,
ob die Variable target_user korrekt gesetzt ist (aktuell:
target_user=\"$target_user\")."
echo ""
echo "Manuelle Reparatur:"
echo "Führe das Skript mit 'sudo' aus
oder prüfe die Berechtigungen für /dev/mem."
kill $monitor_pid
exit 1
fi
# Cleanup
kill $monitor_pid
echo "Test beendet. Bitte dmesg auf 'EDAC' Einträge
prüfen."
#hier ist schluss
# LM Sensors testen/einrichten #
Sensor Module laden
#!/bin/bash
# Target configuration
target_user="root"
# Module list
modules=("coretemp" "jc42" "nct6775")
echo "--- Lade Hardware-Monitoring Module ---"
for mod in "${modules[@]}"; do
if lsmod | grep -q "$mod"; then
echo "Modul
$mod ist bereits geladen."
else
echo "Lade
$mod..."
if ! sudo
modprobe "$mod"; then
echo ""
echo "🟡 Warnung: Zugriff verweigert / Fehlende Rechte"
echo "Datei: /lib/modules/$(uname -r)"
echo ""
echo "Mögliche Lösung:"
echo "Bitte prüfe im Skript-Header, ob die Variable target_user
korrekt gesetzt ist (aktuell: target_user=\"$target_user\")."
echo ""
echo "Manuelle Reparatur:"
echo "Führe 'sudo modprobe $mod' manuell aus oder prüfe, ob
'kmod' installiert ist."
# Wir brechen nicht ab, sondern versuchen das nächste Modul
fi
fi
done
echo -e "\n--- Aktuelle Sensor-Ausgabe ---"
if command -v sensors >/dev/null; then
sensors
else
echo "Sensors-Befehl nicht gefunden.
Installiere lm-sensors..."
sudo apt update && sudo apt
install -y lm-sensors
sensors
fi
# Check for specific JC42 (RAM) sensors
if ls /sys/bus/i2c/drivers/jc42/ >/dev/null
2>&1; then
echo -e "\n✅ RAM-Sensoren (JC42)
aktiv."
fi
# Target configuration
target_user="root"
echo "--- ASUS WS C246 DC Hardware-Monitor ---"
# Check for Nuvoton or ITE Sensor Chips typical for ASUS
if ! command -v sensors >/dev/null; then
sudo apt update && sudo apt
install -y lm-sensors
fi
# Show detailed voltages and temps
echo "Prüfe Spannungen und Temperaturen..."
sensors | grep -iE 'in0|in1|in2|+12V|+5V|Vcore|CPU
Temperature|PCH'
if [ $? -ne 0 ]; then
echo ""
echo "🟡 Warnung: Zugriff verweigert
/ Fehlende Rechte"
echo "Datei: /sys/class/hwmon"
echo "Mögliche Lösung: Variable
target_user prüfen (aktuell: $target_user)."
echo "Manuelle Reparatur: sudo
sensors-detect ausführen und Module laden."
exit 1
fi
# Check for BMC/IPMI (if the ASMB9 module is populated)
echo -e "\n--- BMC / IPMI Status ---"
if sudo ipmitool sdr 2>/dev/null; then
echo "BMC erkannt. Hier sind die
Hardware-Logs:"
sudo ipmitool sel list | tail -n 10
else
echo "Kein aktives BMC-Modul (ASMB9)
über Software-Interface gefunden."
fi
#hier ist schluss
fix:
#!/bin/bash
# Target configuration
target_user="root"
echo "--- Präzise ASUS WS C246 DC Sensor-Analyse ---"
# Fix for the grep warning (escaping the plus sign)
echo "Prüfe Spannungen und Temperaturen..."
sensors | grep -iE "Vcore|in[0-9]|\+12V|\+5V|AUXTIN"
echo -e "\n--- RAM-Temperaturen (JC42) ---"
if ls /sys/bus/i2c/drivers/jc42/ >/dev/null
2>&1; then
sensors | grep -A 1 "jc42"
else
echo "Keine JC42 Sensoren gefunden.
Sind ECC-Module verbaut?"
fi
# Manual Repair Warning if Vcore looks impossible
vcore_val=$(sensors | grep "Vcore" | awk '{print $2}')
if [[ "$vcore_val" == "200.00" ]]; then
echo ""
echo "🟡 Warnung: Sensor-Skalierung
ungenau"
echo "Die Vcore wird vermutlich
falsch ausgelesen (Offset-Problem)."
echo ""
echo "Mögliche Lösung:"
echo "Bitte prüfe im Skript-Header,
ob die Variable target_user korrekt gesetzt ist (aktuell:
target_user=\"$target_user\")."
echo "Oft hilft ein BIOS-Update oder
eine spezifische /etc/sensors.d/asus_ws_c246.conf Datei."
fi
#hier ist schluss
#ECC RAM Temp auslesen#
#!/bin/bash
# Target configuration
target_user="root"
echo "--- Detaillierte ECC-RAM Temperatur-Analyse ---"
# Find all jc42 adapter paths and query them
specifically
found=false
for sensor in /sys/bus/i2c/drivers/jc42/0-00*; do
if [ -d "$sensor" ]; then
# Extract the
address (e.g., 0-0018)
addr=$(basename "$sensor")
echo "Prüfe
RAM-Slot an Adresse: $addr"
# Query
sensors for this specific chip
sensors
"jc42-i2c-$addr" 2>/dev/null | grep -E 'temp1|ALARM'
found=true
fi
done
if [ "$found" = false ]; then
echo "Keine aktiven JC42 Sensoren
gefunden."
echo ""
echo "🟡 Warnung: Zugriff verweigert
/ Fehlende Hardware"
echo "Datei:
/sys/bus/i2c/drivers/jc42/"
echo ""
echo "Mögliche Lösung:"
echo "Bitte prüfe im Skript-Header,
ob die Variable target_user korrekt gesetzt ist (aktuell:
target_user=\"$target_user\")."
echo ""
echo "Manuelle Reparatur:"
echo "Stelle sicher, dass das Modul
'jc42' mit 'sudo modprobe jc42' geladen wurde."
exit 1
fi
echo -e "\n--- Ende der Messung ---"
#hier ist schluss
#System stressen auf Stabilität testen#
#!/bin/bash
# Target configuration
target_user="root"
# Ensure sysbench is installed
if ! command -v sysbench >/dev/null; then
echo "Installiere sysbench..."
sudo apt update && sudo apt
install -y sysbench
fi
echo "--- System Stress Test (CPU & RAM) ---"
# Start RAM test in background
echo "Starte RAM-Durchsatz-Test (schreibend)..."
sysbench memory --memory-oper=write --threads=2 run >
/dev/null &
ram_pid=$!
# Start CPU test in foreground
echo "Starte CPU-Stress-Test (Primzahlen)..."
if ! sysbench cpu --cpu-max-prime=20000
--threads=$(nproc) run; then
echo ""
echo "🟡 Warnung: Zugriff verweigert
/ Fehlende Rechte"
echo "Datei: sysbench execution"
echo ""
echo "Mögliche Lösung:"
echo "Bitte prüfe im Skript-Header,
ob die Variable target_user korrekt gesetzt ist (aktuell:
target_user=\"$target_user\")."
echo ""
echo "Manuelle Reparatur:"
echo "Stelle sicher, dass sysbench
korrekt installiert ist und mit ausreichenden Rechten ausgeführt
wird."
kill $ram_pid 2>/dev/null
exit 1
fi
wait $ram_pid
echo "Belastungstest abgeschlossen."
#hier ist schluss
VM erstellen @ home
4 Threads (2x2)
4 GB RAM
2x 80GB HDD SATA
SystemRescueCD oder ähnliches booten
check sind alle HDDs da?
lsscsi
#Partitionstabellen erstellen
parted /dev/sda mklabel gpt
parted /dev/sdb mklabel gpt
#create partitions
#boot 8MB - sd[ab]1
parted -a optimal -- /dev/sda mkpart primary 1MB 8MB
parted -a optimal -- /dev/sdb mkpart primary 1MB 8MB
#server 40GB - sd[ab]2
parted -a optimal -- /dev/sda mkpart primary 8MB 40GB
parted -a optimal -- /dev/sdb mkpart primary 8MB 40GB
#rescue 10GB - sd[ab]3
parted -a optimal -- /dev/sda mkpart primary 40GB 50GB
parted -a optimal -- /dev/sdb mkpart primary 40GB 50GB
#backup 20GB - sd[ab]4
parted -a optimal -- /dev/sda mkpart primary 50GB 70GB
parted -a optimal -- /dev/sdb mkpart primary 50GB 70GB
#data 5GB - sd[ab]5
parted -a optimal -- /dev/sda mkpart primary 70GB 75GB
parted -a optimal -- /dev/sdb mkpart primary 70GB 75GB
#swap 4GB - sda[ab]6
parted -a optimal -- /dev/sda mkpart primary 75GB 79GB
parted -a optimal -- /dev/sdb mkpart primary 75GB 79GB
#check partitions
fdisk -l /dev/sda
fdisk -l /dev/sdb
#Der Ergebnis sollte so aussehen:
root@rescue:~# fdisk -l /dev/sda
Disk /dev/sda: 80 GiB, 85899345920 bytes, 167772160
sectors
Disk model: VMware Virtual S
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: gpt
Disk identifier: 38141AEF-C18E-4C75-AD59-F7F92047C75E
Device
Start End
Sectors Size Type
/dev/sda1
2048 16383
14336 7M Linux filesystem
/dev/sda2 16384
78125055 78108672 37.2G Linux filesystem
/dev/sda3 78125056 97656831
19531776 9.3G Linux filesystem
/dev/sda4 97656832 136718335 39061504 18.6G
Linux filesystem
/dev/sda5 136718336 146485247 9766912
4.7G Linux filesystem
/dev/sda6 146485248 154296319 7811072
3.7G Linux filesystem
root@rescue:~# fdisk -l /dev/sdb
Disk /dev/sdb: 80 GiB, 85899345920 bytes, 167772160
sectors
Disk model: VMware Virtual S
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: gpt
Disk identifier: 8F143815-E105-4201-B39F-95574802E1A6
Device
Start End
Sectors Size Type
/dev/sdb1
2048 16383
14336 7M Linux filesystem
/dev/sdb2 16384
78125055 78108672 37.2G Linux filesystem
/dev/sdb3 78125056 97656831
19531776 9.3G Linux filesystem
/dev/sdb4 97656832 136718335 39061504 18.6G
Linux filesystem
/dev/sdb5 136718336 146485247 9766912
4.7G Linux filesystem
/dev/sdb6 146485248 154296319 7811072
3.7G Linux filesystem
Paritionen als Boot bzw. RAID markieren
#boot
parted /dev/sda set 1 bios_grub on
parted /dev/sdb set 1 bios_grub on
#server
parted /dev/sda set 2 raid on
parted /dev/sdb set 2 raid on
#rescue
parted /dev/sda set 3 raid on
parted /dev/sdb set 3 raid on
#backup
parted /dev/sda set 4 raid on
parted /dev/sdb set 4 raid on
#data
parted /dev/sda set 5 raid on
parted /dev/sdb set 5 raid on
#swap
parted /dev/sda set 6 raid on
parted /dev/sdb set 6 raid on
Das RAID erstellen
mdadm --create --metadata=1.2 --name=server /dev/md/0
--level=1 --raid-devices=2 /dev/sda2 /dev/sdb2 --assume-clean
mdadm --create --metadata=1.2 --name=rescue /dev/md/1
--level=1 --raid-devices=2 /dev/sda3 /dev/sdb3 --assume-clean
mdadm --create --metadata=1.2 --name=backup /dev/md/2
--level=1 --raid-devices=2 /dev/sda4 /dev/sdb4 --assume-clean
mdadm --create --metadata=1.2 --name=data /dev/md/3
--level=1 --raid-devices=2 /dev/sda5 /dev/sdb5 --assume-clean
mdadm --create --metadata=1.2 --name=swap /dev/md/4
--level=1 --raid-devices=2 /dev/sda6 /dev/sdb6 --assume-clean
#check RAID
cat /proc/mdstat
Das Ergibnis sollte so aussehen:
root@rescue:~# cat /proc/mdstat
Personalities : [raid0] [raid1] [raid4] [raid5] [raid6]
[raid10]
md4 : active raid1 sdb6[1] sda6[0]
3902464 blocks super 1.2
[2/2] [UU]
md3 : active raid1 sdb5[1] sda5[0]
4878336 blocks super 1.2
[2/2] [UU]
md2 : active raid1 sdb4[1] sda4[0]
19513344 blocks super 1.2
[2/2] [UU]
md1 : active raid1 sdb3[1] sda3[0]
9756672 blocks super 1.2
[2/2] [UU]
md0 : active raid1 sdb2[1] sda2[0]
39020544 blocks super 1.2
[2/2] [UU]
unused devices: <none>
#speed up raid build
echo 200000 > /proc/sys/dev/raid/speed_limit_min
echo 400000 > /proc/sys/dev/raid/speed_limit_max
cat /proc/mdstat
mkfs.ext4 -m2 /dev/md/0
mkfs.ext4 -m2 /dev/md/1
mkfs.ext4 -m2 /dev/md/2
mkfs.ext4 -m2 /dev/md/3
mkswap /dev/md/4
e2label /dev/md/0 server
e2label /dev/md/1 rescue
e2label /dev/md/2 backup
e2label /dev/md/3 data
#per blkid und grep checken ob die paritionen auf dem
raid sind
root@rescue:~# blkid | grep md
/dev/md4: UUID="52b22d0d-b4c8-478d-9873-5a5e46fecf19"
TYPE="swap"
/dev/md2: LABEL="backup"
UUID="f7e3854b-a875-4722-9ba0-d67f3151719d" BLOCK_SIZE="4096"
TYPE="ext4"
/dev/md0: LABEL="server"
UUID="90c6e9a5-a5b9-4061-9af3-a4e75052b4e6" BLOCK_SIZE="4096"
TYPE="ext4"
/dev/md3: LABEL="data"
UUID="fbfce877-2acb-4562-a213-7a219eeca644" BLOCK_SIZE="4096"
TYPE="ext4"
/dev/md1: LABEL="rescue"
UUID="5dead53d-bd5e-44cc-8c5a-4459e69f6540" BLOCK_SIZE="4096"
TYPE="ext4"
#server
blkid -o value -s UUID /dev/md/0
UUID="90c6e9a5-a5b9-4061-9af3-a4e75052b4e6"
#rescue
blkid -o value -s UUID /dev/md/1
UUID="5dead53d-bd5e-44cc-8c5a-4459e69f6540"
#backup
blkid -o value -s UUID /dev/md/2
UUID="f7e3854b-a875-4722-9ba0-d67f3151719d"
#data
blkid -o value -s UUID /dev/md/3
UUID="fbfce877-2acb-4562-a213-7a219eeca644"
#swap
blkid -o value -s UUID /dev/md/4
UUID="52b22d0d-b4c8-478d-9873-5a5e46fecf19"
mkdir /server
mkdir /rescue
mkdir /backup
mkdir /data
mount UUID=90c6e9a5-a5b9-4061-9af3-a4e75052b4e6 /server
mount UUID=5dead53d-bd5e-44cc-8c5a-4459e69f6540 /rescue
mount UUID=f7e3854b-a875-4722-9ba0-d67f3151719d /backup
mount UUID=fbfce877-2acb-4562-a213-7a219eeca644 /data
swapon UUID=52b22d0d-b4c8-478d-9873-5a5e46fecf19
alles checken z.B.
df -h
debian 9 installieren in der VM @ home
nur terminal und openssh-server
#now install openssh-server and sudo from the ISO
apt-get install openssh-server sudo
#add user to sudo group
adduser username sudo
Update von Debian 9 (Stretch)
Die Debian Repos für alte Debian Version liegen unter
archive.debian.org
sudo nano /etc/apt/sources.list
deb http://archive.debian.org/debian/ stretch main
contrib non-free
deb http://archive.debian.org/debian/
stretch-proposed-updates main contrib non-free
deb http://archive.debian.org/debian-security
stretch/updates main contrib non-free
#update the system
sudo apt-get update && sudo apt-get upgrade
&& sudo apt-get dist-upgrade
#reboot the system
reboot
Update Debian 9 (Stretch) auf Debian 10 (Buster)
sudo nano /etc/apt/sources.list
deb http://archive.debian.org/debian/ buster main
contrib non-free
deb http://archive.debian.org/debian/
buster-proposed-updates main contrib non-free
deb http://archive.debian.org/debian-security
buster/updates main contrib non-free
sudo apt-get update && sudo apt-get upgrade
&& sudo apt-get dist-upgrade
sudo reboot
Update Debian 10 (Buster) auf Debian 11 (Bullseye)
sudo nano /etc/apt/sources.list
deb http://deb.debian.org/debian bullseye main contrib
non-free
deb http://deb.debian.org/debian bullseye-updates main
contrib non-free
deb http://security.debian.org/debian-security
bullseye-security main contrib non-free
sudo apt-get update && sudo apt-get upgrade
&& sudo apt-get dist-upgrade
sudo reboot
Update Debian 11 (Bullseye) auf Debian 12 (Bookworm)
sudo nano /etc/apt/sources.list
deb http://deb.debian.org/debian bookworm main contrib
non-free-firmware non-free
deb http://deb.debian.org/debian bookworm-updates main
contrib non-free-firmware non-free
deb http://security.debian.org/debian-security
bookworm-security main contrib non-free-firmware non-free
sudo apt-get update && sudo apt-get upgrade
&& sudo apt-get dist-upgrade
sudo reboot
#Voila
#A Debian 12 running on VM
#Upgraded from Debian 9
#using old stype logfiles
#check
ls -lha /var/log/auth.log
ls -lha /var/log/syslog
ls -lha /var/log/lastlog
#Time to clean up
#Remove old deb files, kernels and packages not needed
anymore
sudo apt-get clean
dpkg -l | grep linux-image
sudo apt-get remove --purge linux-image-5.10.0-37-amd64
linux-image-4.9.0-19-amd64 linux-image-4.9.0-13-amd64
linux-image-4.19.0-27-amd64
sudo apt-get autoremove
Suche nach deinstallieren Paketen wo aber noch
Konfigurationsdateien zurückgeblieben sind
dpkg -l | grep '^rc'
sudo apt-get remove --purge bsdmainutils irqbalance
libglib2.0-0 libpython3.7-minimal libpython3.9-minimal
python3.7-minimal python3.9-minimal sgml-base shared-mime-info
xdg-user-dirs xml-core
Zeit SSH anzupassen
sudo nano /etc/ssh/sshd_config
Port 9999
ListenAddress 0.0.0.0
PermitRootLogin no
AuthorizedKeysFile .ssh/authorized_keys
.ssh/authorized_keys2
PasswordAuthentication no
PubkeyAuthentication yes
UseDNS no
#set a SSH key for user that he can login
#so run this as your user NOT as root
cd && mkdir .ssh && chmod 700 .ssh
&& cd .ssh
nano authorized_keys
ssh-rsa bla bla
chmod 600 authorized_keys
Zeit ein Image oder hier tar Archive vom System zu
machen
Dazu SystemRescueCD oder etwas vergleichbares booten,
das Root File System mounten und verpacken.
Über mdadm lassen sich auch die Namen der Dateisysteme
ausgeben
mdadm --examine --brief --scan
ARRAY /dev/md/server metadata=1.2
UUID=5f99973b:c62116ae:50953dbc:ef038594
ARRAY /dev/md/rescue metadata=1.2
UUID=4979ffdd:bcd7ccba:61f270cb:9c0e66b5
ARRAY /dev/md/backup metadata=1.2
UUID=13543f72:1ee8f64c:e0617fb9:79c502dd
ARRAY /dev/md/data metadata=1.2
UUID=989c1c16:26a2842a:b5333c8a:b69370d7
ARRAY /dev/md/swap metadata=1.2
UUID=33e3b5dd:215e13c6:e42a9533:1d1b8249
mkdir /server
mount /dev/md/server /server
mkdir /backup
mount /dev/md/backup /backup
Überprüfen kann man das einfach
df -h
Filesystem Size Used
Avail Use% Mounted on
/dev/md124 37G
1.2G 34G 4% /server
/dev/md126
19G 24K 18G 1% /backup
Jetzt mir tar ein backup von /server machen.
cd /server
datum=$(date +%Y-%m-%d)
tar --use-compress-program=pbzip2 -cvpf
/backup/server_grundsystem_$datum.tar.bz2 .
hat das funktioniert?
ls -lah /backup
-rw-r--r-- 1 root root 342M Jan 5 23:51
server_grundsystem_2026-01-05.tar.bz2
Die Datei server_grundsystem_2026-01-05.tar.bz2 jetzt
irgendwo speichern das man sie später
auf der Hetzner Server hochladen kann.
#Zurück ins RZ, Hetzner Rescue System booten und
Paritionen einrichten
hetzner_server_raid_einrichten
werden alle Platten erkannt?
lsscsi
Ist schon ein RAID vorhanden?
cat /proc/mdstat
Wenn ja RAID stoppen
mdadm --stop /dev/md123
mdadm --stop /dev/md124
mdadm --stop /dev/md125
mdadm --stop /dev/md126
mdadm --stop /dev/md127
Platten schnell löschen
wipefs -a /dev/sda
wipefs -a /dev/sdb
sgdisk --zap-all /dev/sda
sgdisk --zap-all /dev/sdb
Ich erstelle die Partionen in GiB, sind ca. 7% grösser
als GB.
Bei einer 8TB Platte sind 7452GiB verfübar.
Anzeigen lassen kann man sich das mit
parted /dev/sda unit GiB print free
7452 GiB
Neues RAID erstellen
create GPT partion table
parted /dev/sda mklabel gpt
parted /dev/sdb mklabel gpt
create partitions
boot 8MB - sda1
parted -a optimal -- /dev/sda mkpart primary 1MB 8MB
parted -a optimal -- /dev/sdb mkpart primary 1MB 8MB
server 320GiB - sda2
parted -a optimal -- /dev/sda mkpart primary 8MB 320GiB
parted -a optimal -- /dev/sdb mkpart primary 8MB 320GiB
rescue 16GiB - sda3
parted -a optimal -- /dev/sda mkpart primary 320GiB
336GiB
parted -a optimal -- /dev/sdb mkpart primary 320GiB
336GiB
#backup 200GiB - sda4
parted -a optimal -- /dev/sda mkpart primary 336GiB
536GiB
parted -a optimal -- /dev/sdb mkpart primary 336GiB
536GiB
#swap 64GiB - sda5
parted -a optimal -- /dev/sda mkpart primary 536GiB
600GiB
parted -a optimal -- /dev/sdb mkpart primary 536GiB
600GiB
#data rest (minus 5GiB) - sda6
parted -a optimal -- /dev/sda mkpart primary 600GiB
7447GiB
parted -a optimal -- /dev/sdb mkpart primary 600GiB
7447GiB
Damit wären noch 5 GiB Platz unbenutzt.
Sollte man mal schnell 5 GiB brauchen oder falls eine
Platte sollte
Sie wegen eines Defektes ausgetaucht werden müssen ein
paar MB kleiner ausfallen sollte.
#check partitions
fdisk -l /dev/sda
fdisk -l /dev/sdb
root@rescue ~ # fdisk -l /dev/sda
Disk /dev/sda: 7.28 TiB, 8001563222016 bytes,
15628053168 sectors
Disk model: HGST HUH721008AL
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 4096 bytes
I/O size (minimum/optimal): 4096 bytes / 4096 bytes
Disklabel type: gpt
Disk identifier: 35A175A2-0245-49BB-86B9-EB1119D45BDC
Device
Start
End Sectors Size Type
/dev/sda1
2048
16383
14336 7M Linux filesystem
/dev/sda2
16384 671088639 671072256 320G
Linux filesystem
/dev/sda3 671088640
704643071 33554432 16G Linux
filesystem
/dev/sda4 704643072
1124073471 419430400 200G Linux filesystem
/dev/sda5 1124073472 1258291199
134217728 64G Linux filesystem
/dev/sda6 1258291200 15617490943 14359199744
6.7T Linux filesystem
root@rescue ~ # fdisk -l /dev/sdb
Disk /dev/sdb: 7.28 TiB, 8001563222016 bytes,
15628053168 sectors
Disk model: HGST HUH721008AL
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 4096 bytes
I/O size (minimum/optimal): 4096 bytes / 4096 bytes
Disklabel type: gpt
Disk identifier: 21CC194C-693B-48F3-A754-55593D50315A
Device
Start
End Sectors Size Type
/dev/sdb1
2048
16383
14336 7M Linux filesystem
/dev/sdb2
16384 671088639 671072256 320G
Linux filesystem
/dev/sdb3 671088640
704643071 33554432 16G Linux
filesystem
/dev/sdb4 704643072
1124073471 419430400 200G Linux filesystem
/dev/sdb5 1124073472 1258291199
134217728 64G Linux filesystem
/dev/sdb6 1258291200 15617490943 14359199744
6.7T Linux filesystem
Jetzt müssen wir dem System noch sagen was wie die
Partitionen verwendet werden sollen
#boot
parted /dev/sda set 1 bios_grub on
parted /dev/sdb set 1 bios_grub on
#server
parted /dev/sda set 2 raid on
parted /dev/sdb set 2 raid on
#rescue
parted /dev/sda set 3 raid on
parted /dev/sdb set 3 raid on
#backup
parted /dev/sda set 4 raid on
parted /dev/sdb set 4 raid on
#swap
parted /dev/sda set 5 raid on
parted /dev/sdb set 5 raid on
#data
parted /dev/sda set 6 raid on
parted /dev/sdb set 6 raid on
Jetzt teilen wir MDADM mit welche Platten zusammen ein
RAID1 bilden sollen und wie es heissen soll.
ACHTUNG
Ich nutze hier die Option --assume-clean
Das ist GEFÄHRLICH man sollte sie weglassen, warum ich
das jetzt mache darauf werde hier nicht weiter gehen...
Kurz und knapp... es spart mir jetzt Zeit und ich
verlege einen Schritt der jetzt gemacht werden sollte in die
Zukunft
mdadm --create --metadata=1.2 --name=server /dev/md/0
--level=1 --raid-devices=2 /dev/sda2 /dev/sdb2 --assume-clean
mdadm --create --metadata=1.2 --name=rescue /dev/md/1
--level=1 --raid-devices=2 /dev/sda3 /dev/sdb3 --assume-clean
mdadm --create --metadata=1.2 --name=backup /dev/md/2
--level=1 --raid-devices=2 /dev/sda4 /dev/sdb4 --assume-clean
mdadm --create --metadata=1.2 --name=swap /dev/md/3
--level=1 --raid-devices=2 /dev/sda5 /dev/sdb5 --assume-clean
mdadm --create --metadata=1.2 --name=data /dev/md/4
--level=1 --raid-devices=2 /dev/sda6 /dev/sdb6 --assume-clean
#check RAID
cat /proc/mdstat
root@rescue ~ # cat /proc/mdstat
Personalities : [raid1]
md4 : active raid1 sdb6[1] sda6[0]
7179467776 blocks super
1.2 [2/2] [UU]
bitmap: 54/54 pages
[216KB], 65536KB chunk
md3 : active raid1 sdb5[1] sda5[0]
67042304 blocks super 1.2
[2/2] [UU]
md2 : active raid1 sdb4[1] sda4[0]
209583104 blocks super
1.2 [2/2] [UU]
bitmap: 0/2 pages [0KB],
65536KB chunk
md1 : active raid1 sdb3[1] sda3[0]
16759808 blocks super 1.2
[2/2] [UU]
md0 : active raid1 sdb2[1] sda2[0]
335404032 blocks super
1.2 [2/2] [UU]
bitmap: 0/3 pages [0KB],
65536KB chunk
unused devices: <none>
Lässt man --assume-clean weg und will den RAID Aufbau
beschleunigen
macht hier keinen Sinn...
speed up raid build
echo 200000 > /proc/sys/dev/raid/speed_limit_min
echo 400000 > /proc/sys/dev/raid/speed_limit_max
cat /proc/mdstat
Erstellen von Dateisystemen auf den RAID1 Partitionen
und einbinden des SWAP Speichers
mkfs.ext4 -m1 /dev/md/0
mkfs.ext4 -m0 /dev/md/1
mkfs.ext4 -m0 /dev/md/2
mkfs.ext4 -m0 /dev/md/4
mkswap /dev/md/3
Vielleicht nochmal eine Zusammenfassung vom RAID
anschauen?
mdadm --examine --brief --scan
Dateisysteme benennen
e2label /dev/md/0 server
e2label /dev/md/1 rescue
e2label /dev/md/2 backup
e2label /dev/md/4 data
Abfragen der UUIDs zum mounten
blkid -o value -s UUID /dev/md/0
57763470-aa57-465c-9a5d-a61c0354401e server
blkid -o value -s UUID /dev/md/1
51448698-12e1-4d34-b131-3519536b748b rescue
blkid -o value -s UUID /dev/md/2
03b049f2-df78-4984-8055-a992656f6a75 backup
blkid -o value -s UUID /dev/md/3
bbf574dc-1a51-49d2-b512-c75ae5d47dc8 swap
blkid -o value -s UUID /dev/md/4
70adc66b-075d-46ab-82c5-263323a44a9f data
Verzeichnisse erstellen und mounten
mkdir /server && mkdir /rescue && mkdir
/backup && mkdir /data
mount LABEL=server /server && mount LABEL=rescue
/rescue && mount LABEL=backup /backup && mount
LABEL=data /data
Hat soweit alles geklappt?
Haben die Partitionen die richtige Grösse und Namen?
df -h
Filesystem
Size Used Avail Use% Mounted on
/dev/md0
314G 28K 311G 1% /server
/dev/md1
3.9G 24K 3.8G 1% /rescue
/dev/md2
251G 28K 249G 1% /backup
/dev/md3
6.6T 28K 6.6T 1% /data
Die Datei server_grundsystem_2026-01-05.tar.bz2 auf den
Server im Verzeichnis /backup speichern.
mc ist hier dein Freund!
Und im Verzeichnis /server entpacken
cd /server
tar -xvpf /backup/server_grundsystem_2026-01-05.tar.bz2
. --numeric-owner
Das Kernel Dateisystem nach /server mounten
cd
mount -o bind /dev /server/dev
mount -o bind /sys /server/sys
mount -o bind /proc /server/proc
Ins Server System "wechseln"
chroot /server /bin/bash
Zeit das Images welches ja noch die Einstellen aus der
VM von Zuhause hat auf Hetzner anzupassen
nano /etc/network/interfaces
auto eth0
iface eth0 inet static
address 1.2.3.4
netmask 2.3.4.5
gateway 3.4.5.6
dns-nameservers 1.1.1.1 8.8.8.8
nano /etc/default/grub
GRUB_DEFAULT=0
GRUB_TIMEOUT=5
GRUB_DISTRIBUTOR="server"
GRUB_CMDLINE_LINUX_DEFAULT=""
GRUB_CMDLINE_LINUX="net.ifnames=0 biosdevname=0
loglevel=0 noresume nohibernate"
GRUB_DISABLE_OS_PROBER=true
cd /etc/grub.d/
chmod 400 20_linux_xen 30_os-prober 30_uefi-firmware
40_custom 41_custom
nano /etc/resolv.conf
nameserver 1.1.1.1
nameserver 8.8.8.8
nano /etc/hostname
server
nano /etc/fstab
#<file system> <mount point> <type>
<options> <dump> <pass>
UUID=57763470-aa57-465c-9a5d-a61c0354401e / ext4
errors=remount-ro 0 1
UUID=51448698-12e1-4d34-b131-3519536b748b /rescue ext4
defaults 0 2
UUID=03b049f2-df78-4984-8055-a992656f6a75 /backup ext4
defaults 0 2
UUID=bbf574dc-1a51-49d2-b512-c75ae5d47dc8 none swap sw 0
0
UUID=70adc66b-075d-46ab-82c5-263323a44a9f /data ext4
defaults 0 2
nano /etc/hosts
127.0.0.1 localhost.localdomain localhost
1.2.3.4 hostname.domain.tld hostname
127.0.1.1 hostname.domain.tld hostname
/usr/share/mdadm/mkconf
/usr/share/mdadm/mkconf > /etc/mdadm/mdadm.conf
nano /etc/initramfs-tools/conf.d/resume
RESUME=none
Stellen wir das RAID gleich auf kurze Zahlen
nano /etc/mdadm/mdadm.conf
ARRAY /dev/md/0 metadata=1.2
UUID=114cc9e2:3bd499a8:407d4290:030d381b name=rescue:server
ARRAY /dev/md/1 metadata=1.2
UUID=bde62eb9:d837ae9e:d3462008:9b707324 name=rescue:rescue
ARRAY /dev/md/2 metadata=1.2
UUID=c2cfb659:fad63212:5e78aa0a:e6973891 name=rescue:backup
ARRAY /dev/md/3 metadata=1.2
UUID=b0d05c87:605c7cd3:fca05443:db9b9879 name=rescue:swap
ARRAY /dev/md/4 metadata=1.2
UUID=2a0c1aec:e7471fe9:90ddf9e6:5bd5a92c name=rescue:data
update-grub
update-initramfs -u -k all
dpkg-reconfigure grub-pc
reboot
Nach ~ 2 Minuten warten...
Login per SSH sollte möglich sein!
Der Server läuft jetzt mit Debian 12, auf der "echten"
Hardware.
Ist unter seiner IPv4 Adresse erreichbar, die auch fest
in /etc/network/interfaces steht.
Im Gegensatz zu einem frisch installieren Debian 12 oder
13 sind auch noch die alten Logdateien da!
Erreichbar ist nur ein SSH Ports der nicht auf dem
default Port läuft,
so gibt es schonal weniger Angriffe von Bots und
Skript-Kiddies.
Überprüfen kann man das einfach mit
sudo ss -tulpen
Netid
State
Recv-Q
Send-Q
Local
Address:Port
Peer
Address:Port
Process
tcp
LISTEN
0
128
0.0.0.0:9999
0.0.0.0:*
users:(("sshd",pid=656,fd=3)) ino:22920 sk:1
cgroup:/system.slice/ssh.service <->
raid namen?
df -h
#so der Server sollte jetzt mir einem RAID1 laufen und
booten...
#Zeit mit dem Einrichten des Systems anzufangen
Erstaml checken ob es Upates für Debian gibt
sudo apt-get update
sudo apt-get upgrade
sudo apt-get dist-update
und wenn es einen neuen Kernel gibt
sudo reboot
Wo das Grundsystem jetzt läuft installieren wir erstmal
ein paar Tools
sudo apt-get update && sudo apt-get install
screen molly-guard htop mc pbzip2 man less
sudoers anpassen
sudo nano /etc/sudoers
Defaults pwfeedback
$BENUTZER ALL = NOPASSWD: /usr/bin/cat,
/usr/sbin/reboot, /usr/sbin/shutdown
Vollständige Debian 12 Reops mit Quellcode erstmal aber
auskommentiert
sudo nano /etc/apt/sources.list
deb http://deb.debian.org/debian/ bookworm main contrib
non-free non-free-firmware
#deb-src http://deb.debian.org/debian/ bookworm main
contrib non-free non-free-firmware
deb http://security.debian.org/debian-security
bookworm-security main contrib non-free non-free-firmware
#deb-src http://security.debian.org/debian-security
bookworm-security main contrib non-free non-free-firmware
deb http://deb.debian.org/debian/ bookworm-updates main
contrib non-free non-free-firmware
#deb-src http://deb.debian.org/debian/ bookworm-updates
main contrib non-free non-free-firmware
sudo apt-get update
bash autovervollstaendigung
sudo apt-get install bash-completion
sudo nano /etc/bash.bashrc
# enable bash completion in interactive shells
if ! shopt -oq posix; then
if [ -f
/usr/share/bash-completion/bash_completion ]; then
.
/usr/share/bash-completion/bash_completion
elif [ -f /etc/bash_completion ]; then
. /etc/bash_completion
fi
fi
kein IPv6
sudo nano /etc/sysctl.d/99-sysctl.conf
net.ipv6.conf.all.disable_ipv6=1
net.ipv6.conf.default.disable_ipv6=1
net.ipv6.conf.lo.disable_ipv6=1
net.ipv6.conf.eth0.disable_ipv6=1
default editor
sudo nano /etc/environment
EDITOR=nano
sudo nano /etc/profile.d/alias.sh
alias ll="ls -lah"
alias cls="clear"
alias dir="ls -lha | less"
alias zeit='echo -n "Berlin: $(date +%H:%M:%S) "; echo
-n "UTC: $(date +%H:%M:%S -u) "; echo "Sekunden:" $(numfmt
--grouping $(date +%s))'
alias cpu_speed='watch -n 1 "grep \"^[c]pu MHz\"
/proc/cpuinfo"'
sudo chown root:root /etc/profile.d/alias.sh &&
sudo chmod 644 /etc/profile.d/alias.sh
raid_status_beim_login
sudo nano /etc/profile.d/raid_check.sh
#!/bin/bash
MDSTAT="/proc/mdstat"
RED='\033[0;31m'
GREEN='\033[0;32m'
NC='\033[0m' # No Color
if grep -qE "_|inactive|faulty" "$MDSTAT"; then
echo -e "${RED}Achtung Fehler im
RAID${NC}"
else
echo -e "${GREEN}Das RAID ist
OK${NC}"
fi
sudo chown root:root /etc/profile.d/raid_check.sh
&& sudo chmod 644 /etc/profile.d/raid_check.sh
anzeige_welche_installation_gebootet_ist_beim_login
sudo nano /etc/profile.d/check_boot.sh
#!/bin/bash
# Gelbe Farbe
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
echo -e "${YELLOW}Server Installation${NC}"
sudo chown root:root /etc/profile.d/check_boot.sh
&& sudo chmod 644 /etc/profile.d/check_boot.sh
neofetch_installieren_und_beim_start_anzeigen_lassen
sudo apt-get update && sudo apt-get install
neofetch
sudo nano /etc/profile.d/neofetch.sh
#!/bin/bash
printf "\n"
neofetch
sudo chown root:root /etc/profile.d/neofetch.sh
&& sudo chmod 755 /etc/profile.d/neofetch.sh
rc-local_wieder_herstellen
sudo nano /etc/systemd/system/rc-local.service
[Unit]
Description=/etc/rc.local
ConditionPathExists=/etc/rc.local
After=network-online.target
Wants=network-online.target
[Service]
Type=forking
ExecStart=/etc/rc.local start
TimeoutSec=0
StandardOutput=tty
RemainAfterExit=yes
SysVStartPriority=99
[Install]
WantedBy=multi-user.target
sudo chown root:root
/etc/systemd/system/rc-local.service && sudo chmod 644
/etc/systemd/system/rc-local.service
sudo nano /etc/rc.local
#!/bin/sh -e
#
# rc.local
#
# This script is executed at the end of each multiuser
runlevel.
# Make sure that the script will "exit 0" on success or
any other
# value on error.
#
# In order to enable or disable this script just change
the execution
# bits.
#
# By default this script does nothing.
exit 0
sudo chown root:root /etc/rc.local && sudo chmod
770 /etc/rc.local && sudo systemctl enable rc-local
&& sudo systemctl start rc-local
boot.log_beim_starten
sudo nano /etc/rc.local
echo $(hostname -f) started at $(date +%Y-%m-%d) $(date
+%H:%M) >> /root/reboot.log
Turn_off_standby_and_co
sudo systemctl mask sleep.target suspend.target
hibernate.target hybrid-sleep.target
Time_Sync
sudo apt-get install systemd-timesyncd && sudo
systemctl enable systemd-timesyncd && sudo systemctl
start systemd-timesyncd
sudo nano /etc/systemd/timesyncd.conf
[Time]
NTP=ptbtime1.ptb.de ptbtime2.ptb.de ptbtime3.ptb.de
FallbackNTP=0.debian.pool.ntp.org 1.debian.pool.ntp.org
2.debian.pool.ntp.org 3.debian.pool.ntp.org
sudo systemctl stop systemd-timesyncd && sudo
systemctl start systemd-timesyncd
timedatectl status
WoL_Wake_on_LAN
sudo apt-get update && sudo apt-get install
ethtool
sudo nano /etc/rc.local
/usr/sbin/ethtool -s eth0 wol g
ping_fix_for_user
sudo su
echo 'net.ipv4.ping_group_range = 0 2147483647' >
/etc/sysctl.d/99-ping.conf
sysctl -p /etc/sysctl.d/99-ping.conf
exit
Make_nano_a_bit_nicer
sudo nano /etc/nanorc
set constantshow
set indicator
set linenumbers
Force_secure_passwords
sudo apt-get install libpam-pwquality
sudo nano /etc/pam.d/common-password
password [success=1 default=ignore] pam_unix.so obscure
use_authtok try_first_pass yescrypt sha512 shadow remember=5
sudo nano /etc/security/pwquality.conf
minlen = 14
dcredit = -1
ucredit = -1
lcredit = -1
ocredit = -1
maxrepeat = 2
usercheck = 0
dictcheck = 1
minclass = 4
maxsequence = 3
Pfade_fuer_eigene_systemweite_Scripts_erstellen
sudo mkdir -p /opt/usr/bin /opt/usr/sbin
sudo chmod 755 /opt/usr/bin /opt/usr/sbin
Pfade_fuer_eigene_systemweite_Scripts_beim_login_setzen
sudo nano /etc/profile.d/opt-usr-path.sh
if [ -d /opt/usr/bin ]; then
PATH="/opt/usr/bin:$PATH"
fi
if [ -d /opt/usr/sbin ]; then
PATH="/opt/usr/sbin:$PATH"
fi
export PATH
allow_opt_usr_bin_and_opt_usr_sbin_in_sudo
sudo nano /etc/sudoers
Defaults
secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/opt/usr/sbin:/opt/usr/bin"
script_5_sekunden
sudo nano /opt/usr/bin/5_sekunden
#!/bin/bash
while true; do echo $(date +%H:%M:%S); sleep 5; done
sudo chown root:root /opt/usr/bin/5_sekunden &&
sudo chmod 555 /opt/usr/bin/5_sekunden
script_apt_clean
sudo nano /opt/usr/sbin/apt_clean
#!/bin/bash
apt-get clean
rm /var/lib/apt/lists/deb.debian.* >> /dev/null
2>&1
rm /var/lib/apt/lists/security.debian* >>
/dev/null 2>&1
rm /var/lib/apt/lists/software.virtualmin.com* >>
/dev/null 2>&1
sudo chown root:root /opt/usr/sbin/apt_clean &&
sudo chmod 750 /opt/usr/sbin/apt_clean
/opt/usr/sbin/apt_clean in sudoers eintragen
script_cache_clean
sudo nano /opt/usr/sbin/clean_cache
#!/bin/bash
sync; echo 1 > /proc/sys/vm/drop_caches
sync; echo 2 > /proc/sys/vm/drop_caches
sync; echo 3 > /proc/sys/vm/drop_caches
sudo chown root:root /opt/usr/sbin/clean_cache
&& sudo chmod 755 /opt/usr/sbin/clean_cache
sudo nano /etc/sudoers
NOPASSWD: /opt/usr/sbin/clean_cache
script_ports
sudo apt-get update && sudo apt-get install
net-tools
sudo nano /opt/usr/bin/ports
#!/bin/bash
#netstat -tulpen
netstat -tulpen | awk 'NR>2 {print $1, $4, $NF}' |
sed -E 's/[0-9]+\///' | sort -u -t: -k2n | column -t
sudo chown root:root /opt/usr/bin/ports && sudo
chmod 555 /opt/usr/bin/ports
sudo nano /etc/sudoers
NOPASSWD: /opt/usr/bin/ports
script_rechte_anpassen
sudo nano /opt/usr/bin/rechte_anpassen
#!/bin/bash
echo "BEISPIEL:"
echo "chown user:group -R ."
echo "find . -type d -exec chmod 750 {} +"
echo "find . -type f -exec chmod 640 {} +"
sudo chown root:root /opt/usr/bin/rechte_anpassen
&& sudo chmod 555 /opt/usr/bin/rechte_anpassen
script_updates
sudo nano /opt/usr/sbin/updates
#!/bin/bash
apt-get update && apt-get upgrade --yes
&& apt-get dist-upgrade --yes && apt-get clean
sudo chown root:root /opt/usr/sbin/updates &&
sudo chmod 550 /opt/usr/sbin/updates
/opt/usr/sbin/updates in sudoers eintragen!
Restic_installieren
sudo apt-get install restic wget && sudo restic
self-update && sudo mkdir -p /etc/bash_completion.d
&& sudo restic generate --bash-completion
/etc/bash_completion.d/restic
SSH_hardening_www.sshaudit.com
sudo su
rm /etc/ssh/ssh_host_*
ssh-keygen -t rsa -b 4096 -f /etc/ssh/ssh_host_rsa_key
-N ""
ssh-keygen -t ed25519 -f /etc/ssh/ssh_host_ed25519_key
-N ""
echo -e "\nHostKey
/etc/ssh/ssh_host_ed25519_key\nHostKey
/etc/ssh/ssh_host_rsa_key" >> /etc/ssh/sshd_config
awk '$5 >= 3071' /etc/ssh/moduli >
/etc/ssh/moduli.safe
mv /etc/ssh/moduli.safe /etc/ssh/moduli
echo -e "# Restrict key exchange, cipher, and MAC
algorithms, as per sshaudit.com\n# hardening guide.\n
KexAlgorithms
sntrup761x25519-sha512@openssh.com,curve25519-sha256,curve25519-sha256@libssh.org,gss-curve25519-sha256-,diffie-hellman-group16-sha512,gss-group16-sha512-,diffie-hellman-group18-sha512,diffie-hellman-group-exchange-sha256\n\nCiphers
chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-gcm@openssh.com,aes128-ctr\n\nMACs
hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com,umac-128-etm@openssh.com\n\nHostKeyAlgorithms
sk-ssh-ed25519-cert-v01@openssh.com,ssh-ed25519-cert-v01@openssh.com,rsa-sha2-512-cert-v01@openssh.com,rsa-sha2-256-cert-v01@openssh.com,sk-ssh-ed25519@openssh.com,ssh-ed25519,rsa-sha2-512,rsa-sha2-256\n\nRequiredRSASize
3072\n\nCASignatureAlgorithms
sk-ssh-ed25519@openssh.com,ssh-ed25519,rsa-sha2-512,rsa-sha2-256\n\nGSSAPIKexAlgorithms
gss-curve25519-sha256-,gss-group16-sha512-\n\nHostbasedAcceptedAlgorithms
sk-ssh-ed25519-cert-v01@openssh.com,ssh-ed25519-cert-v01@openssh.com,sk-ssh-ed25519@openssh.com,ssh-ed25519,rsa-sha2-512-cert-v01@openssh.com,rsa-sha2-512,rsa-sha2-256-cert-v01@openssh.com,rsa-sha2-256\n\nPubkeyAcceptedAlgorithms
sk-ssh-ed25519-cert-v01@openssh.com,ssh-ed25519-cert-v01@openssh.com,sk-ssh-ed25519@openssh.com,ssh-ed25519,rsa-sha2-512-cert-v01@openssh.com,rsa-sha2-512,rsa-sha2-256-cert-v01@openssh.com,rsa-sha2-256\n\n"
> /etc/ssh/sshd_config.d/ssh-audit_hardening.conf
exit
apt_only_with_IPv4
sudo nano /etc/apt/apt.conf.d/90force-ipv4
Acquire::ForceIPv4 "true";
Reihenfolge_der_Scripte_beim_Login_anpassen
sudo su -
cd /etc/profile.d/
mv neofetch.sh zz_000_neofetch.sh
mv check_boot.sh zz_100_check_boot.sh
mv raid_check.sh zz_200_raid_check.sh
script_reboot_to_rescue
sudo nano /opt/usr/sbin/reboot_to_rescue
#!/bin/bash
/usr/sbin/grub-reboot 2 && /usr/bin/sync
&& /usr/sbin/reboot
sudo chmod 750 /opt/usr/sbin/reboot_to_rescue
sudo nano /etc/sudoers
NOPASSWD: /opt/usr/sbin/reboot_to_rescue
Grub_Eintrag_fuer_Rescue_System
sudo nano /etc/grub.d/11_rescue
#! /bin/sh
echo "Füge einen Starteintrag für Rescue ein" >&2
cat << EOF
menuentry "Rescue" {
insmod part_gpt
insmod search_fs_uuid
search --fs-uuid --no-floppy
--set=root 51448698-12e1-4d34-b131-3519536b748b
configfile /boot/grub/grub.cfg
}
EOF
sudo chmod 755 /etc/grub.d/11_rescue
sudo update-grub
script_um_das_Rescue_System_zu_sichern
sudo nano /opt/usr/sbin/backup_rescue
#!/bin/bash
DATUM=$(date +%Y-%m-%d_%H-%M)
cd /rescue
tar --use-compress-program=pbzip2 -cvpf
/backup/rescue_${DATUM}_$1.tar.bz2 .
cd /backup
md5sum rescue_${DATUM}_$1.tar.bz2 >
rescue_${DATUM}_$1.tar.bz2.md5
sudo chown root:root /opt/usr/sbin/backup_rescue
&& sudo chmod 750 /opt/usr/sbin/backup_rescue
sudo nano /etc/sudoers
NOPASSWD: /opt/usr/sbin/backup_rescue
#Das eigene Rescue System installieren
sudo su
cd /rescue
tar -xvpf /backup/server_grundsystem_2026-01-05.tar.bz2
. --numeric-owner
cd
mount -o bind /dev /rescue/dev
mount -o bind /sys /rescue/sys
mount -o bind /proc /rescue/proc
chroot /rescue /bin/bash
nano /etc/network/interfaces
auto eth0
iface eth0 inet static
address 1.2.3.4
netmask 2.3.4.5
gateway 3.4.5.6
dns-nameservers 1.1.1.1 8.8.8.8
nano /etc/default/grub
GRUB_DEFAULT=0
GRUB_TIMEOUT=5
GRUB_DISTRIBUTOR="rescue at server"
GRUB_CMDLINE_LINUX_DEFAULT=""
GRUB_CMDLINE_LINUX="net.ifnames=0 biosdevname=0
loglevel=0 noresume nohibernate"
GRUB_DISABLE_OS_PROBER=true
cd /etc/grub.d/
chmod 400 20_linux_xen 30_os-prober 30_uefi-firmware
40_custom 41_custom
nano /etc/resolv.conf
nameserver 1.1.1.1
nameserver 8.8.8.8
nano /etc/hostname
server
etc_fstab_auf_rescue_anpassen
nano /etc/fstab
#<file system> <mount point> <type>
<options> <dump> <pass>
UUID=51448698-12e1-4d34-b131-3519536b748b / ext4
errors=remount-ro 0 1
UUID=57763470-aa57-465c-9a5d-a61c0354401e /server ext4
defaults 0 2
server_verzeichnis_auf_dem_Rescue_System_erstellen
mkdir /server
Grub_2_und_RAID_Problem_loesen
#Problem with grub-reboot and RAID
#reboot config is with raid permnent and saved in the
server/boot partition.
#can be fixed by copying a file
#
WARNING: Detected GRUB environment block on diskfilter
device
2 will remain the default boot entry until manually
cleared with:
grub-editenv /boot/grub/grubenv unset
next_entry
mount /server
cp /server/boot/grub/grubenv
/root/server_boot_grub_grubenv
nano /root/server_boot_grub_grubenv
next_entry=0
nano /usr/sbin/reboot_to_server
cp /root/server_boot_grub_grubenv
/server/boot/grub/grubenv && chown root:root
/server/boot/grub/grubenv && chmod 644
/server/boot/grub/grubenv && sync && reboot
chown root:root /usr/sbin/reboot_to_server
chmod 500 /usr/sbin/reboot_to_server
Rescue_Installation_beim_Login_anzeigen
nano /etc/profile.d/zz_100_check_boot.sh
!/bin/bash
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
echo -e "${YELLOW}Rescue Installation${NC}"
update-grub
Rescue_System_Benutzer_anlegen_und_SSH_Key
#Create own user for rescue system
sudo adduser rescue
sudo adduser rescue sudo
sudo nano /etc/sudoers
sudo su - rescue
cd && mkdir .ssh && chmod 700 .ssh
&& cd .ssh
nano authorized_keys2
ssh-rsa bla bla
chmod 600 authorized_keys2
exit
Rescue_System_alten_Benutzer_entfernen
#delete old user and group
sudo userdel -r $BENUTZER
sudo groupdel $BENUTZER
#Weitere Tools installieren
config-start Server_rsync_installieren
sudo apt-get update && sudo apt-get install
rsync
Script_backup_server_to_home
#!/bin/bash
function f_backup() {
while [ 1 ]
do
echo "rsync server to home"
chown backupserver:backupserver /backup/ -R
find /backup/ -type d -exec chmod 750 {} +
find /backup/ -type f -exec chmod 640 {} +
sudo -u backupserver rsync -rt -e "ssh -p 99000"
/backup/ backupserver@host.domain.tld:/backup_server/
if [ "$?" = "0" ] ; then
echo "rsync completed normally"
exit
else
echo "Rsync failure. Backing off and retrying..."
sleep 180
fi
done
}
function f_verbose() {
while [ 1 ]
do
echo "rsync server to home"
chown backupserver:backupserver /backup/ -R
find /backup/ -type d -exec chmod 750 {} +
find /backup/ -type f -exec chmod 640 {} +
sudo -u backupserver rsync -rtv --progress -e "ssh -p
99000" /backup/ backupserver@host.domain.tld:/hdd/backup_server/
if [ "$?" = "0" ] ; then
echo "rsync completed normally"
exit
else
echo "Rsync failure. Backing off and retrying..."
sleep 180
fi
done
}
if [[ "$1" == "v" ]]; then
f_backup_verbose
else
f_backup
fi
sudo chown root:root /opt/usr/sbin/backup_server_to_home
&& sudo chmod 750 /opt/usr/sbin/backup_server_to_home
sudo nano /etc/sudoers
NOPASSWD: /usr/sbin/backup_server_to_home
#backup_server_to_home MUST be run at least once by you
on the console to allow and save the SSH Key from the other
system!
sudo nano /etc/crontab
0 3 * * * root /opt/usr/sbin/backup_server_to_home
config-end
config-start Rescue_System_Script_backup_server
sudo nano /opt/usr/sbin/backup_server
#!/bin/bash
DATUM=$(date +%Y-%m-%d_%H-%M)
cd /server
tar --use-compress-program=pbzip2 -cvpf
/backup/server_${DATUM}_$1.tar.bz2 .
cd /backup
md5sum server_${DATUM}_$1.tar.bz2 >
server_${DATUM}_$1.tar.bz2.md5
sudo chown root:root /opt/usr/sbin/backup_server
&& sudo chmod 750 /opt/usr/sbin/backup_server
sudo nano /etc/sudoers
NOPASSWD: /opt/usr/sbin/backup_server
config-end
User_backupuser_anlegen_und_SSH_Key_erstellen
sudo adduser backupserver
sudo su - backupserver
cd && mkdir .ssh && chmod 700 .ssh/
&& cd .ssh
ssh-keygen -o -a 100 -t ed25519
cat id_ed25519.pub
ssh-ed25519 ********************** backupserver@server
exit
SSH_anpassen_Timeout
sudo nano /etc/ssh/sshd_config
ClientAliveInterval 300
ClientAliveCountMax 5
Benutzer_$BENUTZER_zur_Gurppe_backupuser_hinzufuegen
sudo adduser $BENUTZER backupserver
tldr_installieren
sudo apt-get install tealdeer
sudo mkdir -p /usr/local/share/tldr
sudo chmod 755 /usr/local/share/tldr
sudo TEALDEER_CACHE_DIR=/usr/local/share/tldr tldr
--update
echo 'export TEALDEER_CACHE_DIR=/usr/local/share/tldr' |
sudo tee /etc/profile.d/tldr.sh
Updates per Cron
sudo nano /opt/usr/sbin/update-tldr-systemwide.sh
#!/bin/bash
# Systemweiten tldr-Cache aktualisieren
export TEALDEER_CACHE_DIR=/usr/local/share/tldr
/usr/bin/tldr --update
sudo chmod +x /opt/usr/sbin/update-tldr-systemwide.sh
nano /etc/crontab
0 0 * * 0 root /opt/usr/sbin/update-tldr-systemwide.sh
> /dev/null 2>&1
test:
sudo /opt/usr/sbin/update-tldr-systemwide.sh
#Virtualmin installieren
Virtualmin_installieren
sudo apt-get update
cd && mkdir virtualmin && cd virtualmin
&& wget
https://software.virtualmin.com/gpl/scripts/install.sh
&& chmod 700 install.sh
sudo screen ./install.sh
#ensure SSH login to host after reboot!
https://hostname.domain.tld:10000
Webmin - Networking -> FirewallD -> Allow Port
9999 TCP
Remove Port 22
add Port 9999
Reboot
Virtualmin_Hostname_Problem
nach der installation von virtualmin ist der hostname
hostname.domain.tld sollte aber nach meiner Menung nur
Hostname sein
hostname -f ist
hostname.domain.tld
hostname wieder auf server geändert
sudo nano /etc/hostname
Reboot hier
Virtualmin Post-Installation Wizard
Run email domain lookup server -> Yes, faster mail
processing with more RAM used (≈70M)
Enable virus scanning with ClamAV -> Yes, uses up to
2G of RAM
Run SpamAssassin server filter -> No, slower mail
processing with less RAM used
Run MariaDB database server -> yes
Run PostgreSQL database server -> no
Change MariaDB password -> SicheresPasswwortMySQL
Primary nameserver -> server ->
hostname.domain.tld
Master administrator's email address ->
webmin@hostname.domain.tld
Checking Configuration
Mails_von_root_and_Benutzer_weiterleiten
sudo nano /root/.forward
$BENUTZER
sudo chown root:root /root/.forward
sudo chmod 664 /root/.forward
Virtualmin_Dienste_auf_IPv4_umstellen_Spamassassin
sudo nano /etc/default/spamd
#OPTIONS="--create-prefs --max-children 5
--helper-home-dir"
OPTIONS="--create-prefs --max-children 5
--helper-home-dir -4"
Virtualmin_Dienste_auf_IPv4_umstellen_Dovecot
sudo nano /etc/dovecot/dovecot.conf
#listen = *, ::
listen=*
Virtualmin_Dienste_auf_IPv4_umstellen_Postfix
sudo nano /etc/postfix/main.cf
#inet_protocols = all
inet_protocols = ipv4
Virtualmin_Dienste_auf_IPv4_umstellen_Webmin
sudo nano /etc/webmin/miniserv.conf
#ipv6=1
ipv6=0
Virtualmin_Dienste_auf_IPv4_umstellen_ProFTPd
sudo nano /etc/proftpd/proftpd.conf
#UseIPv6 on
UseIPv6 off
Virtualmin_Dienste_auf_IPv4_umstellen_Bind
sudo nano /etc/default/named
#OPTIONS="-u bind"
OPTIONS="-u bind -4"
Virtualmin_CalmAV_fix_wenn_noetig
#ClanAV sig update per WinSCP if needed
sudo su
/var/lib/clamav
chown clamav:clamav /var/lib/clamav -R
Virtualmin_Default_SSL_Hostname_loeschen
#If Virtualmin creates a hostname.domain.tld with SSL
cert you may want to delete it
#and create a new one so it shows up in normal doamin
list and it not hidden anymore
Server -> Virtualmin -> System Settings ->
Features and Plugins
click on DNS for Domain -> Domains "1" will bring up
hostname.domain.tld
Search Results -> hostname.domain.tld -> Enabled
features
disable DNS for domain
disable Apache website
Virtualmin -> hostname.domain.tld -> Disable and
Delete -> Delete Virtual Server
Virtualmin_unnoetige_Dienste_deaktivieren
#stop and remove unneeded service, reinstall needed
packages
Webmin -> System -> Bootup and Shutdown
etckeeper, etckeeper, fail2ban, firewalld -> Disable
Now and On Boot
Virtualmin_unnoetige_Dienste_deinstallieren
sudo apt-get remove --purge etckeeper git fail2ban
firewalld
sudo apt-get autoremove
sudo apt-get install bind9-utils ipset whois curl wget
Virtualmin_config_checken
Virtualmin -> ReCheck Config
Virtualmin_anpassen
Server -> Webmin -> Wemin Config -> Webmin
Themes -> Framed Theme
Virtualmin -> System Settings -> Account Plans
-> Default Plan ->
Quota for entire server - Unlimited
Quota for server administrator user - Unlimited
Virtualmin -> System Settings -> Features and
Plugins
Check Feature or Plugin and default
Virtualmin -> System Settings -> Virtualmin
Configuration -> User interface settings ->
Show mailbox size in users list - yes
Show last login in users list - yes
Show databases in users list - yes
Sort virtual servers by - Domain name
Show Pro features overview - No
Virtualmin -> System Settings -> Virtualmin
Configuration -> Defaults for new domains ->
Domain name style in username - Full domain name
Force group name to be always same as username - yes
Password field type - Enter password twice
Virtualmin -> System Settings -> Virtualmin
Configuration -> Spam filtering options ->
Default delivery for spam -> $HOME/Maildir/.spam/
Default delivery for viruses -> $HOME/Maildir/.virus/
Default spam whitelist option -> Enabled
Virtualmin -> System Settings -> Virtualmin
Configuration -> Backup and restore ->
Backup compression format - bzip2
Bzip2 compression command - pbzip2
Virtualmin -> System Settings -> Server Template
-> Default ->
DNS for Domain -> Address records for new domains -
only Domain and www
DNS for Domain -> Hostname for MX record ->
Hostname -> hostname.domain.tld
DNS for Domain -> Primary DNS server hostname ->
Hostname -> hostname.domain.tld
Mail for Domain -> Default quota for mail users -
Unlimited
Mail for Domain -> Format for usernames that include
domain - "username.domain"
Website for Domain -> Redirect webmail.${DOM} - no
Website for Domain -> Redirect admin.${DOM} - no
Website for Domain -> Redirects for new websites
-> Redirect all HTTP requests to HTTPS
Enable HTTP2 protocol for new websites -> yes
Virtualmin -> Email Settings -> Email Greylisting
-> enable
Virtualmin -> Email Settings -> Mail Client
Configuration -> Enable mail client autoconfiguration? no
Virtualmin_Backups_Planung
sudo mkdir /backup/vmin_full && sudo mkdir
/backup/vmin_differential
Virtualmin -> Backup and Restore -> Scheduled
Backups
Full Backup
Backup destinations -> Local file or derectory ->
/backup/vmin_full/%Y-%m-%d/
Delete old backups -> Yes, after 94 Days
Additional destination options
Do strftime-style time substitutions on file or
directory name
Transfer each virtual server after it is backed up
Backup format -> Create destination directory
Email backup report to ->
$BENUTZER@hostname.domain.tld
Only send email on failure
Scheduled backup time
Backup level -> Full (all files)
At cron time 0 2 1,10,20 * *
Differential Backup
Backup destinations -> Local file or derectory ->
/backup/vmin_differential/%Y-%m-%d/
Delete old backups -> Yes, after 94 Days
Additional destination options
Do strftime-style time substitutions on file or
directory name
Transfer each virtual server after it is backed up
Backup format -> Create destination directory
Email backup report to ->
$BENUTZER@hostname.domain.tld
Only send email on failure
Scheduled backup time
Backup level -> Differential (changes since full
backup)
At cron time 0 2 2-9,11-19,21-31 * *
Virtualmin_mehr_anpassen
Webmin -> Webmin -> Usermin Configuration -> IP
Access Control -> Resolve hostnames on every request ->
yes
Webmin -> Webmin -> Usermin Configuration -> IP
Access Control -> Only allow from listed addresses
hostname.domain.tld #you want allow to have access all
times
Webmin -> Webmin -> Webmin Configuration -> IP
Access Control -> Resolve hostnames on every request ->
yes
Webmin -> Webmin -> Webmin Configuration -> IP
Access Control -> Only allow from listed addresses
hostname.domain.tld #yout want allow to have access all
times
Webmin -> Webmin -> Webmin Configuration ->
Sending Email ->
Mail sending options -> From address for email from
Webmin -> Address -> webmin@hostname.domain.tld
Test $BENUTZER@hostname.domain.tld
Webmin -> Server -> Read User Mail -> user
Virtualmin_Systemd-timesync_durch_NTP_ersetzen_old-school-rulez
sudo apt-get update
sudo systemctl status systemd-timesyncd
sudo systemctl stop systemd-timesyncd
sudo systemctl disable systemd-timesyncd
sudo apt-get remove --purge systemd-timesyncd
sudo apt-get install ntpdate smartmontools
Virtualmin_config_check
Virtualmin -> System Settings -> Re-Check
Configuration
Virtualmin_NTP_nutzen
Webmin -> Hardware -> System Time -> Time
server sync ->
Timeserver hostnames or addresses - ptbtime1.ptb.de
Synchronize on schedule? - Yes, at times below ..
Virtualmin_Software_Updates_nur_anzeigen_lassen
Webmin -> System -> Software Package Updates ->
Scheduled Updates
Check for updates -> yes, every day
Email updates report to $BENUTZER@hostname.domain.tld
Action when update needed - Just notify for any updates
Virtualmin_Postfix_Mail_Groesse
Webmin -> Servers -> Postfix Mail Server ->
General Resource Control
Max size of a message -> 204800000 (200 MB)
Virtualmin_ProFTPd_Benutzer_ins_home_einsperren
Webmin -> Servers -> ProFTPD Server -> Files
and Directories -> Limit users to directories -> home
Virtualmin_2FA
Webmin -> Webmin -> Webmin Configuration ->
Two-Factor Authentication
Webmin -> Webmin -> Webmin Users -> root
klicken -> Two-Factor Authentication
Virtualmin_Benutzer_keine_unnoetigen_Module_anzeigen_lassen
Webmin -> Webmin -> Webmin Users -> username
-> Available Webmin Modules
uncheck
System: Bacula Backup System, LDAP Users and Groups,
LDAP Client
Servers: PostgreSQL Database Server, Samba Windows File
Sharing, Squid Report Generator, Squid Proxy Server
Networking: ADSL Client, Fail2Ban Intrusion
Detector, IPsec VPN Configuration, Linux Firewall,
NFS Exports, PPP Dialup Client, PPTP VPN Server, Shorewall
Firewall, FirewallD, Kerberos5,
Linux IPv6 Firewall, NIS Client and Server, PPP Dialin
Server, PPTP VPN Client, Shorewall6 Firewall
Hardware: iSCSI Client, iSCSI TGTd, Logical Volume
Management, Printer Administration, iSCSI Server, iSCSI Target
Cluster: all
Tools: Command Shell, Terminal, File Manager, Upload and
Download, Custom Commands
Taegliche_Backups_von_etc_als_Ersatz_fuer_etckeeper
sudo mkdir /backup/etc
sudo nano /opt/usr/sbin/backup_etc
#!/bin/bash
heute=$(date +%Y-%m-%d_%H-%M)
tar --use-compress-program=pbzip2 -cpf
/backup/etc/etc_${heute}.tar.bz2 -C /etc .
sudo chown root:root /opt/usr/sbin/backup_etc
sudo chmod 750 /opt/usr/sbin/backup_etc
sudo nano /etc/sudoers
NOPASSWD: /opt/usr/sbin/backup_etc
sudo nano /etc/crontab
0 1 * * * root /opt/usr/sbin/backup_etc
30 1 * * * root /opt/usr/sbin/backup_server_to_home
keine Subdomains wie ServerAlias mail.${DOM} anlegen
lassen
Virtualmin -> Virtualmin -> System Settings ->
Server Templates -> Website for domain
Directives and settings for new websites
fstab etwas sicherer machen
#<file system> <mount point>
<type> <options> <dump> <pass>
2 UUID=57763470-aa57-465c-9a5d-a61c0354401e / ext4
errors=remount-ro,grpquota,relatime,quota,usrquota,rw 0 1
3 UUID=51448698-12e1-4d34-b131-3519536b748b
/rescue ext4 ro,nofail,defaults 0 2
4 UUID=03b049f2-df78-4984-8055-a992656f6a75
/backup ext4 nofail,defaults 0 2
5 UUID=bbf574dc-1a51-49d2-b512-c75ae5d47dc8 none
swap nofail,sw 0 0
6 UUID=70adc66b-075d-46ab-82c5-263323a44a9f /data
ext4 nofail,defaults 0 2
#Mail auf der Kosole einrichten und an unser Mail System
anpassen
erst nach VirtualMin
EMail_auf_der_Konsole
sudo apt-get update && sudo apt-get install mutt
msmtp
nano ~/.muttrc
set sendmail="/usr/bin/msmtp"
set from=$BENUTZER@hostname.domain.tld
nano ~/.msmtprc
defaults
tls on
tls_starttls on
tls_certcheck off
auth on
logfile /home/$BENUTZER/msmtprc.log
account default
host 127.0.0.1
from $BENUTZER@hostname.domain.tld
user $BENUTZER
password SicheresPasswwort$BENUTZER
port 25
chmod 600 .msmtprc
ls -lha .msmtprc
echo "Test Message with Attachment" | mutt -s "Mail with
file" $BENUTZER@hostname.domain.tld -a ~/.bash_history
#Make mutt use our maildir
nano ~/.muttrc
set sendmail="/usr/bin/msmtp"
set from=$BENUTZER@hostname.domain.tld
set mbox_type=Maildir
set spoolfile="~/Maildir/"
set folder="~/Maildir/"
set mask=".*"
set record="+.Sent"
set postponed="+.Drafts"
# Generate mailboxes for each maildir subdir
mailboxes ! + `\
for file in ~/Maildir/.*; do \
box=$(basename "$file"); \
if [ ! "$box" = '.' -a ! "$box" = '..' -a !
"$box" = '.customflags' \
-a ! "$box" =
'.subscriptions' ]; then \
echo -n "\"+$box\" "; \
fi; \
done`
# Marcos to display folder list when changing maildir
folders
macro index c
"<change-folder>?<toggle-mailboxes>" "open a
different folder"
macro pager c
"<change-folder>?<toggle-mailboxes>" "open a
different folder"
# Macros to display folder list when copying/moving
messages
macro index C
"<copy-message>?<toggle-mailboxes>" "copy a message
to a mailbox"
macro index M
"<save-message>?<toggle-mailboxes>" "move a message
to a mailbox"
#Default Domain (hostname.domain.tld) anlegen
Virtualmin_hostname.domain.tld_anlegen
#Time to get real
#create a host in Virtualmin
#hostname.domain.tld
#use this SSL Cert for the system
Virtualmin -> hostname.domain.tld -> Manage
Virtual Server -> Setup SSL Certificate -> Set as default
#CSF Firewall installieren und Grundeinrichtung
CSF_firewall_by_Aetherinox
#Install dependencies
sudo apt-get update && sudo apt-get install -y
ipset libcrypt-ssleay-perl libio-socket-inet6-perl
libio-socket-ssl-perl libnet-libidn-perl libsocket6-perl perl
wget bind9-dnsutils
sudo perl -MCPAN -e 'install GD::Graph' # für "schöne"
Statistiken
perl -MCPAN -e 'install Sys::Syslog'
#Download and extract
cd && mkdir csf && cd csf &&
wget https://download.configserver.dev/csf.tgz && tar
-xf csf.tgz && cd csf
#run Run Pre-install Tests
sudo perl csftest.pl
#Install csf
sudo sh install.sh
sudo cp /etc/csf/csf.conf /root/csf.conf.default
ls -lha /etc/csf/csf.conf
-rw------- 1 root root 123K 11. Jan 15:54
/etc/csf/csf.conf
config-start CSF_firewall_base_config
#Now comes the fun part... edit the config file
sudo nano /etc/csf/csf.conf
#Basic setup
TESTING = "0"
RESTRICT_SYSLOG = "3"
TCP_IN =
"20,21,22,25,53,853,80,110,143,443,465,587,993,995,9999,10000,20000"
TCP_OUT =
"20,21,22,25,53,853,80,110,113,443,587,993,995,25000"
UDP_OUT = "20,21,53,853,113,123,33434:33523"
#Enable DynDNS in csf
DYNDNS = "1"
DYNDNS_IGNORE = "1"
GLOBAL_DYNDNS_INTERVAL = "300"
#binary paths for Debian 12.12 as of 2025-12-20
IPTABLES = "/usr/sbin/iptables"
IPTABLES_SAVE = "/usr/sbin/iptables-save"
IPTABLES_RESTORE = "/usr/sbin/iptables-restore"
IP6TABLES = "/usr/sbin/ip6tables"
IP6TABLES_SAVE = "/usr/sbin/ip6tables-save"
IP6TABLES_RESTORE = "/usr/sbin/ip6tables-restore"
MODPROBE = "/usr/sbin/modprobe"
IFCONFIG = "/usr/sbin/ifconfig"
SENDMAIL = "/usr/sbin/sendmail"
PS = "/usr/bin/ps"
VMSTAT = "/usr/bin/vmstat"
NETSTAT = "/usr/bin/netstat"
LS = "/usr/bin/ls"
MD5SUM = "/usr/bin/md5sum"
TAR = "/usr/bin/tar"
CHATTR = "/usr/bin/chattr"
UNZIP = "/usr/bin/unzip"
GUNZIP = "/usr/bin/gunzip"
DD = "/usr/bin/dd"
TAIL = "/usr/bin/tail"
GREP = "/usr/bin/grep"
ZGREP = "/usr/bin/zgrep"
IPSET = "/usr/sbin/ipset"
SYSTEMCTL = "/usr/bin/systemctl"
HOST = "/usr/bin/host"
IP = "/usr/bin/ip"
CURL = "/usr/bin/curl"
WGET = "/usr/bin/wget"
#Logfile locations for this Debian 9 ->12.12 as of
2025-12-20
HTACCESS_LOG = "/var/log/apache2/error.log"
MODSEC_LOG = "/var/log/apache2/error.log"
SSHD_LOG = "/var/log/auth.log"
SU_LOG = "/var/log/auth.log"
SUDO_LOG = "/var/log/auth.log"
FTPD_LOG = "/var/log/proftpd/proftpd.log"
SMTPAUTH_LOG = "/var/log/auth.log"
POP3D_LOG = "/var/log/mail.log"
IMAPD_LOG = "/var/log/mail.log"
IPTABLES_LOG = "/var/log/syslog"
SUHOSIN_LOG = "/var/log/syslog"
BIND_LOG = "/var/log/syslog"
SYSLOG_LOG = "/var/log/syslog"
WEBMIN_LOG = "/var/log/auth.log"
config-end
CSF_firewall_DynDNS_namen_fuer_auto_whitelisting
sudo nano /etc/csf/csf.dyndns
#fqdn only
#hostname.domain.tld you want to allow, not the local
hostname
config-end
config-start CSF_firewall_Prozesse_ueberwachen_reset
#CSF Process tracking
#remove all line with exe:/ from /etc/csf/csf.pignore.
#lfd will send you emails with deamons running, grep
them an create a /etc/csf/csf.pignore suiteable for your system.
#Debian 12 2025-12-28
exe:/usr/bin/bash
exe:/usr/bin/dbus-daemon
exe:/usr/bin/pbzip2
exe:/usr/bin/perl
exe:/usr/bin/screen
exe:/usr/bin/watch
exe:/usr/lib/dovecot/anvil
exe:/usr/lib/dovecot/stats
exe:/usr/lib/postfix/sbin/pickup
exe:/usr/lib/postfix/sbin/qmgr
exe:/usr/lib/postfix/sbin/tlsmgr
exe:/usr/lib/systemd/systemd
exe:/usr/lib/virtualbox/VBoxSVC
exe:/usr/lib/virtualbox/vboxwebsrv
exe:/usr/sbin/apache2
exe:/usr/sbin/clamd
exe:/usr/sbin/mariadbd
exe:/usr/sbin/opendkim
exe:/usr/sbin/php-fpm8.2
exe:/usr/sbin/proftpd
exe:/usr/sbin/sshd
#restart csf
sudo csf -ra
config-start CSF_firewall_Install_Support_to_Virtualmin
Webmin -> Webmin -> Wemin Configuration ->
Virtualmin Module ->
Install from local file ->
/usr/local/csf/csfwebmin.tgz
config-end
sudo chown root:root /etc/csf/csf.conf
sudo chmod 600 /etc/csf/csf.conf
config-start CSF_Firewall_DynDNS_Hostname
sudo nano /etc/csf/csf.dyndns
config-end
config-start CSF_Firewall_Prozess_Tracking
sudo nano /etc/csf/csf.pignore
config-end
config-start
Script_Easy_Firewall_restart_mit_sudo_ohne_PW_abfrage
sudo nano /opt/usr/sbin/firewall_restart
#!/bin/bash
/usr/sbin/csf -ra
sudo chown root:root /opt/usr/sbin/firewall_restart
sudo chmod 750 /opt/usr/sbin/firewall_restart
sudo nano /etc/sudoers
$USER ALL = NOPASSWD: /opt/usr/sbin/firewall_restart
config-end
config-start CSF_Tools_Firewall_EMail_durchsuchen
mails nach
find . -type f -exec grep -l "Excessive resource" {} + |
xargs grep -h "Executable:" | sed 's/.*Executable: *//' | sort
-u
find . -type f -exec grep -l "Excessive resource" {} + |
xargs grep -h "Executable:" | sed 's/.*Executable: *//' | sort
-u | sed 's|^|exe:|'
config-end
#CSF Firewall eigene Regeln erstellen
csf eigene regeln
nano /etc/csf/regex.custom.pm
if (($globlogs{SMTPAUTH_LOG} =~ %S) &&
($line =~ /^\S+ \S+ postfix\/smtpd\[\d+\]: warning:
.*\[(\d+\.\d+\.\d+\.\d+)\]: SASL (?:LOGIN|PLAIN) authentication
failed:>
68 return ("Custom SASL Attack
Block",$1,"my_sasl_jail","2","25,465,587,143,993","1");
69 }
#Meine CSF Tools installieren
#!/bin/bash
cat << 'EOF_CSF1' >
/opt/usr/sbin/csf_tools_bin_check
#!/bin/bash
###############################################################################
#
#
# ██████╗ ███████╗███████╗
████████╗ ██████╗ ██████╗ ██╗
███████╗ #
# ██╔════╝ ██╔════╝██╔════╝
╚══██╔══╝██╔═══██╗██╔═══██╗██║
██╔════╝ #
# ██║
███████╗█████╗
██║ ██║ ██║██║
██║██║ ███████╗ #
# ██║
╚════██║██╔══╝
██║ ██║ ██║██║
██║██║ ╚════██║ #
# ╚██████╗
███████║██║
██║ ╚██████╔╝╚██████╔╝███████╗███████║ #
# ╚═════╝
╚══════╝╚═╝
╚═╝ ╚═════╝ ╚═════╝
╚══════╝╚══════╝ #
#
#
# CSF
TOOLKIT
#
# binary
check
#
# Copyright (c) 2025 Oliver Arp aka
The_Kangaroo
#
# Licensed under the GNU General Public License
(GPL)
#
#
#
###############################################################################
#
#System Binary Validator
#
#Verifies that all 28 critical system executables
(iptables, grep, etc.) exist and match the paths defined in
csf.conf.
#It automatically suggests the correct paths if a
mismatch is detected during the system scan.
#
CONF_FILE="/etc/csf/csf.conf"
RED='\033[0;31m'
GREEN='\033[0;32m'
NC='\033[0m' # No Color
# 1. Root check
if [[ $EUID -ne 0 ]]; then
echo -e "${RED}ERROR: Root privileges
required.${NC}"
exit 1
fi
BINARY_LIST="IPTABLES IPTABLES_SAVE IPTABLES_RESTORE
IP6TABLES IP6TABLES_SAVE IP6TABLES_RESTORE MODPROBE IFCONFIG
SENDMAIL PS VMSTAT NETSTAT LS MD5SUM TAR CHATTR UNZIP GUNZIP DD
TAIL GREP ZGREP IPSET SYSTEMCTL HOST IP CURL WGET"
ERR_COUNT=0
# 2. Validation loop
for VAR in $BINARY_LIST; do
echo -n "Searching for $VAR... "
LINE=$(grep -E "^$VAR ="
"$CONF_FILE")
if [[ -n "$LINE" ]]; then
BIN_PATH=$(echo "$LINE" | awk -F'"' '{print $2}' | awk '{print
$1}')
if [[ -x
"$BIN_PATH" ]]; then
echo -e "found $VAR under $BIN_PATH"
echo -e "${GREEN}$VAR ok${NC}"
else
((ERR_COUNT++))
ACTUAL_PATH=$(which "$(basename "$BIN_PATH")" 2>/dev/null)
if [[ -n "$ACTUAL_PATH" ]]; then
echo -e "found $VAR under $ACTUAL_PATH"
echo -e "${RED}ERROR: Path in config ($BIN_PATH) does not match
system!${NC}"
else
echo -e "${RED}ERROR: $VAR not found on system!${NC}"
fi
fi
else
echo -e
"${RED}$VAR not defined in config!${NC}"
fi
echo
"--------------------------------------------------------"
done
# 3. Final Summary
if [[ $ERR_COUNT -gt 0 ]]; then
echo -e "${RED}Validation failed:
$ERR_COUNT binaries have path mismatches or are missing!${NC}"
else
echo -e "${GREEN}All binaries
validated successfully (100.00%).${NC}"
fi
EOF_CSF1
cat << 'EOF_CSF2' >
/opt/usr/sbin/csf_tools_log_file_validator
#!/bin/bash
###############################################################################
#
#
# ██████╗ ███████╗███████╗
████████╗ ██████╗ ██████╗ ██╗
███████╗ #
# ██╔════╝ ██╔════╝██╔════╝
╚══██╔══╝██╔═══██╗██╔═══██╗██║
██╔════╝ #
# ██║
███████╗█████╗
██║ ██║ ██║██║
██║██║ ███████╗ #
# ██║
╚════██║██╔══╝
██║ ██║ ██║██║
██║██║ ╚════██║ #
# ╚██████╗
███████║██║
██║ ╚██████╔╝╚██████╔╝███████╗███████║ #
# ╚═════╝
╚══════╝╚═╝
╚═╝ ╚═════╝ ╚═════╝
╚══════╝╚══════╝ #
#
#
# CSF
TOOLKIT
#
# log file
validator
#
# Copyright (c) 2025 Oliver Arp aka
The_Kangaroo
#
# Licensed under the GNU General Public License
(GPL)
#
#
#
###############################################################################
#
#Active Log Source Checker
#
#Scans all enabled log definitions to ensure the
physical log files exist
#and are readable by the LFD daemon. Color-coded results
quickly identify
#dead links or missing log files that would otherwise
cause monitoring gaps.
#
# Configuration file path
CONF_FILE="/etc/csf/csf.conf"
# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# 1. Check for root/sudo privileges
if [[ $EUID -ne 0 ]]; then
echo -e "${RED}ERROR: This script must be
run as root or with sudo.${NC}"
exit 1
fi
# 2. Check if the config file exists
if [[ ! -r "$CONF_FILE" ]]; then
echo -e "${RED}ERROR: Cannot read
$CONF_FILE.${NC}"
exit 1
fi
echo "Starting CSF Log Configuration Validation..."
echo
"--------------------------------------------------------"
ERR_COUNT=0
TOTAL_COUNT=0
# 3. Process active log definitions
grep -E "^[A-Z0-9_]+_LOG =" "$CONF_FILE" | while read -r
line; do
SERVICE=$(echo "$line" | awk -F'='
'{print $1}' | tr -d ' ')
LOGPATH=$(echo "$line" | awk -F'"'
'{print $2}')
# 4. Filter: Only check if it's an
actual path (starts with /)
if [[ "$LOGPATH" == /* ]]; then
((TOTAL_COUNT++))
echo -n
"Checking $SERVICE... "
if [[ -f
"$LOGPATH" ]]; then
echo -e "${GREEN}OK${NC} ($LOGPATH)"
else
echo -e "${RED}MISSING${NC} ($LOGPATH)"
((ERR_COUNT++))
fi
else
# Skip
switches like "1", "0" or empty values (Optionaler Info-Output)
echo -e
"${BLUE}[INFO]${NC} Skipping $SERVICE:
Not a path ($LOGPATH)"
fi
done
echo
"--------------------------------------------------------"
# 5. Final Summary
if [[ $ERR_COUNT -gt 0 ]]; then
echo -e "${RED}Validation failed:
$ERR_COUNT of $TOTAL_COUNT active logfiles are missing!${NC}"
else
echo -e "${GREEN}Success: All
$TOTAL_COUNT active logfiles found (100.00%).${NC}"
fi
EOF_CSF2
cat << 'EOF_CSF3' >
/opt/usr/sbin/csf_tools_logrotate_check
#!/bin/bash
###############################################################################
#
#
# ██████╗ ███████╗███████╗
████████╗ ██████╗ ██████╗ ██╗
███████╗ #
# ██╔════╝ ██╔════╝██╔════╝
╚══██╔══╝██╔═══██╗██╔═══██╗██║
██╔════╝ #
# ██║
███████╗█████╗
██║ ██║ ██║██║
██║██║ ███████╗ #
# ██║
╚════██║██╔══╝
██║ ██║ ██║██║
██║██║ ╚════██║ #
# ╚██████╗
███████║██║
██║ ╚██████╔╝╚██████╔╝███████╗███████║ #
# ╚═════╝
╚══════╝╚═╝
╚═╝ ╚═════╝ ╚═════╝
╚══════╝╚══════╝ #
#
#
# CSF
TOOLKIT
#
# logrotate check for CSF
logs
#
# Copyright (c) 2025 Oliver Arp aka
The_Kangaroo
#
# Licensed under the GNU General Public License
(GPL)
#
#
#
###############################################################################
#
#Log Maintenance Auditor
#
#Cross-references active CSF log paths with the system's
logrotate configuration
#to prevent uncontrolled file growth. Identifies
unmanaged logs in red to protect
#your server from potential disk space exhaustion.
#
# Configuration paths
CSF_CONF="/etc/csf/csf.conf"
LOGROTATE_DIR="/etc/logrotate.d"
LOGROTATE_CONF="/etc/logrotate.conf"
# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
NC='\033[0m' # No Color
# 1. Root check
if [[ $EUID -ne 0 ]]; then
echo -e "${RED}ERROR: This script must be
run as root.${NC}"
exit 1
fi
echo "Starting CSF vs. Logrotate Consistency Check..."
echo
"--------------------------------------------------------"
ERR_COUNT=0
TOTAL_COUNT=0
# 2. Get all active log paths from CSF
# Wir filtern hier nur die Zeilen, die wirklich einen
Pfad in Anführungszeichen haben
grep -E "^[A-Z0-9_]+_LOG =" "$CSF_CONF" | grep '"/' |
while read -r line; do
SERVICE=$(echo "$line" | awk -F'='
'{print $1}' | tr -d ' ')
LOGPATH=$(echo "$line" | awk -F'"'
'{print $2}')
((TOTAL_COUNT++))
echo -n "Checking $SERVICE
($LOGPATH)... "
# 3. Check if the path is mentioned
in any logrotate config
if grep -q "$LOGPATH"
"$LOGROTATE_CONF" || grep -rq "$LOGPATH" "$LOGROTATE_DIR"
2>/dev/null; then
echo -e
"${GREEN}OK${NC}"
else
echo -e
"${RED}NOT FOUND in logrotate!${NC}"
((ERR_COUNT++))
fi
done
echo
"--------------------------------------------------------"
# 4. Final Summary
if [[ $ERR_COUNT -gt 0 ]]; then
echo -e "${RED}Warning: $ERR_COUNT of
$TOTAL_COUNT logs are not managed by logrotate!${NC}"
echo "This could lead to disk space
issues."
else
echo -e "${GREEN}Excellent: All
$TOTAL_COUNT active logs are covered by logrotate
(100.00%).${NC}"
fi
EOF_CSF3
sudo chown root:root /opt/usr/sbin/csf_tools_bin_check
sudo chown root:root
/opt/usr/sbin/csf_tools_log_file_validator
sudo chown root:root
/opt/usr/sbin/csf_tools_logrotate_check
sudo chmod 555 /opt/usr/sbin/csf_tools_bin_check
sudo chmod 555
/opt/usr/sbin/csf_tools_log_file_validator
sudo chmod 555 /opt/usr/sbin/csf_tools_logrotate_check
echo "sudo nano /etc/sudoers"
echo "ALL=/opt/usr/sbin/csf_tools_bin_check,
/opt/usr/sbin/csf_tools_log_file_validator,
/opt/usr/sbin/csf_tools_logrotate_check"
#Virtualbox und phpVirtualBox installieren und
einrichten
Virtualbox_installieren_und_phpVirtualBox
sudo su
wget -O-
https://www.virtualbox.org/download/oracle_vbox_2016.asc | sudo
gpg --yes --output
/usr/share/keyrings/oracle-virtualbox-2016.gpg --dearmor
sudo nano /etc/apt/sources.list
#Virtualbox
deb [arch=amd64
signed-by=/usr/share/keyrings/oracle-virtualbox-2016.gpg]
https://download.virtualbox.org/virtualbox/debian bookworm
contrib
sudo apt-get update
sudo apt-get install virtualbox-7.2
wget
https://download.virtualbox.org/virtualbox/7.2.4/Oracle_VirtualBox_Extension_Pack-7.2.4-170995.vbox-extpack
sudo VBoxManage extpack install
Oracle_VirtualBox_Extension_Pack-7.2.4-170995.vbox-extpack
rm
Oracle_VirtualBox_Extension_Pack-7.2.4-170995.vbox-extpack
sudo adduser vbox
sudo adduser vbox vboxusers
create vbox.hostname.domain.tld in Virtualmin
create vbox.hostname.domain.tld in Cloudflare.com
sudo su - vbox.hostname.domain.tld
wget
https://github.com/phpvirtualbox/phpvirtualbox/archive/refs/tags/7.2-2.zip
extract to public_html/
exit
php -v #Version 8.2.29
sudo apt-get install libapr1 libaprutil1
libaprutil1-dbd-sqlite3 libaprutil1-ldap php8.2-common
php8.2-mysql php8.2-soap php-pear
sudo nano /etc/default/virtualbox
VBOXWEB_USER=vbox
VBOXWEB_HOST=127.0.0.1
sudo mkdir /data/vbox
sudo mkdir /data/vbox/vms
sudo mkdir /data/vbox/isos
wget
https://download.virtualbox.org/virtualbox/7.2.4/VBoxGuestAdditions_7.2.4.iso
sudo cp VBoxGuestAdditions_7.2.4.iso
/data/vbox/isos/VBoxGuestAdditions_7.2.4.iso
sudo chmod 440
/data/vbox/isos/VBoxGuestAdditions_7.2.4.iso
sudo chown vbox:vbox /data/vbox -R
rm VBoxGuestAdditions_7.2.4.iso
sudo su - vbox.hostname.domain.tld
cd public_html/
cp config.php-example config.php
nano config.php
var $password = 'SicheresPasswwortvbox';
var $language = 'de';
var $vrdeaddress = '1.2.3.4';
var $consoleHost = '1.2.3.4';
#var $previewWidth = 180;
var $previewWidth = 640;
var $browserRestrictFolders = array('/data/vbox');
reboot & login to https://vbox.hostname.domain.tld
to ceate VMs _should_ work
systemctl list-units "vbox*"
systemctl list-unit-files | grep vbox
systemctl status vboxweb-service.service
journalctl -u vboxweb-service.service -xe
Script_laufende_VMs_anzeigen
sudo su - vbox
cd
nano list_running_vms.sh
#!/bin/bash
vboxmanage list runningvms
chmod 750 list_running_vms.sh
Script_VMs_automatischer_start
sudo su - vbox
cd
nano start.sh
#!/bin/bash
#/usr/bin/vboxmanage startvm --type headless
#/usr/bin/vboxmanage startvm --type headless
2e1afc3e-0ab7-45f0-a1a4-b23febdc236c
chmod 750 start.sh
exit
VMs_automatisch_per_SystemD_starten
sudo nano /etc/systemd/system/startvms.service
[Unit]
Description=Start VMs
After=network.target
[Service]
Type=simple
Restart=no
User=vbox
ExecStartPre=/bin/sleep 15
ExecStart=/home/vbox/start.sh
[Install]
WantedBy=multi-user.target
sudo chown root:root
/etc/systemd/system/startvms.service
sudo chmod 660 /etc/systemd/system/startvms.service
sudo systemctl daemon-reload
sudo systemctl enable startvms.service
sudo systemctl start startvms.service
ExecStartPre=/usr/bin/sleep 5 #hinzufügen
sudo nano /lib/systemd/system/vboxweb-service.service
[Unit]
SourcePath=/usr/lib/virtualbox/vboxweb-service.sh
Description=
Before=runlevel2.target runlevel3.target
runlevel4.target runlevel5.target shutdown.target
After=network-online.target vboxdrv.service
Conflicts=shutdown.target
[Service]
Type=forking
Restart=no
TimeoutSec=5min
IgnoreSIGPIPE=no
KillMode=process
GuessMainPID=no
RemainAfterExit=yes
ExecStartPre=/bin/sleep 5
ExecStart=/usr/lib/virtualbox/vboxweb-service.sh start
ExecStop=/usr/lib/virtualbox/vboxweb-service.sh stop
[Install]
WantedBy=multi-user.target
#VirtualBox per TUI
sudo su - vbox
nano vbox_control.sh
#!/bin/bash
#
---------------------------------------------------------------------------------
# Dieses Programm nutzt für seine Funktionen nur die
folgenden Programme:
# - VBoxManage, pgrep, stat, date, du, grep, awk, cut,
tr, mapfile, ls, basename
#
---------------------------------------------------------------------------------
# --- Variablen (Konfiguration) ---
VM_BASE_PATH="/data/vbox/vms/"
ISO_PATH="/data/vbox/isos/"
WIDTH=95
LANG_DEFAULT="DE"
target_user="vbox"
# --- Texte Laden (Assoziatives Array) ---
declare -A TXT
set_language() {
if [[ "$1" == "EN" ]]; then
LANG_CURRENT="EN"
TXT[title]="VIRTUALBOX CLI MANAGER"
TXT[help_head]="VIRTUALBOX CLI MANAGER - HELP / SUMMARY"
TXT[help_usage]="Usage: $0 [Option]"
TXT[help_opt_h]=" -h Show this
help"
TXT[help_opt_en]=" -en Start in English"
TXT[help_opt_de]=" -de Start in German"
TXT[help_desc]="Summary of Features:"
TXT[help_f1]=" * VM-Management: Start (Headless), Pause,
ACPI-Shutdown, Power-Off"
TXT[help_f2]=" * Snapshots:
Create, List and Restore VM states"
TXT[help_f3]=" * Configuration: CPU/RAM adjustments and
ISO Mounting"
TXT[help_f4]=" * Provisioning: Guided creation of
new VMs with Disk/NIC"
TXT[help_keys]="Interactive Keys:"
TXT[help_k1]=" [s] Refresh list, [l] Toggle Language, [q]
Exit, [Num] Select VM"
TXT[help_paths]="Paths:"
TXT[overview]="CURRENT LAB OVERVIEW"
TXT[status]="STATUS"; TXT[uptime]="UPTIME"; TXT[mode]="MODE"
TXT[action]="CHOOSE ACTION"
TXT[menu1]="START (HEADLESS)"; TXT[menu2]="PAUSE (STANDBY)";
TXT[menu3]="SHUTDOWN (ACPI)"
TXT[menu4]="SNAPSHOT MGR"; TXT[menu5]="SHOW DETAILS";
TXT[menu6]="HARD STOP (POWER)"
TXT[menu7]="CREATE VM"; TXT[menu8]="DELETE VM"; TXT[menu9]="EDIT
VM"
TXT[menu10]="ISO OVERVIEW"; TXT[menu_l]="l) LANGUAGE (DE/EN)";
TXT[menu_q]="q) EXIT"; TXT[menu_s]="s) REFRESH"
TXT[err_dep]="ERROR: Missing dependencies"; TXT[err_perm]="🟡
Warning: Access Denied / Missing Permissions"
TXT[prompt_vm]="WHICH VM (Nr)? (s for back): ";
TXT[confirm]="Confirm with"; TXT[done]="DONE. PRESS ANY KEY..."
TXT[v_name]="NAME"; TXT[v_ram]="RAM (MB)"; TXT[v_hdd]="HDD
(MB)"; TXT[v_iso]="Select ISO Archive"; TXT[back]="s) Back"
TXT[det_storage]="STORAGE & ISO CONFIG"
else
LANG_CURRENT="DE"
TXT[title]="VIRTUALBOX CLI MANAGER"
TXT[help_head]="VIRTUALBOX CLI MANAGER - HILFE /
ZUSAMMENFASSUNG"
TXT[help_usage]="Nutzung: $0 [Option]"
TXT[help_opt_h]=" -h Diese Hilfe
anzeigen"
TXT[help_opt_en]=" -en Auf Englisch
starten"
TXT[help_opt_de]=" -de Auf Deutsch
starten"
TXT[help_desc]="Funktionsübersicht:"
TXT[help_f1]=" * VM-Steuerung: Start (Headless),
Pause, ACPI-Shutdown, Power-Off"
TXT[help_f2]=" * Snapshots:
Erstellen, Listen und Wiederherstellen von Zuständen"
TXT[help_f3]=" * Konfiguration: CPU/RAM Anpassung und
ISO-Mounting"
TXT[help_f4]=" * Provisioning: Geführtes Erstellen
neuer VMs inkl. Disk/Netzwerk"
TXT[help_keys]="Tastenbefehle:"
TXT[help_k1]=" [s] Aktualisieren, [l] Sprache wechseln,
[q] Beenden, [Nr] VM wählen"
TXT[help_paths]="Pfade:"
TXT[overview]="AKTUELLE LABOR-ÜBERSICHT"
TXT[status]="STATUS"; TXT[uptime]="UPTIME"; TXT[mode]="MODUS"
TXT[action]="AKTION WÄHLEN"
TXT[menu1]="STARTEN (HEADLESS)"; TXT[menu2]="PAUSIEREN
(STANDBY)"; TXT[menu3]="HERUNTERFAHREN (ACPI)"
TXT[menu4]="SNAPSHOT MANAGEMENT"; TXT[menu5]="DETAILS ANZEIGEN";
TXT[menu6]="HARTER STOP (POWER)"
TXT[menu7]="VM ERSTELLEN"; TXT[menu8]="VM LÖSCHEN";
TXT[menu9]="VM BEARBEITEN"
TXT[menu10]="ISO ÜBERSICHT"; TXT[menu_l]="l) SPRACHE (DE/EN)";
TXT[menu_q]="q) BEENDEN"; TXT[menu_s]="s) AKTUALISIEREN"
TXT[err_dep]="FEHLER: Fehlende Abhängigkeiten";
TXT[err_perm]="🟡 Warnung: Zugriff verweigert / Fehlende Rechte"
TXT[prompt_vm]="WELCHE VM (Nr)? (s für zurück): ";
TXT[confirm]="Bestätige mit"; TXT[done]="FERTIG. BELIEBIGE
TASTE..."
TXT[v_name]="NAME"; TXT[v_ram]="RAM (MB)"; TXT[v_hdd]="HDD
(MB)"; TXT[v_iso]="ISO Archiv wählen"; TXT[back]="s) Zurück"
TXT[det_storage]="STORAGE & ISO KONFIGURATION"
fi
}
# --- Hilfe-Funktion ---
show_help() {
echo -e
"\033[1;32m${TXT[help_head]}\033[0m"
echo -e "${TXT[help_usage]}"
echo -e
"${TXT[help_opt_h]}\n${TXT[help_opt_en]}\n${TXT[help_opt_de]}"
echo -e "\n${TXT[help_desc]}"
echo -e
"${TXT[help_f1]}\n${TXT[help_f2]}\n${TXT[help_f3]}\n${TXT[help_f4]}"
echo -e
"\n${TXT[help_keys]}\n${TXT[help_k1]}"
echo -e "\n${TXT[help_paths]}\n
VM: $VM_BASE_PATH\n ISO: $ISO_PATH"
exit 0
}
# --- Initialisierung & Parameter ---
set_language "$LANG_DEFAULT"
case "$1" in
-h|--help) show_help ;;
-en) set_language "EN" ;;
-de) set_language "DE" ;;
esac
identify_distro() { [[ -f /etc/os-release ]] &&
grep -E "^ID=" /etc/os-release | cut -d'=' -f2 | tr -d '"' ||
echo "unknown"; }
check_dependencies() {
local tools=("VBoxManage" "pgrep"
"stat" "date" "du" "grep" "awk" "cut" "tr" "ls" "basename")
local missing=()
for t in "${tools[@]}"; do command -v
"$t" &> /dev/null || missing+=("$t"); done
if [ ${#missing[@]} -ne 0 ]; then
DID=$(identify_distro); echo -e "\033[0;31m${TXT[err_dep]}:
${missing[*]}\033[0m"
case "$DID"
in rocky|rhel|fedora|almalinux) echo "sudo dnf install
VirtualBox-7.x procps-ng coreutils" ;;
debian|ubuntu|devuan|kali) echo "sudo apt update && sudo
apt install virtualbox procps coreutils" ;; *) echo "Bitte
installiere die Pakete manuell." ;; esac; exit 1
fi
}
check_dependencies
handle_error() {
local file="$1"
echo -e
"\033[1;33m${TXT[err_perm]}\033[0m\nDatei: $file\nLösung:
target_user prüfen (aktuell:
target_user=\"$target_user\").\nManuelle Reparatur: chmod 0644
$file && chown $target_user:root $file"
read -p "${TXT[done]}" d
}
get_vm_ip() { local ip=$(VBoxManage guestproperty get
"$1" "/VirtualBox/GuestInfo/Net/0/V4/IP" 2>/dev/null | grep
"Value:" | awk '{print $2}'); [[ -z "$ip" || "$ip" == "No" ]]
&& echo "---" || echo "$ip"; }
get_uptime() {
local pid=$(pgrep -f "$1"); if [[ -z
"$pid" ]]; then echo "---"; else
local
start=$(stat -c %Y /proc/$pid 2>/dev/null); [[ -z "$start" ]]
&& { echo "---"; return; }
local s=$((
$(date +%s) - start )); local d=$((s/86400)); local
h=$(((s%86400)/3600)); local m=$(((s%3600)/60))
[ $d -gt 0 ]
&& echo "${d}d ${h}h" || { [ $h -gt 0 ] && echo
"${h}h ${m}m" || echo "${m}m"; }
fi
}
refresh_vm_list() { unset VM_NAMES; unset VM_UUIDS;
mapfile -t VM_NAMES < <(VBoxManage list vms | awk -F '"'
'{print $2}'); mapfile -t VM_UUIDS < <(VBoxManage list vms
| awk -F '[{}]' '{print $2}'); }
select_iso() {
local isos=("$ISO_PATH"/*.iso); [[ !
-e "${isos[0]}" ]] && { echo "Keine ISOs gefunden!";
return 1; }
echo -e "\033[1;32m
${TXT[v_iso]}\033[0m"
for i in "${!isos[@]}"; do printf
" %02d) %s\n" "$((i+1))" "$(basename
"${isos[$i]}")"; done
read -p " WAHL (Nr) oder
(s) skip: " choice
[[ "$choice" == "s" ]] && {
SELECTED_ISO="emptydrive"; return 0; }
if [[ "$choice" =~ ^[0-9]+$ ]]
&& [ "$choice" -le "${#isos[@]}" ]; then
SELECTED_ISO="${isos[$((choice-1))]}"; return 0; fi
return 1
}
draw_header() {
local mode_text="$1"; local
skip_list="$2"
clear; echo -e
"\033[0;32m==============================================================================================="
printf "%*s\n" $(( (${#TXT[title]} +
WIDTH) / 2 )) "${TXT[title]}"
echo -e
"===============================================================================================\033[0m"
[[ -n "$mode_text" ]] && echo
-e "\033[1;33m ${TXT[mode]}: $mode_text\033[0m"
if [[ "$skip_list" != "true" ]]; then
printf "%-4s
| %-25s | %-15s | %-12s | %-15s\n" "NR" "VM NAME" "IP"
"${TXT[status]}" "${TXT[uptime]}"
echo
"-----------------------------------------------------------------------------------------------"
for i in
"${!VM_NAMES[@]}"; do
local uuid="${VM_UUIDS[$i]}"; local status="OFFLINE"; local
ip="---"; local uptime="---"
VBoxManage list runningvms | grep -q "$uuid" && {
status="AKTIV"; ip=$(get_vm_ip "$uuid"); uptime=$(get_uptime
"$uuid"); }
printf "%02d | %-25s | %-15s | %-12s | %-15s\n"
"$((i+1))" "${VM_NAMES[$i]}" "$ip" "$status" "$uptime"
done
echo
"-----------------------------------------------------------------------------------------------"
fi
}
while true; do
refresh_vm_list
draw_header ""
printf " 1) %-25s 4)
%-25s 7) %-25s\n" "${TXT[menu1]}" "${TXT[menu4]}"
"${TXT[menu7]}"
printf " 2) %-25s 5)
%-25s 8) %-25s\n" "${TXT[menu2]}" "${TXT[menu5]}"
"${TXT[menu8]}"
printf " 3) %-25s 6)
%-25s 9) %-25s\n" "${TXT[menu3]}" "${TXT[menu6]}"
"${TXT[menu9]}"
printf " 10) %-25s\n"
"${TXT[menu10]}"
echo
"-----------------------------------------------------------------------------------------------"
printf "
%-20s
%-20s %-20s\n" "${TXT[menu_q]}"
"${TXT[menu_s]}" "${TXT[menu_l]}"
echo
"-----------------------------------------------------------------------------------------------"
read -p "${TXT[action]}: " action
[[ "$action" == "l" || "$action" ==
"L" ]] && { [[ "$LANG_CURRENT" == "DE" ]] &&
set_language "EN" || set_language "DE"; continue; }
[[ "$action" == "q" || "$action" ==
"Q" ]] && break
[[ "$action" == "s" || "$action" ==
"S" ]] && continue
if [[ "$action" =~ ^[1-6|8-9]$ ]];
then
cur_mode_key="menu$action";
cur_mode_text="${TXT[$cur_mode_key]}"
draw_header
"$cur_mode_text"
read -p
"${TXT[prompt_vm]}" vm_num; [[ "$vm_num" == "s" ]] &&
continue
idx=$((vm_num-1))
if [[
"$vm_num" =~ ^[0-9]+$ ]] && [ "$idx" -ge 0 ] &&
[ "$idx" -lt "${#VM_UUIDS[@]}" ]; then
SEL_UUID="${VM_UUIDS[$idx]}"; SEL_NAME="${VM_NAMES[$idx]}"
case $action in
1) VBoxManage startvm "$SEL_UUID" --type headless ;;
2) read -p "${TXT[confirm]} 'PAUSE': " c; [[ "$c" == "PAUSE" ]]
&& VBoxManage controlvm "$SEL_UUID" savestate ;;
3) read -p "${TXT[confirm]} 'ACPI': " c; [[ "$c" == "ACPI" ]]
&& VBoxManage controlvm "$SEL_UUID" acpipowerbutton ;;
4) draw_header "$cur_mode_text: $SEL_NAME" "true"
echo "1) Take 2) List 3) Restore
${TXT[back]}"; read -p "Wahl: " snc
case $snc in 1) read -p "Name: " sn; VBoxManage snapshot
"$SEL_UUID" take "$sn" || handle_error "$VM_BASE_PATH" ;; 2)
VBoxManage snapshot "$SEL_UUID" list ;; 3) read -p "Snapshot
Name: " sn; VBoxManage snapshot "$SEL_UUID" restore "$sn" ;;
esac ;;
5) draw_header "$cur_mode_text: $SEL_NAME" "true"
echo -e "\033[1;34m[ SYSTEM ]\033[0m"
VBoxManage showvminfo "$SEL_UUID" | grep -E "^Name:|^Guest
OS:|^UUID:|^Config file:|^Memory size|^Number of CPUs"
lock_info=$(VBoxManage showvminfo "$SEL_UUID" | grep "Session
Lock")
if [[ -n "$lock_info" ]]; then
echo -e "Session Lock: \033[1;31m${lock_info#*:}\033[0m"
if ! VBoxManage list runningvms | grep -q "$SEL_UUID"; then
echo -e "\033[1;33mWARNUNG: VM ist OFFLINE aber GESPERRT
(Zombie?).\033[0m"
echo -e "Prüfe laufende Prozesse: pgrep -af $SEL_NAME"
fi
fi
echo -e "\n\033[1;34m[ NETWORK ]\033[0m"
VBoxManage showvminfo "$SEL_UUID" | grep -E "^NIC" | grep -v
"disabled"
echo -e "\n\033[1;34m[ ${TXT[det_storage]} ]\033[0m"
VBoxManage showvminfo "$SEL_UUID" | grep -iE
"Controller|SATA|IDE" | grep -v "Port Count"
VBoxManage showvminfo "$SEL_UUID" | grep -iE
"(.iso|.vdi|emptydrive)" | sed 's/^/ /'
;;
6) read -p "${TXT[confirm]} 'STOP': " c; [[ "$c" == "STOP" ]]
&& VBoxManage controlvm "$SEL_UUID" poweroff ;;
8) read -p "${TXT[confirm]} 'DELETE': " c; [[ "$c" == "DELETE"
]] && {
if VBoxManage list runningvms | grep -q "$SEL_UUID"; then
echo -e "\033[1;31mFEHLER: VM läuft noch! Erst
ausschalten.\033[0m"
else
VBoxManage unregistervm "$SEL_UUID" --delete
fi
} ;;
9) read -p "${TXT[confirm]} 'EDIT': " c; [[ "$c" == "EDIT" ]]
&& {
draw_header "$cur_mode_text: $SEL_NAME" "true"
echo "1) CPU 2) RAM 3) ISO Mount 4) ISO
Unmount ${TXT[back]}"; read -p "Wahl: " edc
case $edc in
1) read -p "CPUs: " v; VBoxManage modifyvm "$SEL_UUID" --cpus
"$v" ;;
2) read -p "RAM (MB): " v; VBoxManage modifyvm "$SEL_UUID"
--memory "$v" ;;
3) select_iso && VBoxManage storageattach "$SEL_UUID"
--storagectl "IDE" --port 0 --device 0 --type dvddrive --medium
"$SELECTED_ISO" ;;
4) VBoxManage storageattach "$SEL_UUID" --storagectl "IDE"
--port 0 --device 0 --type dvddrive --medium emptydrive ;;
esac
} ;;
esac
read -p "${TXT[done]}" d
fi
fi
if [[ "$action" == "7" ]]; then
draw_header
"${TXT[menu7]}" "true"
read -p
"${TXT[v_name]} (${TXT[back]}): " n; [[ -z "$n" || "$n" == "s"
]] && continue
read -p
"${TXT[v_ram]} [1024]: " r; r=${r:-1024}; read -p "${TXT[v_hdd]}
[10240]: " h; h=${h:-10240}
select_iso
&& iso="$SELECTED_ISO" || iso="emptydrive"
VBoxManage
createvm --name "$n" --basefolder "$VM_BASE_PATH" --register ||
{ handle_error "$VM_BASE_PATH"; continue; }
VBoxManage
modifyvm "$n" --memory "$r" --nic1 bridged --bridgeadapter1 eth0
VBoxManage
storagectl "$n" --name "SATA" --add sata
VBoxManage
createmedium disk --filename "$VM_BASE_PATH/$n/$n.vdi" --size
"$h"
VBoxManage
storageattach "$n" --storagectl "SATA" --port 0 --device 0
--type hdd --medium "$VM_BASE_PATH/$n/$n.vdi"
VBoxManage
storagectl "$n" --name "IDE" --add ide
VBoxManage
storageattach "$n" --storagectl "IDE" --port 0 --device 0 --type
dvddrive --medium "$iso"
read -p
"${TXT[done]}" d
fi
[[ "$action" == "10" ]] && {
draw_header "${TXT[menu10]}" "true"; ls -1 "$ISO_PATH"/*.iso
2>/dev/null | xargs -n1 basename; read -p "${TXT[done]}" d; }
done
echo -e "\033[0m"
exit 0
#hier ist schluss
chmod 750 vbox_control.sh
exit
sudo su - vbox.hostname.domain.tld
htpasswd -c /home/vbox.hostname.domain.tld/.htpasswd
$BENUTZER
chown vbox.hostname.domain.tld:vbox.hostname.domain.tld
/home/vbox.hostname.domain.tld/.htpasswd
chmod 640 /home/vbox.hostname.domain.tld/.htpasswd
nano
/home/vbox.hostname.domain.tld/public_html/.htaccess
AuthType Basic
AuthName "VirtualBox Webzugriff"
AuthUserFile /home/vbox.hostname.domain.tld/.htpasswd
Require valid-user
# Optional: Zugriff auf die .htaccess selbst verbieten
<Files ".htaccess">
Require all denied
</Files>
chown vbox.hostname.domain.tld:vbox.hostname.domain.tld
/home/vbox.hostname.domain.tld/public_html/.htaccess
#Backup vom 2. PC auf den Server einrichten:
ssh von home@domain.tld nach hostname.domain.tld
einrichten
@home als $BENUTZER
cd && mkdir .ssh && chmod 700 .ssh/
&& cd .ssh
ssh-keygen -o -a 100 -t ed25519
cat id_ed25519.pub
ssh-ed25519 *******************************
$BENUTZER@server.lan
@hostname.domain.tld als $BENUTZER
cd
.ssh
nano authorized_keys
ssh-ed25519 ******************************
$BENUTZER@server.lan
rsync -avP /pfad/zur/datei
$BENUTZER@hostname.domain.tld:/ziel/pfad/
#Syncthing installieren und einrichten
Syncthing_installieren_und_config
sudo adduser syncthing
sudo mkdir /data/syncthing
sudo mkdir /home/syncthing/bin
sudo chown syncthing:syncthing /home/syncthing -R
sudo su - syncthing
cd
wget
https://github.com/syncthing/syncthing/releases/download/v2.0.12/syncthing-linux-amd64-v2.0.12.tar.gz
nach bin entpacken
exit
#Start per systemd
sudo nano /etc/systemd/system/syncthing.service
[Unit]
Description=Syncthing
After=network.target
StartLimitIntervalSec=60
StartLimitBurst=4
[Service]
User=syncthing
ExecStart=/home/syncthing/bin/syncthing serve
--gui-address=127.0.0.1:8384 --home=/data/syncthing --no-browser
--no-restart --logfile=/var/log/syncthing.log
Restart=on-failure
RestartSec=1
SuccessExitStatus=3 4
RestartForceExitStatus=3 4
ProtectSystem=full
PrivateTmp=true
SystemCallArchitectures=native
MemoryDenyWriteExecute=true
NoNewPrivileges=true
[Install]
WantedBy=multi-user.target
sudo chown root:root
/etc/systemd/system/syncthing.service
sudo chmod 660 /etc/systemd/system/syncthing.service
sudo systemctl enable syncthing
sudo systemctl start syncthing
sudo systemctl status syncthing
Virtualmin
syncthing.hostname.domain.tld erstellen
HTTP/HTTPS -> 127.0.0.1:8384
Virtualmin -> Virtualmin ->
syncthing.hostname.domain.tld -> Web Configuration -> Edit
Proxy Website ->
Proxying enabled -> yes
Proxy to URL -> http://127.0.0.1:8384/
sudo touch /var/log/syncthing.log
sudo chown syncthing:syncthing /var/log/syncthing.log
sudo chmod 660 /var/log/syncthing.log
sudo cat /var/log/syncthing.log
sudo systemctl restart syncthing
sudo cat /var/log/syncthing.log
Syncthing logrotate
sudo nano /etc/logrotate.d/syncthing
/var/log/syncthing.log {
weekly
rotate 4
compress
missingok
notifempty
copytruncate
create 640 syncthing syncthing
}
sudo chown root:root /etc/logrotate.d/syncthing
sudo chmod 0644 /etc/logrotate.d/syncthing
sudo logrotate -d /etc/logrotate.d/syncthing
PHP Update auf 8.4
dpkg -l | grep php | tee php_packages_alt.txt
sudo apt-get update
sudo apt-get -y install lsb-release ca-certificates curl
apt-transport-https
sudo curl -sSLo /tmp/debsuryorg-archive-keyring.deb
https://packages.sury.org/debsuryorg-archive-keyring.deb
sudo dpkg -i /tmp/debsuryorg-archive-keyring.deb
sudo sh -c 'echo "deb
[signed-by=/usr/share/keyrings/deb.sury.org-php.gpg]
https://packages.sury.org/php/ $(lsb_release -sc) main" >
/etc/apt/sources.list.d/php.list'
sudo apt-get update
sudo apt install php8.4-cli
php -v
sudo systemctl status php8.4-fpm
sudo apt install php8.4-common
php8.4-{bcmath,bz2,curl,gd,gmp,intl,mbstring,opcache,readline,xml,zip}
sudo apt-get install \
php-cgi \
php-cli \
php-common \
php-curl \
php-fpm \
php-gd \
php-mbstring \
php-mysql \
php-pear \
php-xml \
php8.4-cgi \
php8.4-cli \
php8.4-common \
php8.4-curl \
php8.4-fpm \
php8.4-gd \
php8.4-mbstring \
php8.4-mysql \
php8.4-opcache \
php8.4-readline \
php8.4-soap \
php8.4-xml
sudo apt-get update
sudo apt-get upgrade
sudo apt-get dist-upgrade
sudo a2enconf php8.4-fpm
#MariaDB Update
sudo apt-get install apt-transport-https curl
sudo mkdir -p /etc/apt/keyrings
sudo curl -o /etc/apt/keyrings/mariadb-keyring.pgp
'https://mariadb.org/mariadb_release_signing_key.pgp'
sudo nano /etc/apt/sources.list
#MariaDB
deb [signed-by=/etc/apt/keyrings/mariadb-keyring.pgp]
https://deb.mariadb.org/12.1/debian bookworm main
sudo apt-get update
sudo apt-get upgrade
sudo apt-get dist-upgrade
sudo apt-get autoremove
sudo apt-get install \
liblzo2-2 libsnappy1v5 \
mariadb-plugin-provider-bzip2 \
mariadb-plugin-provider-lz4 \
mariadb-plugin-provider-lzma \
mariadb-plugin-provider-lzo \
mariadb-plugin-provider-snappy
sudo mariadb-secure-installation
#rsyncd einrichten
sudo apt-get update && sudo apt-get install
rsync
whereis rsync | grep bin -> /usr/bin/rsync
sudo mkdir /etc/rsyncd/
sudo nano /etc/rsyncd/rsyncd.conf
use chroot = true
transfer logging = true
log file = /var/log/rsyncd.log
[ext500]
comment = ext500
path = /data/rsync/ext500
read only = no
list = no
uid = $BENUTZER
gid = $BENUTZER
sudo chown root:root /etc/rsyncd/rsyncd.conf
sudo chmod 660 /etc/rsyncd/rsyncd.conf
sudo mkdir /data/rsync
sudo mkdir /data/rsync/ext500
per SystemD starten
sudo nano /etc/systemd/system/rsyncd.service
[Unit]
Description=rsyncd
After=network.target
[Service]
ExecStart=/usr/bin/rsync
--config=/etc/rsyncd/rsyncd.conf --daemon --no-detach
--address=127.0.0.1
[Install]
WantedBy=multi-user.target
sudo chown root:root /etc/systemd/system/rsyncd.service
sudo chmod 664 /etc/systemd/system/rsyncd.service
sudo touch /var/log/rsyncd.log
sudo systemctl daemon-reload
sudo systemctl enable rsyncd
sudo systemctl start rsyncd
sudo systemctl status rsyncd
sudo nano /etc/logrotate.d/rsyncd
/var/log/rsyncd.log {
weekly
rotate 4
compress
missingok
notifempty
copytruncate
create 640 root root
}
sudo chown root:root /etc/logrotate.d/rsyncd
sudo chmod 0644 /etc/logrotate.d/rsyncd
sudo logrotate -d /etc/logrotate.d/rsyncd
sudo chown $BENUTZER:$BENUTZER /data/rsync/ext500
-------
sudo rm /etc/logrotate.d/rsyncd
sudo rm /var/log/rsyncd.log
sudo systemctl stop rsyncd
sudo systemctl disable rsyncd
systemctl show -p FragmentPath rsyncd
sudo rm /etc/systemd/system/rsyncd.service
sudo rm /etc/rsyncd/rsyncd.conf
#EMail DKIM einrichten
DKIM
Virtualmin -> EMail Settings -> DomainKeys
Indentified Mail
Key erstellen
DKIM DNS records for domains
202600._domainkey IN TXT ( "v=DKIM1; k=rsa; t=s; p=*" )
Cloudflare Edit DNS
Add Record
Type - TXT
Name - 202600._domainkey
Content - "v=DKIM1; k=rsa; t=s; p=*"
DMARC:
v=DMARC1; p=reject; rua=mailto:rua@hostname.domain.tld;
ruf=mailto:ruf@hostname.domain.tld; adkim=s; aspf=s
Benutzer in Virtualmin unter hostname.domain.tld anlegen
rua@hostname.domain.tld und ruf@hostname.domain.tld
MX eintrag in Cloudflare für hostname.domain.tld anlegen
SPF eintrag in Cloudflare für hostname.domain.tld
anlegen
DKIM eintrag in Cloudflare für hostname.domain.tld
anlegen
DMARC eintrag in Cloudflare für hostname.domain.tld
anlegen
txt
202600._domainkey.server
"v=DKIM1; k=rsa; t=s; p=*"