Zum Inhalt

Demo-Video bereitstellen

Die öffentliche Seite /video spielt das LLARS-Demo-Video /videos/llars_demo.mp4 ab. Die Datei ist rund 88 MB groß und liegt bewusst weder im Repository noch im Frontend-Image (git- und dockerignored). nginx liefert sie direkt aus einem Verzeichnis auf dem Host aus. Auf einem neuen Host, und immer wenn /videos/llars_demo.mp4 mit 404 antwortet, wird sie einmalig von Hand abgelegt.

Woran man das Problem erkennt

/video zeigt die Hinweiskarte „Das Video kann gerade nicht geladen werden" mit dem YouTube-Backup, curl -I …/videos/llars_demo.mp4 liefert 404 Not Found (nginx-Fehlerseite, text/html, 146 Bytes), und der Smoke-Test meldet WARNING: Demo-Video fehlt auf dem Host.


Wo die Datei liegt

Was Wert
Host-Pfad (Standard) /var/llars-static/videos/llars_demo.mp4
Variable LLARS_STATIC_DIR in /var/llars/.env (Standard /var/llars-static)
Pfad im nginx-Container /srv/llars-static/videos/ (read-only)
Mount docker-compose.prod.yml (Production) und docker-compose.staging.yml (Staging :55080)
nginx location /videos/ in nginx.prod.conf (Port 80 und 443) und nginx.prod-no-ssl.conf
Quelle llars-frontend/public/videos/llars_demo.mp4 auf einem Entwicklerrechner

Warum außerhalb des Checkouts

Bis zum 02.10.2026 mountete docker-compose.prod.yml das Video aus ./static/videos, also aus /var/llars/static/videos im Checkout. Jeder Deploy räumt den Checkout mit git reset --hard und git clean -fd auf, und git clean entfernt alles Unversionierte, das nicht ignoriert ist. Weil deploy_bluegreen.sh bei jedem Deploy die versionierte docker/nginx/active_upstream.conf umschreibt, lief das Aufräumen praktisch immer. Auf Production war das Verzeichnis deshalb leer, mit dem Zeitstempel des nächtlichen Deploys (02:22).

Seitdem liegt der Standard unter /var/llars-static, wo weder ein git clean (auch nicht mit -x) noch ein frischer Checkout hinreicht. /static/ steht zusätzlich in .gitignore, und die Skripte schließen static/ beim git clean aus, damit auch der alte Pfad nicht mehr geleert wird.

Blue-Green

Blue und Green teilen sich einen Checkout unter /var/llars; die Farben unterscheiden nur Container-Namen und Compose-Projekte. Der nginx-Container (llars_nginx_service) gehört zu keiner Farbe. Es gibt daher genau ein Video-Verzeichnis, und ein Farbwechsel ändert nichts daran.


Datei ablegen

/var/llars-static liegt unter /var und braucht beim ersten Anlegen Root-Rechte. Ohne sudo geht das über einen kurzlebigen Container, wie ihn auch deploy_bluegreen.sh für chown nutzt (Docker legt das fehlende Host-Verzeichnis beim -v selbst an). Vom Entwicklerrechner aus (SSH-Alias llars für Production, llars-dev für kia-dev; für beide ist VPN nötig):

scp llars-frontend/public/videos/llars_demo.mp4 llars:/tmp/llars_demo.mp4
ssh llars 'docker run --rm \
  -v /tmp/llars_demo.mp4:/src/llars_demo.mp4:ro \
  -v /var/llars-static:/dst \
  alpine:3.19 sh -c "mkdir -p /dst/videos \
    && cp /src/llars_demo.mp4 /dst/videos/llars_demo.mp4 \
    && chmod 755 /dst /dst/videos && chmod 644 /dst/videos/llars_demo.mp4" \
  && rm -f /tmp/llars_demo.mp4'

Mit sudo auf dem Host geht es auch direkt:

sudo install -D -m 0644 /tmp/llars_demo.mp4 /var/llars-static/videos/llars_demo.mp4
sudo chmod 755 /var/llars-static /var/llars-static/videos

Die Rechte sind wichtig: Der nginx-Worker läuft im Container als Benutzer nginx und braucht Leserechte auf Datei (644) und Verzeichnisse (755).

Einmalig nach der Umstellung vom 02.10.2026

Wer das Video vorher nach /var/llars/static/videos/ gelegt hat, muss es einmal nach /var/llars-static/videos/ legen. Am besten geschieht das schon vor dem Deploy, der die Umstellung bringt; dann gibt es keine Lücke. Nach dem Deploy prüfen, ob nginx den neuen Pfad eingehängt hat:

docker inspect llars_nginx_service \
  --format '{{range .Mounts}}{{.Source}} -> {{.Destination}}{{"\n"}}{{end}}' | grep videos

Zeigt das noch /var/llars/static/videos, den nginx-Container neu erstellen (Befehl unten). Danach kann die alte Kopie unter /var/llars/static/ weg.

Optional: schneller Start im Browser

In der aktuellen Datei steht der moov-Block (Metadaten) am Ende. Browser holen ihn per Range-Request nach, das funktioniert, kostet auf langsamen Verbindungen aber Zeit. Mit ffmpeg -i llars_demo.mp4 -c copy -movflags +faststart llars_demo_fast.mp4 wandern die Metadaten nach vorn, ohne neu zu kodieren.


Prüfen

# Auf dem Host (emuliert das FH-Gateway, das per HTTP auf Port 80 weiterleitet)
curl -sI -H "X-Forwarded-Proto: https" http://localhost/videos/llars_demo.mp4

# Von außen
curl -sI https://llars.e-beratungsinstitut.de/videos/llars_demo.mp4

# Range-Streaming (Vorspulen, Safari/iOS): erwartet 206 Partial Content
curl -s -o /dev/null -r 0-0 -w '%{http_code} %{content_type}\n' \
  https://llars.e-beratungsinstitut.de/videos/llars_demo.mp4

Erwartet werden 200 OK (bzw. 206 beim Range-Request), Content-Type: video/mp4 und Accept-Ranges: bytes.

Derselbe Check läuft in jedem Smoke-Test (scripts/ci/smoke_test_demo_video.sh, aufgerufen aus smoke_test.sh). Fehlt die Datei, meldet er eine Warnung mit dem Ablagepfad und lässt den Job grün, denn ein Rollback brächte die Datei nicht zurück. Mit SMOKE_STRICT_VIDEO=1 wird er zum harten Fehler:

SMOKE_STRICT_VIDEO=1 BASE_URL=http://localhost bash scripts/ci/smoke_test_demo_video.sh

Wenn die Datei auf dem Host liegt, nginx aber weiter 404 liefert

Zwei Ursachen sind möglich. Entweder hängt der laufende Container noch den alten Pfad ein (siehe Kasten oben), oder das Verzeichnis wurde gelöscht, während nginx lief; dann zeigt der Bind-Mount noch auf das gelöschte Verzeichnis. In beiden Fällen sieht der Container die Datei nicht:

docker exec llars_nginx_service ls -la /srv/llars-static/videos/

Fehlt sie dort, wird der nginx-Container mit demselben Befehl neu erstellt, den auch deploy_bluegreen.sh verwendet (er hängt dabei die aktuelle active_upstream.conf ein, die aktive Farbe bleibt):

cd /var/llars
docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d --no-deps --force-recreate nginx-service

Staging (:55080) bekommt den Mount beim nächsten deploy_bluegreen.sh deploy.


Datei ersetzen

Eine neue Fassung wird unter demselben Namen abgelegt. nginx liefert das Video mit expires 7d aus; Browser, die es schon geladen haben, können die alte Fassung bis zu sieben Tage aus dem Cache zeigen.