# LTX DeskWEB manuell mit Docker installieren Diese Anleitung installiert das fertige **Web-Frontend** auf Debian/Linux amd64. Auf dem Zielserver wird nichts kompiliert. Athena Deck muss die GUI nicht selbst installieren: Die zwei unten genannten Labels machen sie in „Weitere Dienste“ sichtbar. ## Voraussetzungen und Aufbau - Docker Engine ist installiert und läuft. Für die optionale Compose-Variante zusätzlich ein aktuelles Docker-Compose-Plugin verwenden. - Ein eingerichtetes LTX-Desktop-Backend ist separat vorhanden. Bei Verwendung von Athena Deck stellt dessen API-Port im Videomodus die native LTX-API bereit. - GUI und LTX-Backend sehen dieselben Eingabe- und Ausgabedateien. Nur eine API-Adresse genügt nicht, da die native LTX-API Server-Dateipfade verwendet. - Der gewünschte GUI-Port ist frei. Das Beispiel verwendet Port **8118**. Die GUI braucht keine GPU-Freigabe, NVIDIA-Runtime oder Docker-Socket. Das Image enthält den Webdienst und ffmpeg für Medienvorschauen, keine Modellgewichte. Die folgenden Serverbefehle als root ausführen. Sie entsprechen Athenas aktueller LTX-Pfadstruktur; auf einem anderen Server die Pfade und Benutzergruppen anpassen. ## 1. Fertiges Image herunterladen Falls das Paket einen Login verlangt: ```sh docker login git.casaderoll.de --username michael ``` Passwort bzw. Token interaktiv eingeben. Für den Download genügen Paket-Leserechte. Dann: ```sh docker pull git.casaderoll.de/michael/ltx-deskweb:0.1.0-9ff96db ``` Das Image enthält die Korrekturen für Upload-Rechte und Browser-Höhe. Version und geprüfter Digest stehen in [CONTAINER_REGISTRY.md](CONTAINER_REGISTRY.md). ## 2. Volumes und Zugriffsrechte vorbereiten | Hostpfad im Athena-Beispiel | Pfad im GUI-Container | Zugriff / Zweck | | --- | --- | --- | | `/data/video/ltx-desktop/LTXDesktop/remote-inputs/deskweb` | `/data/inputs` | Lesen/Schreiben: Uploads, importierte Dateien, Vorschaubilder | | `/data/video/ltx-desktop/LTXDesktop/outputs` | `/data/outputs` | Nur Lesen: Ergebnisse des LTX-Backends | | `/opt/ltx-deskweb/secrets/web-password` | `/run/secrets/web_password` | Nur Lesen: Kennwort für die Web-GUI | | `/opt/ltx-deskweb/secrets/ltx-token` | `/run/secrets/ltx_token` | Nur Lesen: API-Token des angesprochenen Backends/Deck-Endpunkts | Die unten beschriebenen Pfade unter `/opt/ltx-deskweb/secrets` sind ein Beispiel für **neue manuelle Installationen**. Die bereits ausgerollte Athena-Instanz verwendet `/opt/ltx-deskweb/source/secrets`; deren Betriebsanleitung steht in [ATHENA_DEPLOYMENT.md](ATHENA_DEPLOYMENT.md). Keine zweite Instanz mit demselben Container-Namen oder Port starten. Nur für die neue Einrichtung: ```sh install -d -m 700 /opt/ltx-deskweb/secrets install -d -o 1000 -g 0 -m 2750 \ /data/video/ltx-desktop/LTXDesktop/remote-inputs/deskweb test -d /data/video/ltx-desktop/LTXDesktop/outputs ``` Der letzte Befehl muss erfolgreich sein. Andernfalls zuerst die tatsächliche Ausgabeablage des LTX-Backends klären, nicht einfach einen leeren Ersatzordner anlegen. Vorhandene Modell-/Medienverzeichnisse nicht rekursiv umberechtigen. **Warum UID 1000 / GID 0?** Die GUI läuft ohne root-UID als Benutzer 1000. Athenas LTX-Backend läuft als UID/GID 0, aber ohne Linux-Capabilities. Es kann deshalb private Dateien eines anderen Benutzers nicht automatisch lesen. Der neue Input-Ordner ist gruppenlesbar und hat das Setgid-Bit (`2750`); neue Dateien erben GID 0 und erhalten `0640`. So können beide Dienste dieselben Uploads lesen. Bei anderer Backend-Identität eine passende gemeinsame Gruppe verwenden. Auch LTX-Ausgaben müssen für die GUI lesbar sein; der Mount bleibt read-only. Zuordnung zum **LTX-Container**, nicht zur GUI: | GUI-Pfad | Derselbe Inhalt aus Sicht des LTX-Backends | | --- | --- | | `/data/inputs` | `/data/LTXDesktop/remote-inputs/deskweb` | | `/data/outputs` | `/data/LTXDesktop/outputs` | Diese zweite Spalte wird mit `BACKEND_INPUT_DIR` und `BACKEND_OUTPUT_DIR` gesetzt. Bei Athena bindet LTX `/data/video/ltx-desktop` vom Host als `/data` ein. Bei anderen Mounts müssen die Backend-Pfade entsprechend angepasst werden. ## 3. Kennwort und API-Token hinterlegen Zwei getrennte Dateien verwenden: - `web-password`: eigenes GUI-Kennwort, mindestens 16 Zeichen. - `ltx-token`: vorhandener API-Token von **Athena Deck**, wenn die URL auf Deck zeigt. Beim direkten LTX-Zugriff stattdessen dessen Token. Nur bei einem Backend ohne Authentifizierung darf diese Datei leer sein. Das folgende interaktive Beispiel schreibt keine Secrets in die Shell-Historie und überschreibt keine vorhandenen Dateien: ```sh python3 - <<'PY' import getpass, os from pathlib import Path root = Path('/opt/ltx-deskweb/secrets') if any((root / name).exists() for name in ('web-password', 'ltx-token')): raise SystemExit('Secret-Dateien existieren bereits; nichts überschrieben.') password = getpass.getpass('Neues GUI-Kennwort (mindestens 16 Zeichen): ') if len(password) < 16 or password != getpass.getpass('GUI-Kennwort wiederholen: '): raise SystemExit('Kennwort zu kurz oder Wiederholung stimmt nicht.') token = getpass.getpass('Vorhandener Deck-/LTX-API-Token: ') for name, value in [('web-password', password), ('ltx-token', token)]: fd = os.open(root / name, os.O_WRONLY | os.O_CREAT | os.O_EXCL, 0o400) with os.fdopen(fd, 'w') as stream: stream.write(value + '\n') os.chown(root / name, 1000, 0) PY ``` Secrets nicht ins Repository einchecken. Sie werden nur in den Container gemountet und bleiben außerhalb des Images. ## 4. Labels und Ports Für die Anzeige unter **Athena Deck → Weitere Dienste** sind beide Labels nötig: ```text io.athena-deck.managed=true io.athena-deck.role=application ``` Zusätzliche beschreibende Labels dieses Images: ```text org.ltx-deskweb.role=frontend org.ltx-deskweb.backend=ltx-desktop ``` Labels werden beim Erstellen des Containers gesetzt. Sie registrieren kein Modell und laden keine GPU-Laufzeit. Die GUI erscheint nur in der Docker-Instanz, die Deck abfragt; ein Container auf einem anderen Server wird dadurch nicht automatisch entdeckt. | Verbindung | Port / Bedeutung | | --- | --- | | Browser → Web-GUI | `8118` im Beispiel; frei wählbar | | Web-GUI → Athena Deck | `8120` im bestehenden Aufbau; die konfigurierte API-Adresse verwenden | | Web-GUI → LTX direkt (optional) | Tatsächlicher nativer LTX-Port, auf Athena derzeit `41955`; kein zusätzlicher GUI-Port | | Mac → Athena (SSH-Tunnel) | SSH-Port `22` auf Athena | Die folgende Variante verwendet **Host-Networking nur für diesen GUI-Container**. Damit erreicht sie Decks `127.0.0.1:8120`, ohne Decks Netzwerk zu verändern. `HOST=127.0.0.1` beschränkt den GUI-Zugriff auf Loopback. Es gibt bei Host-Networking keine `-p`-Portabbildung: `PORT` ist der tatsächlich auf dem Host belegte Port. ## 5. Container starten — ohne Build und ohne Git-Checkout Vorher z. B. mit `ss -ltn` prüfen, dass `8118` frei ist. ```sh docker run -d \ --name ltx-deskweb \ --restart unless-stopped \ --init \ --network host \ --user 1000:0 \ --read-only \ --cap-drop ALL \ --security-opt no-new-privileges:true \ --cpus 2 --memory 1g \ --tmpfs /tmp:size=128m,mode=1777 \ --label io.athena-deck.managed=true \ --label io.athena-deck.role=application \ --label org.ltx-deskweb.role=frontend \ --label org.ltx-deskweb.backend=ltx-desktop \ --env HOST=127.0.0.1 \ --env PORT=8118 \ --env PUBLIC_ORIGIN=http://127.0.0.1:8118 \ --env LTX_BACKEND_URL=http://127.0.0.1:8120 \ --env WEB_PASSWORD_FILE=/run/secrets/web_password \ --env LTX_TOKEN_FILE=/run/secrets/ltx_token \ --env LOCAL_INPUT_DIR=/data/inputs \ --env BACKEND_INPUT_DIR=/data/LTXDesktop/remote-inputs/deskweb \ --env LOCAL_OUTPUT_DIR=/data/outputs \ --env BACKEND_OUTPUT_DIR=/data/LTXDesktop/outputs \ --mount type=bind,src=/data/video/ltx-desktop/LTXDesktop/remote-inputs/deskweb,dst=/data/inputs \ --mount type=bind,src=/data/video/ltx-desktop/LTXDesktop/outputs,dst=/data/outputs,readonly \ --mount type=bind,src=/opt/ltx-deskweb/secrets/web-password,dst=/run/secrets/web_password,readonly \ --mount type=bind,src=/opt/ltx-deskweb/secrets/ltx-token,dst=/run/secrets/ltx_token,readonly \ git.casaderoll.de/michael/ltx-deskweb:0.1.0-9ff96db ``` Für Portainer/andere Container-Verwaltungen dieselben Labels, Umgebungsvariablen, Bind-Mounts, Benutzer- und Netzwerkeinstellungen übernehmen. ### Alternative: vorhandene Compose-Dateien verwenden Im geklonten Repository `.env` und `secrets/` gemäß README vorbereiten. Hier liegen Secrets relativ zum Repository, nicht im Pfad des obigen `docker run`-Beispiels. Die Werte für den dedizierten Input-Ordner inklusive `/deskweb` verwenden. ```sh docker compose -p ltx-deskweb -f compose.yaml -f compose.registry.yaml \ -f deploy/compose.athena.yaml pull ltx-deskweb docker compose -p ltx-deskweb -f compose.yaml -f compose.registry.yaml \ -f deploy/compose.athena.yaml up -d --no-build --no-deps ltx-deskweb ``` `compose.registry.yaml` entfernt den Build-Schritt; die Labels kommen aus `compose.yaml`. Nicht zusätzlich zur `docker run`-Variante starten. ### Alternative: Bridge-Netzwerk oder anderer Container-Stack Ohne `--network host` gilt: `HOST=0.0.0.0` im Container und beispielsweise `-p 127.0.0.1:8118:8118` für den Host. `LTX_BACKEND_URL` muss vom Container aus wirklich erreichbar sein: `127.0.0.1` bezeichnet dann die GUI selbst. `host.docker.internal` allein macht einen ausschließlich auf Host-Loopback gebundenen Backend-Port nicht erreichbar. Netzwerkzugang bewusst planen, nicht pauschal bestehende Backend-Bindings oder Firewallregeln ändern. Ein anderer Rechner benötigt zusätzlich Zugriff auf dieselben Medien, etwa über geeignet eingebundenen gemeinsamen Speicher. ## 6. Im Browser öffnen Auf dem Mac den Tunnel starten und das Terminal offen lassen: ```sh ssh -i /Users/mike_i386/.ssh/athena_key -o BatchMode=yes \ -o ExitOnForwardFailure=yes -N \ -L 8118:127.0.0.1:8118 root@192.168.1.212 ``` Dann [http://127.0.0.1:8118](http://127.0.0.1:8118) öffnen und das GUI-Kennwort verwenden. Die Anwendung läuft auf Athena; der Mac ist Browser und Tunnel-Client. Ist der Tunnel bereits offen, nicht noch einmal denselben Port belegen. `PUBLIC_ORIGIN` muss exakt zur verwendeten Browser-Adresse passen, einschließlich Schema und Port. Bei einer Domain mit HTTPS dort die tatsächliche HTTPS-Origin setzen und einen passenden Reverse Proxy verwenden. Die Anleitung richtet kein öffentliches Routing oder WireGuard ein. Unter Deck „Weitere Dienste“ aktualisieren: `ltx-deskweb` sollte erscheinen. Für Generierung **Video in Deck aktivieren**. Der GUI-Start selbst schaltet keine Modelle um und verändert den LTX-Dienst nicht. ## 7. Prüfen, stoppen, aktualisieren ```sh docker ps --filter name=ltx-deskweb curl --fail --output /dev/null http://127.0.0.1:8118/ docker ps -a --filter label=io.athena-deck.managed=true \ --filter label=io.athena-deck.role=application # Nur die GUI stoppen / wieder starten: docker stop ltx-deskweb docker start ltx-deskweb ``` Für Updates erst die neue geprüfte Image-Version herunterladen und dann nur den GUI-Container ersetzen. Vorher laufende Generierungen und die GUI-Verbindung berücksichtigen; ein Neustart beendet die Web-Sitzungen. Compose-Nutzer starten mit den gleichen drei Dateien erneut `up -d --no-build --no-deps ltx-deskweb`. Bei `docker run` muss der alte GUI-Container nach dem Stoppen entfernt und mit dem neuen Image neu angelegt werden. Die Bind-Mount-Daten bleiben erhalten. Details: [UPGRADE_INFO.md](UPGRADE_INFO.md). Projekte liegen in dieser Version im Browser. JSON-Backup in „Connection & information“ verwenden; ein Container-Backup allein sichert keine Browserprojekte. Medien und Secrets separat sichern. Ein Image enthält keine Nutzerdaten. ## Häufige Fehler | Meldung / Verhalten | Prüfen | | --- | --- | | `Image file not found` | Backend-Pfad, gleicher Hostordner in beiden Containern, Ordnerdurchquerung und Gruppen-Leserechte (`2750` / `0640`) | | GUI läuft, LTX nicht bereit | Deck im Videomodus? API-Port und Token korrekt? Backend erreichbar? | | `Cross-origin request rejected` | `PUBLIC_ORIGIN` stimmt exakt mit der Browser-URL überein | | Container fehlt in Deck | Beide `io.athena-deck.*`-Labels gesetzt und derselbe Docker-Host? | | Registry `unauthorized` | Login auf dem Rechner ausführen, der das Image pullt; Paket-Leserechte prüfen | | Port belegt | Freien `PORT` wählen; Tunnel und `PUBLIC_ORIGIN` ebenfalls anpassen. Bei Host-Networking hilft eine Änderung nur an `-p` nicht. | | Vorschau/Download nicht lesbar | Output-Mount und Dateirechte für UID 1000 / gemeinsame Gruppe prüfen |