2. Februar 20200
Invidious auf einem Uberspace einrichten
Sprache:Crystal - OS:Uberspace
Wie viele große moderne Webseiten ist auch YouTube vollgepackt mit JavaScript-Code, der Besucherinnen ausspäht, ausbremst, nervt, mit Werbung bombadiert und viel zu viele Ressourcen (Speicher, CPU) auf dem Client verbraucht. Außerdem ist so eine JavaScript-basierte Benutzeroberfläche oft noch nicht mal besonders komfortabel zu bedienen.
Glücklicherweise gibt es mit Invidious eine alternative Benutzeroberfläche für YouTube, die als Open-Source-Projekt entwickelt wird. In diesem Artikel stelle ich vor, wie man diese Proxy-artige Software auf einem Uberspace einrichtet und betreibt.
Leider ist die offizielle Installationsanleitung für Invidious ohne Root-Rechte nicht brauchbar. Da Accounts auf Uberspace einfache User-Accounts auf einem Multiuser-System sind, müssen wir alle Abhängigkeiten aus verschiedenen Quellen zusammensuchen und im Benutzerverzeichnis unterbringen.
Zuerst installieren wir PostgreSQL nach der Anleitung auf lab.uberspace.de. Anschließend beziehen wir eine CA-Zertifikat-Datei [1], die Invidious für die SSL-verschlüsselte Kommunikation mit den Google-Servern benötigen wird:
$ mkdir -p $HOME/etc/openssl/certs/ $ cd $HOME/etc/openssl/certs $ wget http://curl.haxx.se/ca/cacert.pem
Jetzt beziehen wir einen aktuellen Checkout des Invidious-Quellcodes, damit wir im Nachfolgenden die jeweils benötigten Versionen der externen Pakete auslesen können:
$ git clone https://github.com/iv-org/invidious $HOME/opt/invidious
Die benötigte Version der Programmiersprache Crystal bestimmen wir mit diesem Befehl:
$ grep "crystal:" $HOME/opt/invidious/shard.yml
crystal: <VERSION>
Seit geraumer Zeit steht hier leider nur noch, dass irgendwas zwischen 1.0.0 und 2.0.0 benötigt wird. In Wirklichkeit ergibt sich aus den Konversationen auf GitHub, dass doch bestimmte Versionen benötigt werden. Im März 2022 wurde beispielsweise Version 1.2.2 empfohlen, und mit Version 1.3 sind Probleme bekannt.
Der Download erfolgt dann aus dem offiziellen Repository:
$ mkdir $HOME/build $ cd $HOME/build $ wget https://github.com/crystal-lang/crystal/releases/download/<VERSION>/crystal-<VERSION>-1-linux-x86_64.tar.gz $ tar xvf crystal-<VERSION>-1-linux-x86_64.tar.gz $ mv crystal-<VERSION>-1 $HOME/opt/crystal
Damit wir nicht alle weiteren Abhängigkeiten selber kompilieren müssen, setzen wir eine Anaconda-Umgebung auf und installieren dort vorkompilierte Pakete:
$ wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh $ bash Miniconda3-latest-Linux-x86_64.sh $ $ # an dieser Stelle einmal ausloggen und wieder einloggen! (base) $ (base) $ conda create -n invidious python=3.7 (base) $ conda activate invidious (invidious) $ conda install -c conda-forge libunwind librsvg (invidious) $ conda install pyyaml go openssl libevent cmake gxx_linux-64 gcc_linux-64 (invidious) $ mkdir -p $CONDA_PREFIX/etc/conda/activate.d/ (invidious) $ mkdir -p $CONDA_PREFIX/etc/conda/deactivate.d/ (invidious) $ cat > $CONDA_PREFIX/etc/conda/activate.d/set_vars.sh << EOF export OLD_LD_LIBRARY_PATH=\${LD_LIBRARY_PATH} export LD_LIBRARY_PATH=\$CONDA_PREFIX/lib:\${LD_LIBRARY_PATH} export LD_LIBRARY_PATH=\$HOME/opt/crystal/lib:\${LD_LIBRARY_PATH} export OLD_PATH=\${PATH} export PATH=\$HOME/opt/crystal/bin/:\${PATH} export OLD_PKG_CONFIG_PATH=\${PKG_CONFIG_PATH} export PKG_CONFIG_PATH=\$CONDA_PREFIX/lib/pkgconfig:\${PKG_CONFIG_PATH} export SSL_CERT_FILE=\$HOME/etc/openssl/certs/cacert.pem EOF (invidious) $ cat > $CONDA_PREFIX/etc/conda/deactivate.d/set_vars.sh << EOF export LD_LIBRARY_PATH=\${OLD_LD_LIBRARY_PATH} unset OLD_LD_LIBRARY_PATH export PATH=\${OLD_PATH} unset OLD_PATH export PKG_CONFIG_PATH=\${OLD_PKG_CONFIG_PATH} unset OLD_PKG_CONFIG_PATH EOF (invidious) $ conda deactivate (base) $ conda activate invidious (invidious) $
Die Bibliotheken lsquic
und boringssl
, die Invidious verwendet, um Kompatibilitätsprobleme mit der von YouTube verwendeten SSL-Verschlüsselung zu lösen, müssen wir leider selbst kompilieren.
Die benötigte lsquic
-Version ermitteln wir mit diesem Befehl
(invidious) $ grep -A2 "lsquic:" $HOME/opt/invidious/shard.yml lsquic: github: iv-org/lsquic.cr version: ~> <LSQUIC-VERSION>
Dann beziehen wir den Quellcode von lsquic
in der eben ermittelten Version und bestimmen darüber die benötigte Version von boringssl
in Form eines Hashes:
(invidious) $ git clone https://github.com/litespeedtech/lsquic $HOME/build/lsquic (invidious) $ cd $HOME/build/lsquic (invidious) $ git checkout v<LSQUIC-VERSION> (invidious) $ grep "git checkout" $HOME/build/lsquic/README.md git checkout <BORINGSSL-HASH>
Dann beziehen und kompilieren wir boringssl
:
(invidious) $ git clone https://boringssl.googlesource.com/boringssl $HOME/build/boringssl (invidious) $ cd $HOME/build/boringssl (invidious) $ git checkout <BORINGSSL-HASH> (invidious) $ export C_FLAGS="-DSO_RXQ_OVFL=40 -D__STDC_FORMAT_MACROS -D__STDC_CONSTANT_MACROS -I$CONDA_PREFIX/include -L$CONDA_PREFIX/lib" (invidious) $ cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_FLAGS="$C_FLAGS" -DCMAKE_C_FLAGS="$C_FLAGS" . (invidious) $ make ssl crypto
Weiter geht's mit der Kompilierung von lsquic
:
(invidious) $ cd $HOME/build/lsquic (invidious) $ git submodule update --init (invidious) $ cmake -DCMAKE_BUILD_TYPE=Release -DBORINGSSL_DIR="$HOME/build/boringssl" -DCMAKE_C_FLAGS="$C_FLAGS" . (invidious) $ make lsquic
Dann installieren wir noch ein paar letzte Abhängigkeiten:
(invidious) $ cd $HOME/opt/invidious (invidious) $ shards install && shards update (invidious) $ cp $HOME/build/boringssl/{ssl,crypto}/*.a $HOME/build/lsquic/src/liblsquic/*.a lib/lsquic/src/lsquic/ext/ (invidious) $ crystal run scripts/fetch-player-dependencies.cr
Jetzt können wir endlich Invidious kompilieren:
(invidious) $ cd $HOME/opt/invidious (invidious) $ crystal build src/invidious.cr --threads 1 --progress -Dskip_videojs_download --link-flags "-L$HOME/build/boringssl/ssl -L$HOME/build/boringssl/crypto -I$CONDA_PREFIX/include -L$CONDA_PREFIX/lib"
Der Kompiliervorgang von Invidious wird auf Uberspace oft frühzeitig getötet, weil er zu viel RAM benutzt. Es hilft, alle parallelen SSH-Sitzungen zu beenden und laufende supervisor-Dienste vorübergehend anzuhalten. Dann muss der Kompilierbefehl eventuell mehrmals ausgeführt werden, bevor er erfolgreich abschließt, ohne getötet zu werden.
Bevor es losgehen kann, muss noch die PostgreSQL-Datenbank invidious
mit dem Benutzer kemal
(Passwort merken!) vorbereitet werden:
(invidious) $ cd $HOME/opt/invidious (invidious) $ createuser -P kemal (invidious) $ createdb -O kemal invidious (invidious) $ psql invidious kemal < ./config/sql/channels.sql (invidious) $ psql invidious kemal < ./config/sql/videos.sql (invidious) $ psql invidious kemal < ./config/sql/channel_videos.sql (invidious) $ psql invidious kemal < ./config/sql/users.sql (invidious) $ psql invidious kemal < ./config/sql/session_ids.sql (invidious) $ psql invidious kemal < ./config/sql/nonces.sql (invidious) $ psql invidious kemal < ./config/sql/annotations.sql (invidious) $ psql invidious kemal < ./config/sql/playlists.sql (invidious) $ psql invidious kemal < ./config/sql/playlist_videos.sql
Das beim Anlegen von kemal
gewählte Passwort tragen wir jetzt zusammen mit unserer Domain bzw. Subdomain in die Konfigurationsdatei config/config.yml
im Invidious-Verzeichnis ein. Wenn die Datei noch nicht existiert erstellen wir sie als Kopie von config/config.example.yml
:
channel_threads: 1 feed_threads: 1 db: user: kemal password: <PostgreSQL-DB-Password> host: localhost port: 5432 dbname: invidious full_refresh: false https_only: false domain: <Domain> login_enabled: false registration_enabled: false
Die letzten zwei Zeilen sind optional und deaktivieren die Benutzeranmeldung und -registrierung.
Invidious soll im Produktivbetrieb als Hintergrundprozess laufen, was wir mit supervisord
sicherstellen können. Dazu legen wir die Datei $HOME/etc/services.d/invidious.ini
mit dem folgenden Inhalt an:
[program:invidious] command=%(ENV_HOME)s/opt/invidious/invidious.sh stdout_logfile=%(ENV_HOME)s/logs/invidious.out.log stdout_logfile_maxbytes=1MB stdout_logfile_backups=0 stderr_logfile=%(ENV_HOME)s/logs/invidious.err.log stderr_logfile_maxbytes=1MB stderr_logfile_backups=0 autostart=yes autorestart=yes stopasgroup=true stopsignal=QUIT
Wir rufen nicht direkt die Invidious-Binary auf, sondern ein Wrapper-Skript, das einige Umgebungsvariablen setzt. Dazu legen wir die Datei $HOME/opt/invidious/invidious.sh
mit dem folgenden Inhalt an (wir denken daran, das Skript mit chmod +x
ausführbar zu machen!):
#!/usr/bin/bash source $HOME/miniconda3/etc/profile.d/conda.sh conda activate invidious cd $HOME/opt/invidious ./invidious
Schließlich können wir den Prozess mit supervisorctl reread
starten und den Status mit supervisorctl status
überprüfen.
Wenn alles gut gegangen ist, lauscht Invidious jetzt auf Port 3000. Damit das auch von draußen sichtbar ist, richten wir mit uberspace web backend set / --http --port 3000
einen entsprechenden Reverse-Proxy ein.
Invidious lässt sich übrigens besonders komfortabel in Kombination mit der Firefox-Erweiterung Privacy Redirect verwenden. Dort lässt sich auch die alternative Twitter-Oberfläche Nitter aktivieren, die ich in einem weiteren Artikel vorstelle.