Est-ce qu’on peut installer PeerTube sur OpenBSD ? Sans plus ?

Sans Nginx en fait.

Cet article n’est plus adéquat en dehors de la méthode d’installation. Je recommande l’utilisation de Nginx. Je garderais la partie sur Httpd+Relayd, quelqu’un pourrait la trouver utile.

Pourquoi ?

Plusieurs raisons pour ce questionnement :

  • Nginx n’est pas en Base.
  • On a des demons http en Base, pourrait-on s’en servir en lieu et place de Nginx ?
  • Ces démons sont concus avec la culture OpenBSD et utilisent ses améliorations successives, notamment pledge().
  • Nginx est, de ce que j’ai compris, vraiment un truc de plus en plus tordu.

Grosso modo, on a ce qu’il faut en base, pourquoi ne pas s’en servir. Qui plus est, Relayd va alors utiliser directement LibreSSL et donc on aura une connection TLS avec les tous derniers protocoles qui vont bien.

Incovénients

On utilisera TLS 1.3 (quand Nginx ne fournit que du 1.2 sur OpenBSD) mais on utilisera que http/1.1 quand Nginx délivre en http/2. C’est donc un mal pour un bien.

On doit transformer toute la configuration Nginx qui est fournie clé en main par le dévellopeur de PeerTube en une configuration relayd + httpd, ce qui est loin d’être simple.

Préliminaires

Je recommande la lecture des livres de Michael W Lucas pour OpenBSD, Relayd et TLS. Cela vous épargnera beaucoup de peine.

Ah aussi, ayez le manuel de relayd.conf ouvert. Non, serieux, ce truc est imbittable sans le manuel.

Je vais reprendre des morceaux importants des articles précédants pour décrire la procédure d’installation. L’avantage c’est que vous n’avez pas besoin d’aller les relire, sauf si vous voulez l’historique ou une explication plus poussée.

Installation / Upgrade

Vous devez installer PostgreSQL, Redis et nodejs. Là, pas moyen d’y echapper.

    doas pkg_add postgresql-contrib redis node python3 youtube-dl ffmpeg

N’oubliez pas d’aller vérifier la doc du port de PostgreSQL, ca sort pas tout seul du chapeau. IL FAUT BOSSER ! En même temps vous voulez monter une instance PeerTube, ce sera pas de tout repos des fois…

Il faut créer un utilisateur dédié.

    doas useradd -L daemon -d /var/www/peertube _peertube
    doas chown _peertube:_peertube /var/www/peertube
    doas -u _peertube mkdir /var/www/peertube/(versions|storage|config) 

Il est à noter que comme son nom l’indique storage contiendra les vidéos et tout le reste des données de l’instance hormis configuration et programme lui-même. Vous devriez peut-être le mettre sur un point de montage dédié. Avec une grosse partition. Une très grosse partition.

Ah au fait. PeerTube lui-même, le programme… il pèse dans les 700 Mo. Il requiert aussi de la place pour compiler et s’installer. De même que PostgreSQL, qui va allégrement depasser le gigaoctet. Donc n’oubliez pas de régulièrement faire de la place dans /var, virez les vieilles versions, vérifiez que les logs tournent et n’encombrent pas l’espace. On ne joue plus dans le petit bassin.

Je n’utilise pas le script d’upgarde de PeerTube. Le lien symbolique crée à la fin bug. Et node joue des tours avec /tmp.

Bon, reprenons. On télécharge la dernière version de PeerTube dans le repertoire kivabien.

    cd /var/www/peertube/versions
    doas -u _peertube wget https://github.com/Chocobozzz/PeerTube/releases/download/$VERSION/peertube-v$VERSION.zip
    doas -u _peertube unzip peertube-v$VERSION.zip

Ce paragraphe n’est pas adéquat. Installez le package yarn depuis les dépots openbsd (devel/yarn dans les ports). Yarn n’a pas besoin de /tmp/node.

Au cours de la compilation, npm/yarn va demander la présence du binaire node dans /tmp. Autant s’en occuper tout de suite. Et installer yarn.

    cd /tmp
    ln -s /usr/local/bin/node .
    doas npm install --global yarn

On peut maintenant compiler.

    cd /var/www/peertube/versions/peertube-v$VERSION
    doas -u _peertube yarn install --production --pure-lockfile

Ca tourne …

    yarn install v1.22.4
    [1/5] Validating package.json...
    warning peertube@3.1.0: The engine "postgres" appears to be invalid.
    warning peertube@3.1.0: The engine "redis-server" appears to be invalid.
    warning peertube@3.1.0: The engine "ffmpeg" appears to be invalid.
    [2/5] Resolving packages...
    warning Resolution field "oauth2-server@3.1.0-beta.1" is incompatible with requested version "oauth2-server@3.0.0"
    warning Resolution field "http-signature@1.3.5" is incompatible with requested version "http-signature@~1.2.0"
    ...
    [4/4] Building fresh packages...
    Done in 39.90s.
    Done in 60.43s.

Tada

N’oubliez pas de lier le dossier du programme comme suis.

    cd /var/www/peertube
    doas rm peertube-latest/ && doas ln -s versions/peertube-v$VERSION ./peertube-latest

Vous pouvez faire un lien vers la configuration par defaut. Oui, faire un lien logique dans un lien logique… L’avantage c’est que le defaut sera toujours celui de la version courante. Plus besoin de mettre cela à jour.

    ln -s /var/www/peertube/peertube-latest/config/default.yaml /var/www/peertube/config/default.yaml

Rcctl

Bon, il faut maintenant pouvoir démarrer PeerTube comme un démon normal. Ok. Accroche toi coco…

J’y suis jamais arrivé.

Donc j’ai fini par utiliser un hyperviseur Node, comme il en existe en PHP ou Python. . J’installe Pm2 suivant les instructions fournies dans la doc.

doas npm install pm2 -g

Je place un fichier ecosystem.config.js dans /etc/pm/. Et en fait, comme vous l’avez compris, c’est pm2 qui demarre. Pas PeerTube. Du moins pas encore.

module.exports = {
apps : [{
    name: 'peertube',
    cwd:  '/var/www/peertube/peertube-latest/',
    "listen_timeout" : 2000,
    env: {
        "USER":         "_peertube",
        "NODE_ENV":     "production",
        "HOME":         "/var/www/peertube/",
        "NODE_CONFIG_DIR": "/var/www/peertube/config/",
    },
    script: '/var/www/peertube/peertube-latest/dist/server',
    }, ]
};

Reste plus qu’à demarrer PM2 au boot via rcctl, comme n’importe quel autre démon.

Donc plaçons un fichier /etc/rc.d/peertube, et n’oublions pas de l’activer dans /etc/rc.conf.local :

#!/bin/ksh

daemon="/usr/local/bin/pm2"

daemon_user="_peertube"

. /etc/rc.d/rc.subr

pexp="node: PM2.*God Daemon.*"

rc_start() {
    ${rcexec} "${daemon} start /etc/pm/ecosystem.config.js"
}

rc_reload() {
    ${rcexec} "${daemon} reload /etc/pm/ecosystem.config.js"
}

rc_cmd $1    

Mais on ne peut pas encore démarrer le bidule puisqu’on a pas la conf’ http(s). PeerTube check lors de son initialisation qu’il arrive bien à trouver son propre serveur web obligatoirement en https. Donc maintenant, on s’y colle.

Httpd

Je ne recommande pas l’utilisation de Httpd+Relayd en lieu et place de Nginx. Cette installation crashe lors de l’envoi de video de grande taille.

La configuration du serveur web, httpd, est extrémement simple, puisqu’il ne sert que les fichiers statiques.

/etc/httpd.conf

server "tube.example.com" {
        listen on * port www

        location "/.well-known/acme-challenge/*" {
                root "/acme"
                request strip 2
        }
        location * {
                block return 302 "https://$HTTP_HOST$REQUEST_URI"
        }
}

server "tube.example.com" {
        listen on * port 8000

        root "/var/www/peertube/storage"

        location "/.well-known/acme-challenge/*" {
                root "/acme"
                request strip 2
        }
}

On observera que je ne redirige pas le challenge ACME en https. Ca correspond bien à mon installation avec Buypass.

C’est Relayd qui fait le boulot le plus compliqué. Et justement, on va s’y attaquer.

Relayd

Relayd va servir à terminer la connection TLS et à dispatcher les flux http en sortie

  • soit vers Httpd pour servir les contenus statiques
  • soit vers le serveur de peertube lui-même (vous voyez, celui qui écoute sur le port 9000 sur localhost)
  • en plus de cela on peut terminer la connection live en ipv6, ce qui n’est pas possible nativement.

On va analyser le relayd.conf, en partant d’en haut.

NB : comme décrit par M Lucas, les protocols sont avant les relais, qu’importe que cela ait du sens ou pas.

/etc/relayd.conf

    # Macros
    #
    ext4="192.0.2.10"
    ext6="2001:DB8:96b1::100"
    webhost="lo0"

    #
    # Global Options
    #
    # interval 10
    # timeout 1000
    # prefork 5

    #
    # Each table will be mapped to a pf table.
    #
    table <webhosts> { $webhost }
    table <apihosts> { 127.0.0.1 }

En tête de fichier, on indique, dans des macros, les adresses où arrivent les requêtes entrantes. Autrement dit : vos adresses publiques.

Les tables webhosts et apihosts peuvent effectivement être séparées. On peut par exemple faire tourner les démons peertube et httpd sur des hotes séparés. Par contre, le démon peertube écoute lui en priorité en ipv4 pour l’instant. D’où mon 127.0.0.1 dans apihosts. Je n’ai aucune idée de savoir s’il est possible d’utiliser de la repartition de charge (construire une grosse instance avec plusieurs serveurs en backend distribués via ces tables).

On présente le protocole rtmp pour pouvoir le relayer en ipv6 en toute fin du fichier.

    protocol rtmp {
            tcp { nodelay, sack, socket buffer 65536, backlog 128 }
    }

Bon, là on s’attaque vraiment au problème.

La première partie décrit les options génériques. Je me suis efforcé de reprendre les mêmes valeurs que la configuration fournie par PeerTube.

Les options tls keypair sont décrites dans le manuel. Que vous retournez lire de temps en temps hein… HEIN …

http websockets est important pour PeerTube.

La ligne de ciphers ne peut pas être remplacée par HIGH car apparement, on inclut des suites déclassées. Et aussi : il faut une seule ligne, pas plusieurs options et je n’ai pas reussi à faire de retour avec \ . Deal with it.

    http protocol https {
            match request header append "X-Forwarded-For"   value "$REMOTE_ADDR"
            match request header append "X-Forwarded-By"    value "$SERVER_ADDR:$SERVER_PORT"

            match response header set "Feature-Policy" value "camera 'none'; microphone 'none'"
            match response header set "Strict-Transport-Security" value "max-age=31536000"
            match response header set "X-Content-Type-Options" value "nosniff"

            # Various TCP options
            tcp { nodelay, sack, socket buffer 65536, backlog 128 }

            tls { tlsv1.3 tlsv1.2, ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384 }

            tls edh params auto
            tls keypair tube.example.com

            http websockets

Là, on va commencer à différencier les requêtes suivant leur destination. Je vais tenter de coller au mieux avec la configuration fournie par PeerTube. On pourrait certainement faire beaucoup plus. Le fichier de conf’ Nginx est bien plus granulaire. Il restreint par exemple les méthodes HTTP authorisées, ce que je n’arrive pas à faire.

            match request path "/api/v1/videos/upload" tag "UPLOAD"
            match response tagged "UPLOAD" header set "Access-Control-Allow-Methods" value "POST, HEAD"
            match response tagged "UPLOAD" header set "X-File-Maximum-Size 8G always"

            match request path "/client/*" tag "CLIENT"
            match response tagged "CLIENT" header set "Cache-Control" value "public, max-age=31536000, immutable"

            match request path "/static/*" tag "STATIC"
            match response tagged "STATIC" header set "Access-Control-Allow-Methods"        value "GET, OPTIONS"
            match response tagged "STATIC" header set "Access-Control-Max-Age"      value "1728000"
            match response tagged "STATIC" header set "Content-Type"                value "text/plain charset=UTF-8"

            match response tagged "STATIC" header set "Access-Control-Allow-Headers" value "Range,DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type"

            pass request tagged "STATIC" forward to <webhosts>

            pass request path "/tracker/socket"     forward to <apihosts>
            pass request path "/socket.io"          forward to <apihosts>
            pass request path "/*"                  forward to <apihosts>
    }

Si vous arrivez à faire mieux, n’hésitez pas à commentez s’il vous plait. Je mettrai à jour mon installation ainsi que cet article.

Maintenant, on a les trois relais, tls en ipv6, tls en ipv4 et rtmp (pour la diffusion live) relayé de ipv6 vers PeerTube qui écoute en ipv4.

    relay wwwtls6 {
            # Run as a SSL/TLS accelerator
            listen on $ext6 port https tls

            protocol https

            # httpd serve static and the rest on port 8000
            forward to <webhosts> port 8000

            # peertube stuff listens on 9000
            forward to <apihosts> port 9000
    }

    relay wwwtls4 {
            # Run as a SSL/TLS accelerator
            listen on $ext4 port https tls

            protocol https

            # httpd serve static and the rest on port 8000
            forward to <webhosts> port 8000

            # peertube stuff listens on 9000
            forward to <apihosts> port 9000
    }

    relay live {
            listen on $ext6 port 1935
            forward to <apihosts> port 1935
            protocol rtmp
    }

Conclusion

Donc voila.

On a le guide complet d’installation de PeerTube sur OpenBSD, sans Nginx mais avec Httpd et Relayd.

On peut envoyer la sauce.

    doas rcctl restart peertube