Website veroeffentlicht und die Diagnose des Skripts geschaerft

https://jamulix.de/OR/ steht auf dem Stand des heutigen Baus: 213 Dateien
uebertragen, 35 geloescht, alle vierzehn HTTP-Proben richtig - darunter die
entscheidende: /OR/anhang-glossar-literatur.html liefert jetzt 404 statt 200.
Der zweite Lauf unmittelbar danach uebertrug 0 Dateien und loeschte nichts.

Die Abbruchgrenze hat gleich beim ersten Einsatz gegriffen: 35 Loeschungen
ueber der Vorgabe von 30. Die Liste war vollstaendig erklaerbar - 33
verwaiste PNGs aus dem Aufraeumschritt, das leere bilder_04/__pycache__/ aus
dem spiegle_bilder()-Fehler und die geteilte Anhangseite. Dass ein
scp-Upload alle 35 stehen gelassen haette, ist damit belegt statt behauptet.

Zwei Huerden auf dem Weg, beide ins Skript uebersetzt:

ssh-copy-id braucht ein echtes Terminal. In der Claude-Code-Sitzung gibt es
keins, aber DISPLAY ist gesetzt - ssh sucht daraufhin ssh-askpass, das nicht
installiert ist. Der Schritt gehoert in ein normales Terminalfenster.

Danach sperrte fail2ban den Port: erste Verbindung erfolgreich, die folgenden
"Connection refused", waehrend die Website weiter mit 200 antwortete. Nach
sieben Minuten war die Sperre weg; weitere Versuche haetten sie verlaengert.

pruefe_ziel_erreichbar() unterscheidet jetzt die abgewiesene Verbindung von
der abgelehnten Anmeldung. Vorher meldete es in beiden Faellen "Der Schluessel
liegt noch nicht auf dem Server" - beim zweiten Mal glatt falsch, denn er lag
laengst dort.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
dschlueter 2026-09-08 16:52:00 +02:00
commit ef79e6fdc1
2 changed files with 66 additions and 9 deletions

View file

@ -205,23 +205,39 @@ def rsync_befehl(env: dict[str, str], probelauf: bool) -> list[str]:
def pruefe_ziel_erreichbar(env: dict[str, str]) -> None:
"""Ein Handschlag, bevor 23 MB losgeschickt werden - und er unterscheidet
die beiden Fehlerursachen, die sonst leicht verwechselt werden: Anmeldung
scheitert (ssh liefert 255) gegen rsync fehlt am Ziel."""
"""Ein Handschlag, bevor 23 MB losgeschickt werden. Er unterscheidet die
Ursachen, die sonst leicht verwechselt werden - alle drei sind hier schon
aufgetreten: Verbindung abgewiesen, Anmeldung gescheitert, rsync fehlt."""
kennung = f'{env["OR_BENUTZER"]}@{env["OR_HOST"]}'
# BatchMode: keine Passwortabfrage, damit der Aufruf nicht haengt. Der
# ssh-agent funktioniert weiterhin. stderr laeuft absichtlich durch, damit
# ssh seine eigene Diagnose zeigen kann.
# ssh-agent funktioniert weiterhin. stderr wird mitgelesen UND
# weitergereicht: gelesen, um die Ursache zu erkennen, gezeigt, damit ssh
# seine eigene Diagnose loswird.
ergebnis = subprocess.run(
ssh_optionen(env).split() + ["-o", "BatchMode=yes", kennung,
"command -v rsync || echo KEIN_RSYNC"],
stdout=subprocess.PIPE, text=True)
capture_output=True, text=True)
if ergebnis.stderr:
print(ergebnis.stderr.rstrip(), file=sys.stderr)
if ergebnis.returncode == 255:
# Abgewiesene Verbindung ist NICHT dasselbe wie eine gescheiterte
# Anmeldung. Beim ersten Einsatz dieses Skripts sperrte fail2ban den
# Port, nachdem ssh-copy-id ein paar Passwortversuche verbraucht hatte -
# die Meldung "Schluessel liegt nicht auf dem Server" fuehrte da in die
# falsche Richtung, denn der Schluessel lag laengst dort.
if "Connection refused" in ergebnis.stderr or "timed out" in ergebnis.stderr:
raise SystemExit(
f"FEHLER: {env['OR_HOST']} weist die Verbindung auf Port 22 ab.\n"
f" Wenn die Website selbst antwortet, ist meist eine\n"
f" Sperre nach fehlgeschlagenen Anmeldeversuchen die\n"
f" Ursache (fail2ban). Sie loest sich nach einigen\n"
f" Minuten von selbst - weitere Versuche verlaengern sie.")
raise SystemExit(
f"FEHLER: Keine SSH-Verbindung zu {kennung} (siehe Meldung oben).\n"
f"FEHLER: Anmeldung an {kennung} abgelehnt (siehe Meldung oben).\n"
f" Haeufigste Ursache: Der oeffentliche Schluessel liegt noch\n"
f" nicht auf dem Server. Einmalig:\n"
f" ssh-copy-id {kennung}\n"
f" nicht auf dem Server. Einmalig, in einem ECHTEN Terminal\n"
f" (ssh braucht dafuer ein tty):\n"
f" ssh-copy-id -i ~/.ssh/id_ed25519.pub {kennung}\n"
f" Bei passwortgeschuetztem Schluessel: ssh-add einmal "
f"ausfuehren.")
if ergebnis.returncode != 0: