Showcase nachgezogen: restliche Portfolio-Dateien auf aktuellen Stand
parent
a2be9fec88
commit
40bc8913e7
1 changed files with 137 additions and 0 deletions
|
|
@ -154,6 +154,143 @@ sftp-root-directory = /
|
|||
```
|
||||
Passwort nicht als Parameter setzen — wird beim ersten Datei-Transfer-Zugriff im Guacamole-Seitenpanel abgefragt.
|
||||
|
||||
## 8. Auto-Stop bei Nichtnutzung + Wake-Mechanismus (Stromsparen)
|
||||
|
||||
CT102 läuft dauerhaft (~335 MB RAM + etwas CPU im Leerlauf), auch wenn niemand per VNC verbunden ist. Ziel: automatisch stoppen, wenn ungenutzt, mit einfachem Weg zum Wiederstarten.
|
||||
|
||||
⚠️ **NICHT TUN:** `pct suspend`/`resume` (CRIU-Checkpointing) für einen echten Ruhezustand verwenden. Proxmox unterstützt das für Container nur experimentell — für einen vollen Desktop-Prozessbaum (X11/VNC/Firefox) real riskant (bekannte CRIU-Einschränkungen bei komplexen Prozessbäumen/offenen Sockets). Stattdessen: komplett stoppen und bei Bedarf neu starten — bei einem LXC dauert das nur Sekunden, kein Kernel-Boot wie bei einer echten VM.
|
||||
|
||||
### Wake-Mechanismus (spiegelt "Wake PC1" aus `01-pve-host.md` Abschnitt 6)
|
||||
|
||||
```bash
|
||||
useradd -m -s /bin/bash browserwake
|
||||
ssh-keygen -t ed25519 -N "" -f /home/browserwake/.ssh/browserwake_key
|
||||
|
||||
# WICHTIG: Optionen und Schlüssel MÜSSEN auf einer einzigen Zeile stehen!
|
||||
PUBKEY=$(cat /home/browserwake/.ssh/browserwake_key.pub)
|
||||
echo "no-port-forwarding,no-x11-forwarding,no-agent-forwarding,command=\"/usr/local/bin/start-browser-desktop.sh\" ${PUBKEY}" \
|
||||
> /home/browserwake/.ssh/authorized_keys
|
||||
|
||||
apt-get install -y sudo
|
||||
cat > /etc/sudoers.d/browserwake <<'EOF'
|
||||
browserwake ALL=(root) NOPASSWD: /usr/sbin/pct start 102
|
||||
EOF
|
||||
chmod 440 /etc/sudoers.d/browserwake
|
||||
```
|
||||
|
||||
`/usr/local/bin/start-browser-desktop.sh`:
|
||||
```bash
|
||||
#!/usr/bin/env bash
|
||||
sudo /usr/sbin/pct start 102
|
||||
echo "Management-Desktop (CT102) gestartet (oder lief bereits)."
|
||||
```
|
||||
|
||||
Neue Guacamole-SSH-Verbindung "Management-Desktop starten" (`hostname=<LAN_IP_PVE>`, `port=22`, `username=browserwake`, `private-key`, `command=/usr/local/bin/start-browser-desktop.sh`) — gleicher Aufbau wie "Wake PC1". Nutzung: erst diese Verbindung anklicken (paar Sekunden warten), danach die normale "Management-Desktop (Browser)"-VNC-Verbindung öffnen.
|
||||
|
||||
⚠️ **NICHT TUN:** Optionen (`no-port-forwarding,...,command="..."`) und den Public-Key-String auf zwei separate Zeilen in `authorized_keys` schreiben (z.B. weil man die Optionen erst per `echo` schreibt und den Key danach per `>>` anhängt). SSHs Format verlangt **beides auf einer Zeile** — zwei Zeilen ergeben eine kaputte erste Zeile (wird ignoriert) und einen **komplett unrestriktiven** zweiten Schlüssel ohne jede Einschränkung. Beim ersten Testlauf genau so passiert und erst durch einen expliziten Test (`ssh -i key user@host "beliebiger befehl"` — führte den beliebigen Befehl aus statt des erzwungenen Skripts) aufgefallen. Nach jeder `authorized_keys`-Änderung mit forced command **immer** gegentesten: ein beliebiger Befehl darf niemals durchkommen.
|
||||
|
||||
`pct` erfordert Root-Rechte — ein unprivilegierter Linux-User kann es nicht direkt aufrufen (`pct: command not found` bzw. Permission-Fehler). Deshalb die eng begrenzte `sudo`-Regel nur für exakt `pct start 102`, nicht für `pct` allgemein.
|
||||
|
||||
### Auto-Stop bei Inaktivität
|
||||
|
||||
`/usr/local/bin/browser-desktop-idle-check.sh`, Cron alle 5 Minuten. Finale Version prüft die tatsächliche **X11-Eingabe-Idle-Zeit** (`xprintidle`, direkt im Container gemessen) statt eines Verbindungsstatus:
|
||||
|
||||
```bash
|
||||
IDLE_THRESHOLD_MS=900000 # 15 Minuten
|
||||
STATUS=$(/usr/sbin/pct status 102 2>/dev/null | awk '{print $2}')
|
||||
[ "$STATUS" != "running" ] && exit 0
|
||||
|
||||
IDLE_MS=$(/usr/sbin/pct exec 102 -- env DISPLAY=:1 XAUTHORITY=/root/.Xauthority xprintidle 2>/dev/null)
|
||||
case "$IDLE_MS" in ''|*[!0-9]*) exit 0 ;; esac
|
||||
|
||||
if [ "$IDLE_MS" -ge "$IDLE_THRESHOLD_MS" ]; then
|
||||
/usr/sbin/pct shutdown 102 --timeout 30
|
||||
# + ntfy-Push
|
||||
fi
|
||||
```
|
||||
|
||||
**Vorgeschichte — drei verworfene Verbindungsstatus-Ansätze, bevor die eigentliche Ursache klar wurde:**
|
||||
|
||||
⚠️ **NICHT TUN (erste Version):** Aktive Verbindung per `pct exec 102 -- ss ...` **innerhalb** des Containers prüfen — die eingehende Verbindung ist dort nicht sichtbar, wohl aber vom PVE-Host aus (unter der Tailscale-IP des Containers).
|
||||
|
||||
⚠️ **NICHT TUN:** Auch die host-seitige `ss`-Prüfung auf Port 5901 ist nicht zuverlässig. Reale Beobachtung: eine Guacamole-Sitzung endete laut eigener `guacamole_connection_history`-Tabelle sauber nach 15 Sekunden — `ss` zeigte aber über Stunden weiterhin ESTABLISHED. Vermutlich hält `guacd` die Backend-Verbindung länger offen als die Nutzer-Sitzung dauert.
|
||||
|
||||
⚠️ **NICHT TUN:** Guacamoles eigene History-Tabelle (`end_date IS NULL` = aktive Sitzung) abfragen — es gab verwaiste Einträge ohne `end_date` von nie sauber beendeten alten Sitzungen, nicht von einer echten laufenden Sitzung unterscheidbar.
|
||||
|
||||
Direkter Check im `guacd`-Container selbst (`docker exec guacd netstat -tn`) war technisch die zuverlässigste der drei TCP-Varianten — **hatte aber einen grundsätzlichen, nicht behebbaren blinden Fleck:** eine offene Verbindung sagt nichts darüber aus, ob der Nutzer gerade AFK ist. Bleibt der Guacamole-Tab offen und der Nutzer geht weg, bleibt die TCP-Verbindung bestehen — der Auto-Stop hätte nie ausgelöst. Erst ein Live-Test (Nutzer bewusst AFK mit offenem Tab) deckte das auf.
|
||||
|
||||
⚠️ **NICHT TUN (zusätzlicher Bug, unabhängig vom obigen):** `pct` ohne absoluten Pfad aufrufen. Cron läuft mit `PATH=/usr/bin:/bin` (ohne `/usr/sbin`, wo `pct` liegt) — Aufrufe ohne absoluten Pfad schlagen unter Cron mit "not found" fehl, `STATUS` bleibt leer, das Skript nimmt den "läuft nicht"-Zweig und erreicht die eigentliche Prüfung nie. Gefunden durch gezieltes Nachstellen der Cron-Umgebung (`env -i ... PATH=/usr/bin:/bin`). Lektion: bei "funktioniert manuell, aber nicht unter Cron" immer zuerst die PATH-Differenz prüfen.
|
||||
|
||||
**Finale Lösung:** `xprintidle` misst die Zeit seit der letzten echten Maus-/Tastatur-Eingabe auf X11-Ebene, unabhängig vom Verbindungsstatus — löst das AFK-Problem strukturell und macht das bisherige Zähler-Statefile überflüssig (Idle-Zeit ist bereits selbst der Zustand).
|
||||
|
||||
**Verifikation:** Wake-Key-Test (erzwungener Befehl + Port-Forwarding) bestanden. Auto-Stop unter simulierter Cron-Umgebung (minimaler PATH) mit künstlich niedrigem Threshold end-to-end getestet: Container wurde korrekt gestoppt.
|
||||
|
||||
### Screen-Lock nach 3 Min. Inaktivität (Enterprise-Richtlinie als Orientierung)
|
||||
|
||||
Zusätzlich zum Auto-Stop: die Desktop-Sitzung selbst soll sich sperren, wenn niemand aktiv ist — unabhängig vom Auto-Stop-Timer. `xautolock` ist nicht paketiert (Debian <DEBIAN_RELEASE>), daher ein eigener minimaler Watcher statt eines fertigen Tools.
|
||||
|
||||
⚠️ **NICHT TUN (erste Version):** `xtrlock` als Locker einsetzen. Funktional korrekt, aber `xtrlock` ist ein reines Xlib-Programm ohne jede Unterstützung für die X-Zwischenablage — entsperren geht nur durch **blindes Eintippen** des Passworts, ein Paste aus einem Passwortmanager (`xdotool key ctrl+v` gegen den laufenden Lock getestet) hat nachweislich **keine** Wirkung. Für ein starkes, zufälliges Passwort aus dem Passwortmanager unpraktikabel. `i3lock`/`slock` sind dieselbe Xlib-Keygrab-Familie (Debian-Tag `uitoolkit::xlib`) und hätten dieselbe Einschränkung.
|
||||
|
||||
⚠️ **NICHT TUN (zweiter Versuch):** `xfce4-screensaver` (GTK-basiert, `uitoolkit::gtk`, unterstützt Paste in der Theorie) als Ersatz einsetzen. In dieser konkreten Umgebung (TigerVNC-Session ohne Display-Manager-Login, ohne `xfce4-power-manager`, `Xtigervnc` ohne DPMS-Extension) funktioniert weder die manuelle Sperr-Anweisung (`xfce4-screensaver-command --lock` hängt den Daemon auf, D-Bus-Anfragen laufen danach in einen Timeout) noch die automatische Idle-Auslösung (kein `xfce4-power-manager`, das das nötige Idle-Signal liefert). Der Daemon selbst crasht nicht, wird aber dauerhaft unresponsive — ein reales Risiko, den Desktop komplett gesperrt und unentsperrbar zu hinterlassen. Deshalb wieder deinstalliert.
|
||||
|
||||
**Finale Lösung:** ein minimaler, selbst geschriebener Python/Tkinter-Lock-Dialog (`python3-tk`) — echtes GUI-Textfeld, Paste funktioniert standardmäßig (`tkinter.Entry` unterstützt Strg+V ohne Zusatzaufwand), kein Display-Manager/D-Bus-Session-Dienst nötig.
|
||||
|
||||
`/usr/local/bin/gui-lock.py`:
|
||||
```python
|
||||
import tkinter as tk
|
||||
SECRET_FILE = "/root/.config/lock-secret"
|
||||
|
||||
def check_and_maybe_unlock(event=None):
|
||||
with open(SECRET_FILE) as f:
|
||||
secret = f.read().strip()
|
||||
if entry.get() == secret:
|
||||
root.destroy()
|
||||
else:
|
||||
entry.delete(0, tk.END)
|
||||
root.bell()
|
||||
|
||||
root = tk.Tk()
|
||||
root.attributes("-fullscreen", True)
|
||||
root.attributes("-topmost", True)
|
||||
root.configure(bg="black")
|
||||
root.config(cursor="none")
|
||||
label = tk.Label(root, text="Gesperrt — Passwort eingeben", fg="white", bg="black", font=("sans", 18))
|
||||
label.pack(pady=(300, 20))
|
||||
entry = tk.Entry(root, show="*", font=("sans", 18), width=30, justify="center")
|
||||
entry.pack()
|
||||
entry.bind("<Return>", check_and_maybe_unlock)
|
||||
entry.focus_force()
|
||||
root.wait_visibility() # sonst: "grab failed: window not viewable"
|
||||
root.grab_set_global()
|
||||
root.mainloop()
|
||||
```
|
||||
|
||||
Vergleichs-Passwort steht in `/root/.config/lock-secret` (chmod 600) — **kein** PAM/Linux-Account-Passwort, eigenständiges Secret nur für diesen Lock. Dadurch komplett unabhängig vom Root-Account, kein SSH-Bezug, keine PAM-Komplexität.
|
||||
|
||||
`/usr/local/bin/lock-on-idle.sh`:
|
||||
```bash
|
||||
#!/bin/sh
|
||||
THRESHOLD_MS=180000 # 3 Minuten
|
||||
while true; do
|
||||
IDLE=$(xprintidle 2>/dev/null || echo 0)
|
||||
[ "$IDLE" -ge "$THRESHOLD_MS" ] && python3 /usr/local/bin/gui-lock.py
|
||||
sleep 10
|
||||
done
|
||||
```
|
||||
|
||||
`/root/.config/tigervnc/xstartup`:
|
||||
```sh
|
||||
#!/bin/sh
|
||||
unset SESSION_MANAGER
|
||||
unset DBUS_SESSION_BUS_ADDRESS
|
||||
/usr/local/bin/lock-on-idle.sh &
|
||||
exec startxfce4
|
||||
```
|
||||
|
||||
⚠️ **NICHT TUN:** `root.grab_set_global()` direkt nach dem Erstellen des Fensters aufrufen — Tk wirft `TclError: grab failed: window not viewable`, weil das Fenster vom Window-Manager noch nicht gemappt wurde. Vorher `root.wait_visibility()` aufrufen.
|
||||
|
||||
**Verifikation:** Watcher-Loop mit künstlich niedrigem Threshold end-to-end getestet — löst automatisch aus, ohne manuellen Aufruf. Entsperren per `xdotool`-simuliertem Strg+V-Paste (aus der X-Zwischenablage) erfolgreich getestet. Gegentest mit falschem Passwort bestätigt: Lock bleibt bestehen. Getipptes (nicht eingefügtes) Passwort funktioniert weiterhin normal.
|
||||
|
||||
## Verifikation
|
||||
|
||||
```bash
|
||||
|
|
|
|||
Loading…
Reference in a new issue