1. Einleitung
Bilder sind oft der grösste Speicherfresser auf Webservern und verlangsamen die Ladezeiten. Während es viele WordPress-Plugins gibt, arbeiten diese oft ressourcenintensiv oder kosten Geld. Für Server-Administratoren (speziell unter CloudPanel) ist ein serverseitiges Bash-Skript oft die effizientere Lösung.
Dieses Tutorial stellt ein umfassendes «Universal Image Optimizer»-Skript vor. Es konvertiert Bilder vollautomatisch in das WebP-Format, aktualisiert Datenbankpfade und bereinigt den Speicherplatz – alles über ein interaktives Terminal-Menü.
- Zielgruppe: Server-Admins, Entwickler, CloudPanel-Nutzer
- Voraussetzungen: Root-Zugriff, ImageMagick, WP-CLI
- Funktionen: WordPress, Statische Galerien, NodeJS-Apps
[BILD 1: Schematische Darstellung des Skript-Ablaufs: Input JPG -> Konverter -> Output WebP + DB Update]
2. Überblick
Am Ende dieses Tutorials haben Sie ein einsatzbereites Bash-Tool auf Ihrem Server installiert, das folgende Aufgaben übernimmt:
- Massenaustausch von JPG/PNG gegen WebP (Qualität 82).
- Automatisches Suchen & Ersetzen in der WordPress-Datenbank.
- Erstellung von Thumbnails für statische Galerien.
- Pfadanpassung in Custom-Apps (via .env und MySQL).
3. Schritt-für-Schritt Anleitung
Schritt 1: Abhängigkeiten installieren
Damit das Skript funktioniert, müssen ImageMagick (für die Bildbearbeitung) und ein MySQL-Client installiert sein. Auf den meisten CloudPanel-Instanzen ist dies Standard, zur Sicherheit prüfen wir es:
apt update
apt install imagemagick mariadb-client -y
Schritt 2: Das Skript erstellen
Erstellen Sie eine neue Datei auf Ihrem Server, idealerweise im Root-Verzeichnis.
Datei: /root/optimize_cloudpanel.sh
Aktion: Neu erstellen
#!/bin/bash
# ---------------------------------------------------------
# UNIVERSAL IMAGE OPTIMIZER (CloudPanel / Server)
# Version 9: WordPress + Galerie + NodeJS
# ---------------------------------------------------------
set -e
# --- KONFIGURATION ALLGEMEIN ---
WP_BIN="/usr/bin/wp"
QUALITY=82
# --- KONFIGURATION GALERIE (Fester Pfad) ---
GALLERY_PATH="/home/web1/htdocs/web1/wp-content/uploads/galerien"
GALLERY_MAX_EDGE=1600
THUMB_SIZE="150x150"
# --- KONFIGURATION NODEJS (r) ---
NODE_APP_PATH="/home/web2/htdocs/web2"
NODE_UPLOAD_DIR="$NODE_APP_PATH/uploads"
NODE_ENV_FILE="$NODE_APP_PATH/.env"
# --- KONFIGURATION WORDPRESS DOMAINS ---
declare -A WP_LABELS
declare -A WP_PATHS
# --- DOMAIN 1 ---
WP_LABELS[1]="web3"
WP_PATHS[1]="/home/web3/htdocs/web3"
# --- DOMAIN 2 ---
WP_LABELS[2]="web4"
WP_PATHS[2]="/home/web4/htdocs/web4"
# --- Weitere Domains hier einfach anfügen ... ---
# ---------------------------------------------------------
# HILFSFUNKTIONEN
# ---------------------------------------------------------
show_header() {
clear
echo "================================================="
echo " SERVER BILD-OPTIMIERER (2-in-1 + NodeJS)"
echo "================================================="
}
get_owner() {
stat -c '%U:%G' "$1"
}
press_enter_to_continue() {
echo ""
echo "-------------------------------------------------"
read -p "Drücke [ENTER], um zum Hauptmenü zurückzukehren..." DUMMY
}
# ---------------------------------------------------------
# FUNKTION 1: WORDPRESS MODUS
# ---------------------------------------------------------
run_wordpress() {
while true; do
show_header
echo "--- WORDPRESS MODUS ---"
echo "Wähle die Installation:"
echo ""
for ID in "${!WP_LABELS[@]}"; do
echo " [$ID] ${WP_LABELS[$ID]}"
done | sort -n
echo " [0] Zurück zum Hauptmenü"
echo ""
read -p "Nummer: " SEL
if [[ "$SEL" == "0" ]]; then return; fi
WP_ROOT="${WP_PATHS[$SEL]}"
if [ -z "$WP_ROOT" ]; then
echo ">> Ungültige Auswahl."; sleep 1; continue
fi
UPLOAD_DIR="$WP_ROOT/wp-content/uploads"
if [ ! -d "$UPLOAD_DIR" ]; then
echo ">> Fehler: Ordner nicht gefunden: $UPLOAD_DIR"; press_enter_to_continue; return
fi
OWNER=$(get_owner "$WP_ROOT")
echo "-------------------------------------------------"
echo "Webseite: ${WP_LABELS[$SEL]}"
echo "Pfad: $UPLOAD_DIR"
echo "-------------------------------------------------"
echo "Aktion: Konvertierung zu WebP (1:1 Größe)."
echo " Originale werden GELÖSCHT."
echo " Datenbank wird aktualisiert."
echo "-------------------------------------------------"
read -p "Starten? (j/n): " C
if [[ "$C" != "j" && "$C" != "J" ]]; then continue; fi
echo ""
echo ">>> Verarbeite Bilder..."
find "$UPLOAD_DIR" -type f \( -iname "*.webp" -o -iname "*.webp" -o -iname "*.webp" \) | while read FILE; do
DIR=$(dirname "$FILE")
NAME="${FILE%.*}"
WEBP="$NAME.webp"
if [ ! -f "$WEBP" ]; then
if nice -n 10 convert "$FILE" -quality $QUALITY -define webp:method=6 "$WEBP"; then
echo "NEU: $(basename "$FILE") -> WebP. Lösche Original."
rm "$FILE"
fi
else
echo "CLEANUP: Lösche altes Original $(basename "$FILE")"
rm "$FILE"
fi
done
echo ">>> Korrigiere Rechte..."
chown -R "$OWNER" "$UPLOAD_DIR"
echo ">>> Datenbank Update (WP-CLI)..."
read -p "DB jetzt aktualisieren? (j/n): " D
if [[ "$D" == "j" || "$D" == "J" ]]; then
cd "$WP_ROOT"
$WP_BIN search-replace '.webp' '.webp' --all-tables --precise --allow-root
$WP_BIN search-replace '.webp' '.webp' --all-tables --precise --allow-root
$WP_BIN search-replace '.webp' '.webp' --all-tables --precise --allow-root
$WP_BIN cache flush --allow-root
echo ">> Fertig."
else
echo ">> Übersprungen."
fi
press_enter_to_continue
return
done
}
# ---------------------------------------------------------
# FUNKTION 2: GALERIE MODUS
# ---------------------------------------------------------
run_gallery() {
show_header
echo "--- GALERIE MODUS ---"
if [ ! -d "$GALLERY_PATH" ]; then
echo "FEHLER: $GALLERY_PATH nicht gefunden."; press_enter_to_continue; return
fi
OWNER=$(get_owner "$GALLERY_PATH")
echo "Ziel: $GALLERY_PATH"
echo "User: $OWNER"
echo "Aktion: Resize (${GALLERY_MAX_EDGE}px) + Thumbnails. Originale LÖSCHEN."
read -p "Starten? (j/n): " C
if [[ "$C" != "j" && "$C" != "J" ]]; then return; fi
echo ">>> Suche Bilder..."
find "$GALLERY_PATH" -type f \( -iname "*.webp" -o -iname "*.webp" -o -iname "*.webp" -o -iname "*.heic" \) \
-not -path '*/Thumbnail/*' | while read FILE; do
DIR=$(dirname "$FILE")
FILENAME=$(basename "$FILE")
NAME="${FILENAME%.*}"
OUT_MAIN="$DIR/$NAME.webp"
THUMB_DIR="$DIR/Thumbnail"
OUT_THUMB="$THUMB_DIR/$NAME.webp"
mkdir -p "$THUMB_DIR"
if [ ! -f "$OUT_MAIN" ]; then
nice -n 10 convert "$FILE" -resize "${GALLERY_MAX_EDGE}x${GALLERY_MAX_EDGE}>" \
-quality $QUALITY -define webp:method=6 "$OUT_MAIN"
nice -n 10 convert "$OUT_MAIN" -thumbnail "${THUMB_SIZE}^" -gravity center -extent "$THUMB_SIZE" \
-quality $QUALITY "$OUT_THUMB"
echo "Galerie: $FILENAME verarbeitet. Lösche Original."
rm "$FILE"
else
echo "Überspringe (existiert schon): $FILENAME"
fi
done
echo ">>> Korrigiere Rechte..."
chown -R "$OWNER" "$GALLERY_PATH"
echo "Fertig."
press_enter_to_continue
}
# ---------------------------------------------------------
# FUNKTION 3: NODEJS MODUS (ictlager)
# ---------------------------------------------------------
run_nodejs_ict() {
show_header
echo "--- NODEJS MODUS (ictlager) ---"
if [ ! -f "$NODE_ENV_FILE" ]; then
echo "FEHLER: .env Datei nicht gefunden in:"
echo "$NODE_ENV_FILE"
press_enter_to_continue; return
fi
OWNER=$(get_owner "$NODE_UPLOAD_DIR")
echo "App Pfad: $NODE_APP_PATH"
echo "Uploads: $NODE_UPLOAD_DIR"
echo "User: $OWNER"
echo "-------------------------------------------------"
echo "ACHTUNG: Dies ist keine WordPress-Installation!"
echo "Das Script liest die MySQL-Zugangsdaten aus der .env-Datei,"
echo "um in der Tabelle 'Product' die Pfade (.webp -> .webp) zu ändern."
echo "-------------------------------------------------"
read -p "Bist du sicher? (j/n): " C
if [[ "$C" != "j" && "$C" != "J" ]]; then return; fi
# 1. Credentials aus .env parsen
DB_URL=$(grep "DATABASE_URL" "$NODE_ENV_FILE" | cut -d'=' -f2- | tr -d '"' | tr -d "'")
if [[ $DB_URL =~ mysql://([^:]+):([^@]+)@([^:]+):([0-9]+)/(.+) ]]; then
DB_USER="${BASH_REMATCH[1]}"
DB_PASS="${BASH_REMATCH[2]}"
DB_HOST="${BASH_REMATCH[3]}"
DB_PORT="${BASH_REMATCH[4]}"
DB_NAME="${BASH_REMATCH[5]}"
DB_NAME=$(echo "$DB_NAME" | cut -d'?' -f1)
else
echo "FEHLER: Konnte DATABASE_URL nicht parsen."
press_enter_to_continue; return
fi
echo ">> DB Credentials gefunden: $DB_USER @ $DB_NAME"
# 2. Bilder konvertieren
echo ">>> Konvertiere Bilder..."
find "$NODE_UPLOAD_DIR" -type f \( -iname "*.webp" -o -iname "*.webp" -o -iname "*.webp" \) | while read FILE; do
DIR=$(dirname "$FILE")
NAME="${FILE%.*}"
WEBP="$NAME.webp"
if [ ! -f "$WEBP" ]; then
if nice -n 10 convert "$FILE" -quality $QUALITY -define webp:method=6 "$WEBP"; then
echo "NEU: $(basename "$FILE") -> WebP. Lösche Original."
rm "$FILE"
fi
else
echo "CLEANUP: Lösche altes Original $(basename "$FILE")"
rm "$FILE"
fi
done
# 3. Rechte
echo ">>> Korrigiere Rechte..."
chown -R "$OWNER" "$NODE_UPLOAD_DIR"
# 4. SQL Update
echo ">>> Aktualisiere Datenbank (Tabelle 'Product')..."
SQL_CMD_JPG="UPDATE Product SET imagePath = REPLACE(imagePath, '.webp', '.webp') WHERE imagePath LIKE '%.webp';"
SQL_CMD_JPEG="UPDATE Product SET imagePath = REPLACE(imagePath, '.webp', '.webp') WHERE imagePath LIKE '%.webp';"
SQL_CMD_PNG="UPDATE Product SET imagePath = REPLACE(imagePath, '.webp', '.webp') WHERE imagePath LIKE '%.webp';"
mysql -u"$DB_USER" -p"$DB_PASS" -h"$DB_HOST" -P"$DB_PORT" "$DB_NAME" -e "$SQL_CMD_JPG"
mysql -u"$DB_USER" -p"$DB_PASS" -h"$DB_HOST" -P"$DB_PORT" "$DB_NAME" -e "$SQL_CMD_JPEG"
mysql -u"$DB_USER" -p"$DB_PASS" -h"$DB_HOST" -P"$DB_PORT" "$DB_NAME" -e "$SQL_CMD_PNG"
echo ">> Datenbank-Pfade aktualisiert."
echo "Fertig."
press_enter_to_continue
}
# ---------------------------------------------------------
# HAUPTMENÜ LOOP
# ---------------------------------------------------------
while true; do
show_header
echo "Was möchtest du tun?"
echo "1) WordPress optimieren"
echo "2) Fotogalerie optimieren"
echo "3) NodeJS App optimieren (ictlager)"
echo "4) Beenden"
echo ""
read -p "Auswahl [1-4]: " CHOICE
case "$CHOICE" in
1) run_wordpress ;;
2) run_gallery ;;
3) run_nodejs_ict ;;
4) echo "Tschüss!"; exit 0 ;;
*) echo "Ungültig."; sleep 1 ;;
esac
done
Schritt 3: Konfiguration anpassen
Bevor Sie das Skript starten, müssen Sie die Pfade zu Ihren Webseiten im oberen Bereich des Skripts (unter --- KONFIGURATION ---) anpassen:
-
-
- WordPress: Passen Sie die Arrays
WP_LABELS(Name) undWP_PATHS(Systempfad) an. - Galerie: Setzen Sie
GALLERY_PATHauf Ihren statischen Bilderordner. - NodeJS: Falls verwendet, prüfen Sie
NODE_APP_PATHund den Tabellennamen im SQL-Abschnitt (standardmässig ‚Product‘).
- WordPress: Passen Sie die Arrays
-
Schritt 4: Ausführbar machen und Starten
Geben Sie der Datei die nötigen Ausführungsrechte und starten Sie das Menü:
chmod +x /root/optimize_cloudpanel.sh
./optimize_cloudpanel.sh
[BILD 2: Screenshot des interaktiven Terminal-Menüs bei der Ausführung]
4. Wichtige Hinweise & Stolperfallen
Backup Pflicht: Dieses Skript arbeitet destruktiv und löscht Originaldateien, um Speicherplatz zu sparen. Erstellen Sie vor der Ausführung zwingend ein Backup der Webseite oder einen Server-Snapshot.
WordPress Update: Bestätigen Sie die Frage nach dem Datenbank-Update immer mit «J». Andernfalls sind die Bilder physisch WebP, aber WordPress sucht weiterhin nach JPG, was zu fehlerhaften Bildern auf der Webseite führt.
5. Ergebnis & Fazit
Mit diesem Skript haben Sie eine leistungsfähige Lösung, um Ihre Server-Assets zu modernisieren. Durch die Konvertierung zu WebP sparen Sie Speicherplatz und beschleunigen die Auslieferung der Webseiten signifikant. Die Integration von WordPress, statischen Galerien und Custom-Apps in ein einziges Menü erleichtert die Wartung enorm.
Ein logischer nächster Schritt wäre die Einrichtung eines Cronjobs, falls Sie diese Aufgaben regelmässig automatisiert ausführen möchten.