281 lines
12 KiB
Markdown
281 lines
12 KiB
Markdown
# 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 |
|