Deployment · Bash · Shell-Scripting · DevOps · CI/CD
Shell-Skripte für Deployments
Checklisten, Guards und automatische Rollbacks

Ein Deployment-Skript ohne Checklisten deployt auch dann, wenn der Build fehlerhaft ist. Ohne Guards läuft ein zweites Deployment parallel zum ersten. Ohne Rollback-Mechanismus ist ein fehlgeschlagenes Deployment ein manuelles Notfall-Szenario. Professionelle Shell-Skripte für Deployments lösen alle drei Probleme — mit einfachen, wartbaren Bash-Mustern.

14 Min. Lesezeit Pre-Deploy-Checks · Guards · Atomares Deployment · Rollback · CI/CD Bash 4.x · 5.x · Linux · GitHub Actions · GitLab CI

1. Was ein Deployment-Skript leisten muss

Ein professionelles Deployment-Skript ist mehr als ein Wrapper um rsync und einen Webserver-Reload. Es muss sicherstellen, dass ein Deployment nur dann startet, wenn alle Voraussetzungen erfüllt sind. Es muss verhindern, dass zwei Deployments gleichzeitig auf denselben Server schreiben. Es muss den Zielserver nach dem Transfer in einen konsistenten Zustand bringen — kein Teilzustand, kein kurzes Zeitfenster mit inkonsistenter Dateistruktur. Und es muss bei jedem Fehler in irgendeinem Schritt automatisch in einen sicheren Zustand zurückfallen, ohne manuellen Eingriff zu erfordern.

Diese Anforderungen sind in vielen Projekten nie explizit formuliert — bis das erste Mal ein Deployment schief geht. Dann zeigt sich, ob das Deployment-Skript diese Szenarien abgedeckt hat oder nicht. Ein Deployment, das die Produktion für 30 Minuten in einen defekten Zustand versetzt, weil der automatische Rollback fehlte, kostet mehr als die Zeit, die ein robustes Deployment-Skript in der Entwicklung kostet. Dieser Artikel zeigt die Bausteine, die jedes produktionstaugliche Deployment-Skript in Bash enthalten sollte.

Die Architektur eines professionellen Deployment-Skripts folgt immer derselben Phasenstruktur: Pre-Deploy (Checklisten, Guards), Transfer (atomarer Dateicopy), Post-Deploy (Health-Checks, Service-Reload), Verification (HTTP-Check, Log-Prüfung) und ggf. Rollback. Diese Phasen sind nicht optional — jede ausgesparte Phase ist ein Risiko. Das Deployment-Skript ist der Torwächter zwischen Build-Artefakt und Produktionsserver, und dieser Torwächter muss jeden seiner Schritte explizit verifizieren.

2. Pre-Deploy-Checklisten: Voraussetzungen systematisch prüfen

Eine Pre-Deploy-Checkliste ist eine Sammlung von Guard-Bedingungen, die vor dem ersten Transfer-Schritt geprüft werden. Das Deployment-Skript bricht ab, wenn eine dieser Bedingungen nicht erfüllt ist — mit einer klaren Fehlermeldung, die den Operator sofort weiß lässt, was fehlt. Typische Pre-Deploy-Checks: Existenz und Lesbarkeit der Konfigurationsdatei, Erreichbarkeit des Zielservers, verfügbarer Speicherplatz auf dem Zielserver, Gültigkeit der SSH-Verbindung, Existenz des Build-Artefakts, Übereinstimmung der Deploy-Branch mit der erwarteten Branch.

Die Implementation als Funktion run_preflight_checks() ist das empfohlene Muster für Deployment-Skripte: Alle Checks in einer dedizierten Funktion zusammengefasst, die am Anfang des Skripts aufgerufen wird. Jeder einzelne Check ist eine Bedingung mit expliziter Fehlermeldung und einem Exit-Code, der dem Monitoring mitteilt, welcher Check fehlgeschlagen ist. Das Skript schlägt laut und früh fehl — nicht still und spät, wenn der Transfer bereits zur Hälfte abgeschlossen ist. "Fail fast" ist bei Deployment-Skripten kein Stilmittel, sondern eine betriebliche Notwendigkeit.


#!/usr/bin/env bash
# deploy.sh — Production deployment with preflight checks, guards and rollback
set -euo pipefail
IFS=$'\n\t'

# --- Configuration ---
readonly REMOTE_HOST="${REMOTE_HOST:?Set REMOTE_HOST}"
readonly REMOTE_USER="${REMOTE_USER:-deploy}"
readonly DEPLOY_BASE="${DEPLOY_BASE:-/var/www/releases}"
readonly CURRENT_LINK="${CURRENT_LINK:-/var/www/current}"
readonly BUILD_DIR="${BUILD_DIR:-./dist}"
readonly KEEP_RELEASES="${KEEP_RELEASES:-7}"
readonly HEALTH_URL="${HEALTH_URL:?Set HEALTH_URL for post-deploy check}"
readonly LOCK_FILE="/tmp/deploy-${REMOTE_HOST}.lock"
readonly TS="$(date +%Y%m%d-%H%M%S)"
readonly RELEASE_DIR="${DEPLOY_BASE}/${TS}"

log()  { printf "[%s] [INFO]  %s\n" "$(date +%T)" "$*"; }
warn() { printf "[%s] [WARN]  %s\n" "$(date +%T)" "$*" >&2; }
err()  { printf "[%s] [ERROR] %s\n" "$(date +%T)" "$*" >&2; }

# --- Preflight check suite ---
run_preflight_checks() {
  log "Running preflight checks..."

  # 1. Build artifact exists and is non-empty
  [[ -d "$BUILD_DIR" ]] || { err "Build directory not found: $BUILD_DIR"; exit 10; }
  [[ -n "$(ls -A "$BUILD_DIR")" ]] || { err "Build directory is empty: $BUILD_DIR"; exit 11; }

  # 2. Remote host reachable via SSH
  ssh -o ConnectTimeout=5 -o BatchMode=yes \
    "${REMOTE_USER}@${REMOTE_HOST}" "true" 2>/dev/null \
    || { err "SSH connection failed to ${REMOTE_USER}@${REMOTE_HOST}"; exit 12; }

  # 3. Sufficient disk space on remote (require 500 MB free)
  local free_kb
  free_kb=$(ssh "${REMOTE_USER}@${REMOTE_HOST}" \
    "df --output=avail /var/www | tail -1")
  (( free_kb >= 512000 )) \
    || { err "Insufficient disk space on $REMOTE_HOST: ${free_kb}KB free"; exit 13; }

  # 4. No other deployment in progress (checked by guard, but verify here too)
  ssh "${REMOTE_USER}@${REMOTE_HOST}" \
    "test ! -f /tmp/deploy.lock || exit 14" \
    || { err "Deployment already in progress on $REMOTE_HOST"; exit 14; }

  log "All preflight checks passed."
}

3. Guards: Nebenläufigkeit und Doppelstarts verhindern

Ein Guard-Mechanismus im Deployment-Skript verhindert, dass zwei Deployment-Prozesse gleichzeitig auf denselben Server schreiben. Ohne Guard passiert in CI/CD-Umgebungen mit parallelen Pipelines regelmäßig Folgendes: Ein Deployment läuft, ein zweiter Push triggert gleichzeitig ein weiteres Deployment, beide rsync-Prozesse schreiben gleichzeitig in dasselbe Release-Verzeichnis, der Symlink-Swap wird zweimal mit unterschiedlichen Zielverzeichnissen ausgeführt. Das Ergebnis ist ein Produktionsserver in einem undefinierten Zustand.

Das robuste Muster für Deployment-Skripte ist ein zweigleisiger Guard: ein lokaler flock-basierter Lock für mehrere gleichzeitige Ausführungen desselben Skripts auf derselben Maschine, und ein Remote-Lock auf dem Zielserver für Deployments aus verschiedenen Quellen. Der Remote-Lock ist eine Datei, die zu Beginn des Deployments angelegt und am Ende — im EXIT-Trap — entfernt wird. Wer an dieser Stelle auf PID-File-Muster zurückgreift, muss die Cleanup-Logik sorgfältig implementieren: Ein Crash ohne Cleanup hinterlässt ein verwaistes Lockfile, das alle zukünftigen Deployments blockiert. flock übergibt die Sperre dagegen automatisch an das Betriebssystem — das Lockfile wird beim Prozessende automatisch freigegeben.


#!/usr/bin/env bash
# guards.sh — Local flock guard + remote lock for deployment serialization
set -euo pipefail

readonly LOCAL_LOCK="/tmp/deploy-local.lock"
readonly REMOTE_LOCK="/tmp/deploy-${REMOTE_HOST}.lock"
readonly REMOTE_USER="${REMOTE_USER:-deploy}"
readonly REMOTE_HOST="${REMOTE_HOST:?}"

REMOTE_LOCK_ACQUIRED=0

cleanup() {
  local code=$?
  # Always release remote lock if we acquired it
  if [[ $REMOTE_LOCK_ACQUIRED -eq 1 ]]; then
    ssh "${REMOTE_USER}@${REMOTE_HOST}" "rm -f '$REMOTE_LOCK'" 2>/dev/null || true
    log "Remote lock released"
  fi
  [[ $code -eq 0 ]] && log "Deployment completed successfully" \
                     || err "Deployment failed with exit code $code"
}
trap cleanup EXIT

# --- Local guard: prevent parallel deployments from same machine ---
exec 9>"$LOCAL_LOCK"
flock -n 9 || { err "Another deployment is already running locally"; exit 13; }
log "Local lock acquired"

# --- Remote guard: prevent deployments from different machines ---
ssh "${REMOTE_USER}@${REMOTE_HOST}" "
  if [ -f '$REMOTE_LOCK' ]; then
    echo 'LOCKED' >&2
    exit 1
  fi
  touch '$REMOTE_LOCK'
" || { err "Deployment already in progress on $REMOTE_HOST (remote lock exists)"; exit 14; }

REMOTE_LOCK_ACQUIRED=1
log "Remote lock acquired on $REMOTE_HOST"

4. Atomares Deployment: Symlink-Swap und Versionshistorie

Ein atomares Deployment-Skript stellt sicher, dass der Webserver zu keinem Zeitpunkt auf einen unvollständigen oder inkonsistenten Dateizustand zeigt. Das Muster: Jedes Deployment bekommt ein eigenes timestamped Release-Verzeichnis. rsync überträgt alle Dateien in dieses neue Verzeichnis. Erst nachdem der Transfer vollständig und verifiziert abgeschlossen ist, wird ein symbolischer Link auf das neue Verzeichnis umgebogen. Dieser Symlink-Swap ist ein einziger Syscall (rename(2) unter der Haube von ln -sfn) und damit atomar — der Webserver sieht niemals einen Zwischenzustand.

Die Versionshistorie ist ein Nebenprodukt dieses Musters: Jedes frühere Release-Verzeichnis bleibt erhalten, bis es durch die Rotation gelöscht wird. Rollbacks sind damit trivial: Den Symlink auf das gewünschte ältere Release-Verzeichnis zeigen lassen. Kein erneutes Deployment, kein Warten auf Transfer. Ein Rollback dauert so lange wie ein ln -sfn-Aufruf. Das ist das entscheidende Merkmal eines professionellen Deployment-Skripts: Rollbacks sind keine Notfallprozedur, sondern eine vorbereitete, getestete und in Sekunden ausführbare Aktion.

5. Post-Deploy-Health-Checks: Erfolg verifizieren

Nach dem Symlink-Swap verifiziert das Deployment-Skript, dass der Produktionsserver tatsächlich mit der neuen Version antwortet und keine Fehlermeldungen zurückgibt. Der einfachste Health-Check: ein HTTP-Request gegen den definierten Health-Endpoint mit curl --silent --max-time 10 --fail. Das --fail-Flag macht curl mit einem Nicht-Null-Exit-Code fehlschlagen, wenn der HTTP-Status-Code 4xx oder 5xx ist. Das kombiniert in einem einzigen Befehl die Prüfung von Erreichbarkeit und korrektem Antwortformat.

Für Magento-Deployments und komplexere Applikationen reicht ein einfacher HTTP-200-Check nicht aus. Das Deployment-Skript sollte mehrere Health-Check-Ebenen implementieren: HTTP-Status für Basis-Erreichbarkeit, Inhaltsprüfung für spezifische Elemente (z.B. Versionsnummer in der Response, Abwesenheit von PHP-Error-Seiten), Log-Prüfung für kurz nach dem Deployment auftretende Fehler. Ein Health-Check, der erst 60 Sekunden nach dem Symlink-Swap prüft, gibt Applikations-Caches Zeit zum Aufwärmen und deckt Fehler ab, die erst nach den ersten Requests auftreten.

6. Rollback-Mechanismen: automatisch und manuell

Das Deployment-Skript implementiert zwei Rollback-Varianten: automatisch bei fehlgeschlagenem Health-Check, und manuell über ein separates Rollback-Skript. Der automatische Rollback im EXIT-Trap: Wenn der Health-Check fehlschlägt und das Skript mit Fehlercode beendet wird, bringt der EXIT-Trap den Symlink auf das vorherige Release-Verzeichnis zurück. Das setzt voraus, dass das vorherige Release-Verzeichnis beim Deployment-Start gemerkt wurde: PREVIOUS_RELEASE="$(readlink -f "$CURRENT_LINK")".

Der manuelle Rollback ist ein separates Deployment-Skript (rollback.sh), das das gewünschte Release-Verzeichnis als Parameter nimmt oder interaktiv aus den verfügbaren Releases auswählen lässt. Dieses Skript führt denselben Symlink-Swap und dieselben Health-Checks durch wie das Deployment. Die wichtigste Eigenschaft eines Rollback-Skripts: Es ist das am wenigsten häufig ausgeführte Skript, aber das mit den höchsten Anforderungen an Zuverlässigkeit. Es muss im Stressmoment eines Produktionsvorfalls zuverlässig funktionieren. Das erfordert regelmäßige Tests — nicht nur in der Entwicklung, sondern auch auf der Produktionsumgebung als geplante Übung.


#!/usr/bin/env bash
# rollback.sh — Automated and manual rollback with health check verification
set -euo pipefail
IFS=$'\n\t'

readonly REMOTE_HOST="${REMOTE_HOST:?}"
readonly REMOTE_USER="${REMOTE_USER:-deploy}"
readonly DEPLOY_BASE="${DEPLOY_BASE:-/var/www/releases}"
readonly CURRENT_LINK="${CURRENT_LINK:-/var/www/current}"
readonly HEALTH_URL="${HEALTH_URL:?Set HEALTH_URL}"

log() { printf "[%s] [INFO]  %s\n" "$(date +%T)" "$*"; }
err() { printf "[%s] [ERROR] %s\n" "$(date +%T)" "$*" >&2; }

list_releases() {
  ssh "${REMOTE_USER}@${REMOTE_HOST}" \
    "ls -1dt '${DEPLOY_BASE}'/*/ 2>/dev/null | head -10"
}

get_current_release() {
  ssh "${REMOTE_USER}@${REMOTE_HOST}" \
    "readlink -f '$CURRENT_LINK' 2>/dev/null || echo 'none'"
}

perform_rollback() {
  local target_release="$1"

  log "Rolling back to: $target_release"
  log "Current release: $(get_current_release)"

  # Validate target release exists on remote
  ssh "${REMOTE_USER}@${REMOTE_HOST}" \
    "test -d '$target_release'" \
    || { err "Release directory not found: $target_release"; exit 1; }

  # Atomic symlink swap
  ssh "${REMOTE_USER}@${REMOTE_HOST}" \
    "ln -sfn '$target_release' '$CURRENT_LINK' && echo 'Symlink updated'"

  # Post-rollback health check
  log "Verifying rollback via health check..."
  local attempt
  for attempt in 1 2 3; do
    if curl --silent --max-time 10 --fail "$HEALTH_URL" > /dev/null 2>&1; then
      log "Health check passed after rollback (attempt $attempt)"
      return 0
    fi
    warn "Health check attempt $attempt failed — retrying in 5s..."
    sleep 5
  done

  err "Health check failed after rollback — MANUAL INTERVENTION REQUIRED"
  err "Current symlink points to: $(get_current_release)"
  exit 1
}

# --- Main: use provided release or let user choose ---
if [[ $# -eq 1 ]]; then
  TARGET_RELEASE="$1"
else
  log "Available releases:"
  list_releases
  read -rp "Enter release path to roll back to: " TARGET_RELEASE
fi

perform_rollback "$TARGET_RELEASE"
log "Rollback complete. Active release: $(get_current_release)"

7. Benachrichtigungen und Deployment-Protokolle

Ein professionelles Deployment-Skript protokolliert jeden Schritt und sendet Benachrichtigungen bei Erfolg und Fehler. Das Mindestprotokoll: Beginn und Ende des Deployments mit Zeitstempeln, jeder Schritt mit Dauer, alle Fehlermeldungen mit Exit-Codes und Zeilennummern. Das Protokoll wird in eine datierte Log-Datei geschrieben und gleichzeitig auf der Konsole ausgegeben. Das Muster exec > >(tee -a "$DEPLOY_LOG") 2>&1 am Skriptanfang sorgt dafür, dass jede Ausgabe — stdout und stderr — gleichzeitig im Terminal und in der Logdatei landet.

Benachrichtigungen via Webhook (Slack, Teams, Mattermost) oder E-Mail informieren das Team ohne Log-Monitoring. Das Deployment-Skript sendet am Ende des EXIT-Traps eine Benachrichtigung mit: Deployment-Status (Erfolg/Fehler/Rollback), Release-Verzeichnis, Deployment-Dauer und bei Fehlern die letzte Fehlermeldung aus dem Log. Eine einfache Webhook-Benachrichtigung via curl -X POST mit JSON-Body braucht wenige Zeilen und ist deutlich zuverlässiger als E-Mail. Die Benachrichtigungslogik im EXIT-Trap stellt sicher, dass auch bei abgebrochenem Deployment eine Meldung gesendet wird.

8. CI/CD-Integration: Deployment-Skripte in Pipelines

Das Deployment-Skript in einer CI/CD-Pipeline ist kein autonomes Programm, sondern ein Schritt in einem größeren Workflow. Es empfängt Konfiguration über Umgebungsvariablen (Secrets für SSH-Key und Remote-Host, Build-Artefaktpfad, Health-URL), führt seinen Ablauf durch und kommuniziert Erfolg oder Fehler über Exit-Codes zurück an die Pipeline. Die Pipeline entscheidet basierend auf dem Exit-Code, ob nachfolgende Steps ausgeführt oder der gesamte Workflow als fehlgeschlagen markiert wird.

Die empfohlene Pipeline-Struktur für ein Deployment-Skript: Build-Step, Test-Step, ShellCheck-Step auf dem Deployment-Skript selbst, Staging-Deployment-Step, Staging-Health-Check-Step, manueller Approve-Step (für Produktions-Deployments), Produktions-Deployment-Step, Produktions-Health-Check-Step. Dieses Muster stellt sicher, dass ein fehlerhaftes Deployment-Skript zuerst auf Staging getestet wird, bevor es die Produktion erreicht. Und der manuelle Approve-Step gibt dem Team die Kontrolle, kritische Deployments zum richtigen Zeitpunkt zu aktivieren.

9. Deployment-Strategien im Vergleich

Verschiedene Deployment-Skript-Strategien haben unterschiedliche Trade-offs bei Downtime, Rollback-Fähigkeit und Komplexität. Die Wahl hängt von den Anforderungen an Verfügbarkeit und Rollback-Geschwindigkeit ab.

Strategie Downtime Rollback Komplexität
Direktes Überschreiben Während Transfer Kein automatischer Rollback Minimal
Symlink-Swap (atomar) Keine (atomar) ln -sfn — Sekunden Moderat
Maintenance-Mode + Deploy Geplant (Wartungsfenster) Manuell, Minuten Moderat
Blue-Green (2 Server) Keine (Load-Balancer-Swap) Load-Balancer zurückschalten Hoch (2 Umgebungen)
Canary (schrittweise) Keine Traffic-Verschiebung Sehr hoch

Für die meisten Webserver-Deployments auf einem einzelnen Server ist der atomare Symlink-Swap die optimale Strategie: keine Downtime, Rollback in Sekunden, moderater Implementierungsaufwand. Das Deployment-Skript mit rsync + --link-dest + Symlink-Swap deckt diese Strategie vollständig ab. Für Multi-Server-Setups mit Load-Balancer ist Blue-Green die nächste sinnvolle Stufe — wobei der Load-Balancer-Swap dann das atomare Element ist, das das Symlink-Swap ersetzt.

Mironsoft

Shell-Automatisierung, DevOps-Tooling und Deployment-Infrastruktur

Deployment-Skripte, die automatisch zurückrollen?

Wir implementieren atomare Deployment-Skripte mit vollständigen Pre-Deploy-Checklisten, Guard-Mechanismen, Health-Checks und automatischem Rollback — vollständig in Bash, wartungsarm und ohne externe Abhängigkeiten.

Deployment-Audit

Bestehende Deployment-Skripte auf fehlende Guards und Rollback-Lücken prüfen

Atomares Deployment

Symlink-Swap, Versionshistorie und automatischen Rollback implementieren

CI/CD-Integration

Deployment-Skripte in GitHub Actions oder GitLab CI mit Approve-Gate einbinden

10. Zusammenfassung

Ein professionelles Deployment-Skript in Bash besteht aus fünf unverzichtbaren Bausteinen. Pre-Deploy-Checklisten prüfen alle Voraussetzungen bevor ein Byte auf den Zielserver übertragen wird. Guard-Mechanismen verhindern parallele Deployments durch lokales flock und Remote-Locks. Atomares Deployment über rsync + --link-dest und Symlink-Swap stellt sicher, dass der Webserver keinen inkonsistenten Zustand sieht. Post-Deploy-Health-Checks verifizieren, dass die neue Version korrekt antwortet. Automatischer Rollback im EXIT-Trap kehrt bei fehlgeschlagenem Health-Check sofort zum letzten guten Release zurück.

Das wichtigste Qualitätsmerkmal eines Deployment-Skripts: Es ist getestet — nicht nur als manueller Test einmalig bei der Entwicklung, sondern regelmäßig und automatisch. ShellCheck in der CI-Pipeline prüft statische Korrektheit. BATS-Tests verifizieren Preflight-Checks und Rollback-Logik. Und gelegentliche Rollback-Übungen auf der Produktionsumgebung stellen sicher, dass der Rollback-Mechanismus tatsächlich funktioniert, wenn er gebraucht wird — nicht erst beim ersten echten Vorfall.

Shell-Skripte für Deployments — Das Wichtigste auf einen Blick

Pre-Deploy-Checks

run_preflight_checks() vor dem Transfer: Artefakt vorhanden, SSH erreichbar, Speicherplatz frei, kein aktives Deployment. Fail fast mit klaren Exit-Codes.

Guards

Lokales flock + Remote-Lock verhindern parallele Deployments. EXIT-Trap gibt alle Locks zuverlässig frei — auch bei Crashes.

Atomares Deployment

rsync --link-dest in neues Release-Verzeichnis, dann ln -sfn für atomaren Symlink-Swap. Keine Downtime, vollständige Versionshistorie.

Automatischer Rollback

PREVIOUS_RELEASE vor Deployment merken. Bei fehlgeschlagenem Health-Check im EXIT-Trap sofort zurückrollen. Rollback-Skript separat und regelmäßig testen.

11. FAQ: Shell-Skripte für Deployments

1Was sind Pre-Deploy-Checks?
Bedingungen vor dem Transfer: Artefakt vorhanden, SSH erreichbar, Speicherplatz frei, kein aktives Deployment. Fail-fast am Anfang ist günstiger als Abbruch auf halbem Weg.
2Parallele Deployments verhindern?
flock für lokale Serialisierung + Remote-Lock auf dem Zielserver. EXIT-Trap gibt alle Locks bei Prozessende frei — auch bei Crashes.
3Was ist ein atomares Deployment?
Neues Release-Verzeichnis per rsync befüllen, dann mit ln -sfn atomar umschalten. Kein Zwischenzustand für den Webserver sichtbar.
4Automatisches Rollback implementieren?
PREVIOUS_RELEASE vor Deployment merken. Im EXIT-Trap bei fehlgeschlagenem Health-Check: ln -sfn $PREVIOUS_RELEASE zurückschalten.
5Was prüft ein Post-Deploy-Health-Check?
HTTP-Status (curl --fail), Inhalt (keine Fehlerseite), Log-Prüfung. Erst 30–60s nach Symlink-Swap für Cache-Aufwärmung warten.
6Wie viele Releases aufbewahren?
5–10 Releases für ausreichend Rollback-Optionen. Da --link-dest nur Deltas speichert, ist der Overhead je Release meist minimal.
7Deployment-Skript in GitHub Actions?
SSH-Key als Secret, Staging automatisch, Produktion nach environment: production mit required reviewers. Manueller Approve vor jedem Produktions-Deploy.
8Rollback-Skript testen?
Geplante Rollback-Übungen auf Staging. Regelmäßig testen — nicht erst beim ersten Produktionsvorfall. Health-Check verifiziert das Ergebnis automatisch.
9Symlink-Swap vs. Blue-Green?
Symlink-Swap: ein Server, kein Load-Balancer nötig, kostengünstig. Blue-Green: zwei Server + Load-Balancer, höhere Infrastrukturkosten. Beide zero downtime.
10Alle Schritte in Logdatei protokollieren?
exec > >(tee -a $LOG) 2>&1 am Skriptanfang leitet stdout+stderr in Terminal und Datei. Datierte Log-Dateinamen für automatische Rotation.