Markus Michalski FAQ

Server Tools: Technische Details

Technische Details zu Server Tools: Schichten und Module, Programmablauf, Webserver-Dispatch, erzeugte Apache- und Nginx-Konfigurationen, Logrotate, Versionserkennung, Fehlerbehandlung, Tests und CI.

English Version

Zurück zur Übersicht


Technische Details

Aufbau

Server Tools besteht aus einem Einstiegsscript und Libraries nach dem Muster "Building Blocks": Kleine Funktionen erledigen je eine Aufgabe, übergeordnete Funktionen setzen sie zu Abläufen mit Validierung, Rückfrage, Rollback und Audit-Log zusammen.

graph TD
    A["bin/server-tools"] --> B["core.sh, config.sh, security.sh"]
    A --> C["backup.sh, install.sh"]
    A --> D["database.sh, vhost.sh, ssl.sh, cron.sh, firewall.sh, fail2ban.sh, log.sh, status.sh, user.sh"]
    A --> E["cli.sh, menu.sh"]
    D --> F["_ws_dispatch"]
    F --> G["webserver/apache.sh"]
    F --> H["webserver/nginx.sh"]
Datei Aufgabe
bin/server-tools Einstieg: Library-Pfad bestimmen, Flags auswerten, Befehl verteilen
lib/core.sh Logging, die, confirm, Abhängigkeitsprüfung, Versionsbestimmung
lib/config.sh Standardwerte, Config laden und prüfen, --config-Ausgabe
lib/security.sh Eingabevalidierung, Escaping, Audit-Log, Passwort-Erzeugung, sicheres Schreiben
lib/backup.sh Backups vor dem Löschen, Backup-Übersicht
lib/install.sh install und uninstall
lib/database.sh MySQL-Operationen
lib/vhost.sh VHost-Abläufe, Logrotate, Audit
lib/webserver/apache.sh, nginx.sh Konfigurationserzeugung und Site-Mechanik je Webserver
lib/ssl.sh, cron.sh, firewall.sh, fail2ban.sh, log.sh, status.sh, user.sh Fachmodule
lib/cli.sh Argument-Verarbeitung und Verteilung der CLI-Befehle
lib/menu.sh Interaktives Menü
conf/server-tools.conf.example Config-Vorlage

Jede Library beginnt mit einem Guard (_<NAME>_SOURCED), der doppeltes Laden verhindert.

Programmablauf

  1. bin/server-tools setzt set -euo pipefail.
  2. Es sucht die Libraries in ../lib relativ zur Binary, danach in /usr/local/lib/server-tools.
  3. Es lädt alle Libraries in fester Reihenfolge: core, config, security, backup, database, vhost, ssl, cron, status, log, firewall, fail2ban, user, install, cli, menu.
  4. Die globalen Flags --yes und --quiet werden aus der Argumentliste entfernt. --yes setzt ST_AUTO_CONFIRM=true.
  5. Der erste Parameter wählt den Befehl. Die meisten Zweige führen nacheinander check_root, load_config, check_dependencies und die CLI-Funktion aus.
  6. Ohne Argument startet das Menü.

Die Version bestimmt core.sh aus der Datei .version neben den Libraries, sonst per git describe --tags --always im Verzeichnis der Libraries, sonst dev.

Fehlerbehandlung

Das Entry-Script läuft mit set -e. Eine Funktion, die mit Status 1 endet, beendet damit den ganzen Aufruf mit Exit-Code 1. Das Menü fängt das ab: Jede Aktion läuft dort mit || true, ein Fehler führt zurück ins Menü.

Meldungen schreiben log_info, log_warn und log_error auf stderr. die schreibt eine Fehlermeldung und beendet mit 1.

Webserver-Dispatch

vhost.sh ruft webserver-abhängige Funktionen über _ws_dispatch <name> <argumente> auf. Je nach ST_WEBSERVER wird daraus apache_<name> oder nginx_<name>:

Name Aufgabe
vhost_config_path Pfad der Konfigurationsdatei
vhost_exists, vhost_enabled Existenz, Aktivierung
generate_vhost_config, generate_proxy_config, generate_redirect_config Konfiguration erzeugen
generate_www_redirect_snippet, generate_https_redirect_snippet Weiterleitungs-Blöcke
get_vhost_docroot, get_vhost_php_version, get_vhost_type, get_vhost_backend, websocket_enabled Werte aus einer Konfiguration lesen
change_php_version_in_config Socket-Pfad ersetzen
enable_site, disable_site, reload Aktivieren, Deaktivieren, Test und Reload
enable_modules_php, enable_modules_proxy, rewrite_module_ensure Apache-Module, bei Nginx ohne Wirkung

Typ, DocumentRoot, PHP-Version und Backend eines VHosts liest das Tool aus der Konfigurationsdatei, es gibt keine eigene Datenbank.

Erzeugte Konfigurationen

Die Beispiele zeigen die Vorlagen mit example.com, einem Alias und PHP 8.3.

Apache, PHP-VHost

<VirtualHost *:80>
    ServerName example.com
    ServerAlias www.example.com
    ServerAdmin webmaster@localhost
    DocumentRoot /var/www/example.com/html

    <Directory /var/www/example.com/html>
        Options -Indexes +FollowSymLinks
        AllowOverride All
        Require all granted
    </Directory>

    <FilesMatch \.php$>
        SetHandler "proxy:unix:/run/php/php8.3-fpm.sock|fcgi://localhost"
    </FilesMatch>

    # Security Headers
    Header always set X-Content-Type-Options "nosniff"
    Header always set X-Frame-Options "SAMEORIGIN"
    Header always set Referrer-Policy "strict-origin-when-cross-origin"
    Header always set Permissions-Policy "geolocation=(), microphone=(), camera=()"

    # Forwarded Headers
    RequestHeader set X-Forwarded-Proto expr=%{REQUEST_SCHEME}
    RequestHeader set X-Forwarded-Port expr=%{SERVER_PORT}

    ServerSignature Off

    ErrorLog /var/www/example.com/logs/error.log
    CustomLog /var/www/example.com/logs/access.log combined
</VirtualHost>

Apache, Reverse Proxy

Statt DocumentRoot, Directory und FilesMatch enthält der Block:

    ProxyPreserveHost On
    ProxyPass / http://localhost:3000/
    ProxyPassReverse / http://localhost:3000/

Mit --websocket folgt ein Block RewriteEngine On mit zwei RewriteCond (Upgrade: websocket, Connection: upgrade) und RewriteRule ^/?(.*) ws://localhost:3000/$1 [P,L]. Security- und Forwarded-Header sowie die Log-Pfade entsprechen dem PHP-VHost.

Nginx, PHP-VHost

server {
    listen 80;
    server_name example.com www.example.com;
    root /var/www/example.com/html;
    index index.php index.html;

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    location ~ \.php$ {
        try_files $uri =404;
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_pass unix:/run/php/php8.3-fpm.sock;
    }

    location ~ /\.ht {
        deny all;
    }

    # Security Headers
    add_header X-Content-Type-Options "nosniff" always;
    add_header X-Frame-Options "SAMEORIGIN" always;
    add_header Referrer-Policy "strict-origin-when-cross-origin" always;
    add_header Permissions-Policy "geolocation=(), microphone=(), camera=()" always;

    access_log /var/www/example.com/logs/access.log;
    error_log /var/www/example.com/logs/error.log;
}

Der Nginx-Proxy-Block enthält ein location / mit proxy_pass, proxy_http_version 1.1, proxy_set_header Host $host (außer bei --preserve-host false), X-Real-IP, X-Forwarded-For, X-Forwarded-Proto und X-Forwarded-Port, mit --websocket zusätzlich Upgrade und Connection "upgrade". Die Block-Struktur muss mit einer einzelnen Zeile } enden, weil Weiterleitungs-Blöcke vor dieser Zeile eingefügt werden.

Logrotate

/etc/logrotate.d/vhost-<domain> enthält für /var/www/<domain>/logs/*.log: weekly, missingok, rotate <ST_LOGROTATE_ROTATE>, maxage <ST_LOGROTATE_DAYS>, compress, delaycompress, notifempty, create 640 www-data www-data, sharedscripts und ein postrotate, das den Webserver neu lädt, wenn dessen PID-Datei existiert. Welcher Webserver das ist, steht beim Erzeugen fest im Text.

Dateien, die das Tool anlegt

Pfad Zweck
/etc/server-tools/config Konfiguration
<ST_CREDENTIAL_DIR>/<db>.txt Zugangsdaten je Datenbank
<ST_BACKUP_DIR>/*.tar.gz Backups vor dem Löschen
<ST_DB_BACKUP_DIR>/*.sql.gz Datenbank-Dumps
<ST_AUDIT_LOG> Audit-Log
/etc/logrotate.d/vhost-<domain> Logrotate je VHost
/var/www/<domain>/logs/, html/ Verzeichnisse einer Domain
/etc/cron.d/<name> Cronjobs
/etc/cron.d/ssl-renewal, /usr/local/bin/ssl-renewal.sh, /var/log/ssl-renewal.log Zertifikats-Erneuerung
/var/www/<domain>/.ssh/authorized_keys Schlüssel des Domain-Users

Entwicklung und Tests

make setup-tests   # BATS und Hilfsbibliotheken nach tests/libs klonen
make test          # alle Tests
make lint          # ShellCheck
make format-check  # shfmt -i 4 -bn -ci
make check         # lint, format-check und test

Die Tests liegen in tests/unit/*.bats (mehr als 500 Tests in 17 Dateien). Jeder Test läuft in einem eigenen temporären Verzeichnis, Systembefehle werden durch Mocks ersetzt (mock_command in tests/test_helper.bash). Kein Test berührt das echte System.

Die CI führt bei Push und Pull Request auf main drei Jobs aus: ShellCheck und shfmt, die BATS-Tests und einen Install-Smoke-Test, der make install, make uninstall, ./bin/server-tools install und uninstall gegen die echten /usr/local-Pfade ausführt.

Code-Stil: Bash 4.4 oder neuer, vier Leerzeichen Einrückung, set -euo pipefail nur im Entry-Script, Commits nach Conventional Commits. Die Vorgaben stehen in CONTRIBUTING.md des Repositories.