Server-Härtung & Betrieb (Max-Security): Debian 12 + YunoHost + Nextcloud + WordPress + Mail
Ziel: Dieser Leitfaden dokumentiert die vollständige Härtung und den professionellen Betrieb ab Beginn der Härtungsphase (inkl. Monitoring, Architektur, Backup und Max-Security).
Alle Maßnahmen sind für ein produktives VPS-Setup optimiert und bewusst ressourcenschonend gehalten.
Projektüberblick
Was wurde stabilisiert
I/O-Spitzen durch lokale WordPress-Backups beseitigt, Swap aktiviert, Repos konsolidiert, Redis + DB-Tuning, Rate-Limits, Kernel-Hardening, Alarmierung.
I/O-Spitzen durch lokale WordPress-Backups beseitigt, Swap aktiviert, Repos konsolidiert, Redis + DB-Tuning, Rate-Limits, Kernel-Hardening, Alarmierung.
Was dieses Runbook liefert
Schritt-für-Schritt Hardening, wiederholbare Checks, Rollback, Wartungsplan, Restore-Plan und eine saubere Ziel-Architektur inkl. Migrationspfad.
Schritt-für-Schritt Hardening, wiederholbare Checks, Rollback, Wartungsplan, Restore-Plan und eine saubere Ziel-Architektur inkl. Migrationspfad.
1. Scope, Annahmen, Grundregeln
- System: Debian 12 (Bookworm), YunoHost 12.x, nginx, php-fpm (8.3), MariaDB, Redis, Fail2Ban
- Apps: Nextcloud (Hub), WordPress, Mail-Stack (Postfix/Dovecot)
- Prämisse: Stabilität auf 2-GB-VPS (keine „Heavy-Suites“, kein Overkill, aber maximale Härtung mit vertretbarem Risiko)
- Grundregel: Änderungen immer mit
nginx -t/php-fpm -tprüfen, dann erst reload/restart.
Hinweis (YunoHost-Kompatibilität): Nginx/SSOwat/Nextcloud-Header und CSP nur YunoHost-konform anpassen. Zu aggressive CSP kann Nextcloud-Apps brechen.
2. Baseline-Checks (vor jeder Änderung)
Diese Checks geben dir in 60 Sekunden Klarheit, ob das System gesund ist.
uptime free -h df -h sudo ss -tulpen | egrep ':22|:80|:443|:25|:587|:993|:53' || true sudo systemctl status nginx --no-pager sudo systemctl status php8.3-fpm --no-pager sudo systemctl status mariadb --no-pager sudo systemctl status redis-server --no-pager sudo fail2ban-client status
3. Beginn der Härtungsphase (Kontext & Auslöser)
Auslöser: Instabilität/Timeouts (Nextcloud/YunoHost), „Zu viele Anfragen“, sporadische Verbindungsabbrüche. Haupttreiber: lokale WordPress-Backups (BackWPup) erzeugten I/O- und CPU-Spitzen, bei 2 GB RAM ohne Swap.
- Disk-Analyse zeigte große Backup-Archive in
/var/www/wordpress/wp-content/uploads/backwpup. - Swap wurde eingeführt, um Lastspitzen abzufedern.
- APT-Repo-Mix (Sury/Yarn) wurde bereinigt, um Paketkonflikte zu verhindern.
4. Speicher & I/O stabilisieren (Root-FS, WordPress Backups)
4.1 Schnellanalyse: Wo liegt das Volumen?
sudo du -h --max-depth=1 /var | sort -hr sudo du -h --max-depth=1 /var/www | sort -hr sudo du -h --max-depth=2 /var/www/wordpress/wp-content/uploads | sort -hr | head -20
4.2 Maßnahme: lokale WP-Backups vermeiden
- Ziel: Keine Multi-GB ZIP-Backups lokal auf dem VPS behalten.
- Empfehlung: BackWPup so konfigurieren, dass Backups offsite (S3/FTP/Storage) gehen und lokal nur 0–2 Rotationen verbleiben.
Regel: Auf 2 GB RAM niemals „tägliches Vollbackup lokal als ZIP“ dauerhaft laufen lassen. Das erzeugt exakt die beobachteten Timeouts/Abbrüche.
5. Swap aktivieren (Stabilität bei Lastspitzen)
Status: Swapfile 2 GB ist aktiv. Leichte Swap-Nutzung ist normal und erhöht Stabilität.
sudo swapon --show free -h ls -lh /swapfile grep -n swapfile /etc/fstab || true
5.1 (Optional) Swappiness konservativ setzen
echo "vm.swappiness=20" | sudo tee -a /etc/sysctl.conf sudo sysctl -p | tail -n 20
6. APT/Repository-Härtung (Stabilität statt Paketmix)
Ziel: Repos so minimal wie möglich halten. Jede zusätzliche Quelle erhöht das Risiko von Dependency-Brüchen.
6.1 Sury/Yarn entfernt bzw. deaktiviert
- Sury-Repo: deaktiviert (404-Fehler, Versionsmix).
- Yarn-Repo: entfernt (NO_PUBKEY). Nicht notwendig für Betrieb.
grep -R "sury" -n /etc/apt/sources.list /etc/apt/sources.list.d/* || true ls -1 /etc/apt/sources.list.d sudo apt update sudo apt -f install -y sudo apt autoremove --purge -y sudo apt autoclean
7. Redis (Cache + Locking) – Nextcloud stabilisieren
Status: Redis läuft stabil (localhost), PHP-Modul geladen, Verbindung ok (
redis-cli ping → PONG).
7.1 Verifikation
php -m | grep -i redis redis-cli ping sudo systemctl status redis-server --no-pager
7.2 Nextcloud auf Redis setzen (TCP localhost)
sudo yunohost app shell nextcloud php occ config:system:set redis host --value="127.0.0.1" php occ config:system:set redis port --value=6379 --type=integer php occ config:system:set memcache.locking --value="\OC\Memcache\Redis" php occ config:system:set memcache.distributed --value="\OC\Memcache\Redis" php occ config:system:get redis php occ config:system:get memcache.locking exit
8. MariaDB – Performance & I/O reduzieren
Status:
innodb_buffer_pool_size = 768M (805306368 Bytes) gesetzt – optimal für 2 GB RAM.
8.1 Verifikation
sudo mysql -e "SHOW VARIABLES LIKE 'innodb_buffer_pool_size';" sudo mysql -e "SHOW VARIABLES LIKE 'max_connections';" sudo systemctl status mariadb --no-pager
8.2 Empfohlene MariaDB-Parameter (2 GB RAM)
In /etc/mysql/mariadb.conf.d/50-server.cnf unter [mysqld] (nur, wenn nicht bereits gesetzt):
# /etc/mysql/mariadb.conf.d/50-server.cnf (unter [mysqld]) innodb_buffer_pool_size = 768M innodb_log_file_size = 256M innodb_flush_method = O_DIRECT innodb_flush_log_at_trx_commit = 2 max_connections = 60 tmp_table_size = 64M max_heap_table_size = 64M
sudo systemctl restart mariadb sudo mysql -e "SHOW VARIABLES LIKE 'innodb_buffer_pool_size';"
9. PHP-FPM – Prozesslimits für 2 GB RAM
Ziel: Verhindern, dass PHP-FPM durch zu viele Worker RAM frisst und das System in Swap- oder Timeout-Szenarien läuft.
9.1 Konfigurationspfad
- Aktiv:
php8.3-fpm - Pool:
/etc/php/8.3/fpm/pool.d/www.conf
9.2 Empfohlene Werte
# /etc/php/8.3/fpm/pool.d/www.conf pm = dynamic pm.max_children = 18 pm.start_servers = 4 pm.min_spare_servers = 2 pm.max_spare_servers = 6 pm.max_requests = 500
sudo php-fpm8.3 -t sudo systemctl restart php8.3-fpm sudo systemctl status php8.3-fpm --no-pager
10. Fail2Ban – Bruteforce & App-Schutz
Status: 11 Jails aktiv (u.a. nextcloud, wordpress, sshd, yunohost-portal). Das ist ein sehr guter Schutzgrad.
sudo fail2ban-client status sudo fail2ban-client status sshd sudo fail2ban-client status nextcloud sudo fail2ban-client status wordpress
10.1 Default-Härtung (konservativ, produktionssicher)
# /etc/fail2ban/jail.local [DEFAULT] bantime = 24h findtime = 10m maxretry = 3
sudo systemctl restart fail2ban sudo fail2ban-client status
11. Nginx – Rate Limiting (DoS/Bot-Schutz) & Best Practices
11.1 Global Zone in nginx.conf (http{} Block)
# /etc/nginx/nginx.conf (innerhalb http { ... })
limit_req_zone $binary_remote_addr zone=global_limit:10m rate=10r/s;11.2 Anwendung im HTTPS server{} Block (443)
# innerhalb server { listen 443 ssl http2; ... } für mitcloud.mayit.eu
limit_req zone=global_limit burst=20 nodelay;sudo nginx -t sudo systemctl reload nginx
Wichtig: Zu strikte Limits können echte Nutzer (z.B. WebDAV Sync) beeinträchtigen. Bei Problemen:
rate erhöhen oder burst anpassen.
12. Kernel Hardening (sysctl)
Empfohlene Baseline (produktionssicher). Block ans Ende von /etc/sysctl.conf:
# IP Spoofing Protection net.ipv4.conf.all.rp_filter=1 net.ipv4.conf.default.rp_filter=1 # Disable IP forwarding net.ipv4.ip_forward=0 # SYN Flood Protection net.ipv4.tcp_syncookies=1 # Disable source routing net.ipv4.conf.all.accept_source_route=0 net.ipv6.conf.all.accept_source_route=0 # Ignore ICMP broadcast net.ipv4.icmp_echo_ignore_broadcasts=1 # Log suspicious packets net.ipv4.conf.all.log_martians=1
sudo sysctl -p sudo sysctl net.ipv4.ip_forward sudo sysctl net.ipv4.tcp_syncookies
13. Monitoring mit E-Mail Alarmierung
Status: Testmail erfolgreich. Monitoring läuft leichtgewichtig über ein Health-Check Script + Cron (alle 5 Minuten).
13.1 Mailutils (falls erforderlich)
sudo apt install -y mailutils echo "Testmail Monitoring OK" | mail -s "Server Test" DEINE-MAIL@DOMAIN.DE
13.2 Health-Check Script
sudo nano /usr/local/sbin/server-health-check.sh
#!/bin/bash
MAIL="DEINE-MAIL@DOMAIN.DE"
HOSTNAME=$(hostname)
# RAM Check
RAM_USED=$(free | awk '/Mem:/ {printf("%.0f"), $3/$2*100}')
if [ "$RAM_USED" -gt 85 ]; then
echo "RAM usage is ${RAM_USED}% on ${HOSTNAME}" | mail -s "ALERT: High RAM on ${HOSTNAME}" "$MAIL"
fi
# Disk Check
DISK_USED=$(df / | awk 'END{print $5}' | sed 's/%//')
if [ "$DISK_USED" -gt 85 ]; then
echo "Disk usage is ${DISK_USED}% on ${HOSTNAME}" | mail -s "ALERT: High Disk on ${HOSTNAME}" "$MAIL"
fi
# Load Check
LOAD=$(uptime | awk -F'load average:' '{ print $2 }' | cut -d, -f1 | tr -d ' ')
LOAD_INT=${LOAD%.*}
if [ "$LOAD_INT" -gt 2 ]; then
echo "Load average is ${LOAD} on ${HOSTNAME}" | mail -s "ALERT: High Load on ${HOSTNAME}" "$MAIL"
fi
# Service Check
for SERVICE in nginx php8.3-fpm mariadb redis-server
do
if ! systemctl is-active --quiet "$SERVICE"; then
echo "Service $SERVICE is NOT running on ${HOSTNAME}" | mail -s "ALERT: Service down on ${HOSTNAME}" "$MAIL"
fi
donesudo chmod +x /usr/local/sbin/server-health-check.sh sudo /usr/local/sbin/server-health-check.sh
13.3 Cron (alle 5 Minuten)
sudo crontab -e # hinzufügen: */5 * * * * /usr/local/sbin/server-health-check.sh
13.4 (Optional) Täglicher Statusreport
Empfehlung: ein kompakter Tagesreport (z.B. 08:00). Vorteil: du bemerkst Trends früh.
# /usr/local/sbin/server-daily-report.sh (Beispiel – optional)
# Sammle: uptime, df -h, free -h, fail2ban status, top 5 processes by mem/cpu, last 100 auth.log lines
# Versand per mail -s "Daily Report ${HOSTNAME}" "$MAIL"14. Backup-Konzept (professionell) + Restore-Plan
Prinzip: Backups sind nur so gut wie der getestete Restore. Mindestens 1× pro Quartal Restore-Test durchführen und dokumentieren.
14.1 Backup-Ziele (Empfehlung)
| Komponente | Was sichern? | Ziel | Rotation |
|---|---|---|---|
| YunoHost | Konfiguration + Apps + Daten (YunoHost Backup) | Offsite Storage (S3/FTP/Remote) | täglich inkrementell / wöchentlich voll |
| Nextcloud | Data Dir + DB Dump + config.php + custom apps | Offsite + ggf. Snapshot | täglich |
| WordPress | DB + wp-content | Offsite (keine ZIP lokal) | täglich/2-täglich |
| Maildirs + DB/Configs (je nach Setup) | Offsite | täglich |
14.2 YunoHost Backup (Standardweg)
sudo yunohost backup create --system --apps nextcloud,wordpress --name "daily-$(date +%F)" sudo yunohost backup list # Speicherorte prüfen (je nach YunoHost-Konfiguration): /home/yunohost.backup/ oder konfiguriertes Storage
14.3 Nextcloud konsistent sichern (App Maintenance Mode)
Strategie: Für konsistente Backups: Maintenance Mode + DB Dump + Files sichern. Bei großen Instanzen alternativ Snapshots mit kurzer Downtime.
sudo yunohost app shell nextcloud php occ maintenance:mode --on # DB Dump (lokal – danach offsite kopieren) mysqldump --single-transaction -h localhost -u nextcloud -p"$(php -r 'include(\"/var/www/nextcloud/config/config.php\"); echo $CONFIG[\"dbpassword\"];')" nextcloud \ > /home/yunohost.app/nextcloud/data/backup-nextcloud-db-$(date +%F).sql php occ maintenance:mode --off exit
Wichtig: DB-Passwort via config.php ist sensitiv. Sorge für sichere Dateirechte und offsite Transfer via verschlüsseltem Kanal.
14.4 Restore-Plan (Kurzform)
- RTO/RPO definieren: z.B. RTO 4h, RPO 24h (je nach Anspruch)
- Restore-Test: 1×/Quartal auf Test-VPS oder Snapshot
- Reihenfolge: System → DB → App → Daten → Checks
# 1) System-Stand prüfen (Debian/YunoHost Version) # 2) YunoHost Backup restore (system + apps) # 3) Nextcloud: maintenance:mode on → DB import → files restore → files:scan → maintenance off # 4) WordPress: DB import + wp-content restore # 5) Smoke Tests: HTTP(S), login, webdav, cron, mail flow
15. Architektur-Upgrade-Plan (Roadmap)
Ist-Architektur: Alles auf einem 2-GB-VPS. Vorteil: einfach. Risiko: Resource-Contention (Backups, Updates, Peaks).
15.1 Ziel-Architektur (empfohlen)
| Variante | Beschreibung | Vorteile | Risiken/Notes |
|---|---|---|---|
| A (Minimal) | VPS auf 4 GB RAM upgraden | Einfachster Stabilitätsgewinn | Kosten ↑, aber geringes Risiko |
| B (Empfohlen) | WordPress auslagern (eigener VPS/Managed) | Nextcloud erhält Ressourcen, weniger I/O-Spitzen | DNS/SSL/Backup getrennt |
| C (Professionell) | Mail separieren (oder managed), NC + WP getrennt | Security-Isolation, bessere Wartbarkeit | Komplexität ↑, aber best practice |
15.2 Migrationspfad (Kurz)
- WordPress Move: DNS TTL senken → Backup → Restore auf Ziel → Test → DNS Switch → Monitoring
- Nextcloud bleibt: Redis/DB/Swap/Rate-Limits bleiben wie dokumentiert.
- Mail: nur migrieren, wenn klare Notwendigkeit und saubere Restore-Tests möglich sind.
16. Max-Security Checkliste
| Bereich | Maßnahme | Status | Verifikation |
|---|---|---|---|
| SSH | Key-only, Root-Login aus, max tries reduziert | OK | sshd_config + Login-Test |
| Fail2Ban | sshd, nextcloud, wordpress, portal + recidive | OK | fail2ban-client status |
| Nginx | Rate limiting aktiv | OK | nginx -T | grep limit_req |
| Kernel | sysctl baseline hardening | OK | sysctl … |
| PHP-FPM | max_children begrenzt + max_requests | OK | php-fpm8.3 -t + Prozesszählung |
| DB | Buffer Pool 768M + flush optimiert | OK | SHOW VARIABLES |
| Redis | Cache + Locking (localhost) | OK | redis-cli ping |
| Repos | Keine unsicheren/kaputten Repos | OK | apt update |
| Monitoring | Healthcheck + Mail Alerts | OK | Testmail + Cron |
17. Betriebsprozesse (Wartung, Updates, Notfall)
17.1 Regelmäßige Wartung (monatlich)
sudo apt update sudo apt upgrade -y sudo apt autoremove --purge -y sudo yunohost diagnosis run sudo fail2ban-client status sudo journalctl -p 3 -xb --no-pager | tail -n 200
17.2 Nextcloud Wartung (monatlich/quartalsweise)
sudo yunohost app shell nextcloud php occ status php occ db:add-missing-indices php occ maintenance:repair exit
17.3 Incident Quick Response
# 1) Ressourcen uptime free -h df -h sudo iotop -oPa # falls installiert # 2) Web/DB/PHP sudo systemctl status nginx php8.3-fpm mariadb redis-server --no-pager # 3) Logs (kurz) sudo tail -n 200 /var/log/nginx/error.log sudo journalctl -u php8.3-fpm --since "30 min ago" --no-pager | tail -n 200 sudo journalctl -u mariadb --since "30 min ago" --no-pager | tail -n 200 # 4) Fail2Ban / Bruteforce sudo fail2ban-client status nextcloud sudo fail2ban-client status sshd
18. Rollback-Strategie
- Nginx: Änderungen rückgängig →
nginx -t→ reload - PHP-FPM:
www.confzurück →php-fpm8.3 -t→ restart - DB: Parameter zurück → restart → Buffer Pool ggf. reduzieren
- sysctl: Werte entfernen →
sysctl -p - Nextcloud: config.php Einträge (Redis) zurücksetzen, falls nötig
19. Appendix – Nützliche Befehle
# Welche Dienste laufen? sudo systemctl list-units --type=service --state=running # Welche PHP-FPM Units existieren? sudo systemctl list-units | grep fpm # Nginx Konfiguration komplett anzeigen (vorsichtig, sehr lang) sudo nginx -T | head -n 120 # Nextcloud config Werte prüfen sudo yunohost app shell nextcloud php occ config:system:get trusted_domains php occ config:system:get overwrite.cli.url exit
Dokument-Standard: Dark/YunoHost-Style V2 (TOC fixiert, Copy-Buttons inkl. Fallback, Print-CSS).
Autor: MayIT
Hinweis: Bei jeder größeren Änderung: Backup + kurzer Smoke-Test (Login, WebDAV, Admin-Panel, Mailflow).
Autor: MayIT – Projektdokumentation Debian 12 YunoHost Härtung, Monitoring, Backup & MaxSecurity
