PeerTube en Docker + Object Storage

TL;DR
Lorsqu’on active PEERTUBE_OBJECT_STORAGE_PROXY_PROXIFY_PRIVATE_FILES, comment on l’utilise?

Bonjour !

J’installe PeerTube avec le docker-compose.yml proposé, légèrement modifié pour enlever certbot et postfix (j’ai un conteneur séparé pour certbot et un serveur de courriel externe).
Voici mon docker-compose.yml :

version: "3.3"
services:
  webserver:
    image: chocobozzz/peertube-webserver:latest
    env_file:
      - .env
    ports:
     - "80:80"
     - "443:443"
    volumes:
      - type: bind
        source: ./docker-volume/nginx/peertube
        target: /etc/nginx/conf.d/peertube.template
      - assets:/var/www/peertube/peertube-latest/client/dist:ro
      - ./docker-volume/data:/var/www/peertube/storage
      - /root/data/certbot/certs:/etc/letsencrypt
    depends_on:
      - peertube
    restart: "always"
  peertube:
    image: chocobozzz/peertube:production-bookworm
    networks:
      default:
        ipv4_address: 172.18.0.42
    env_file:
      - .env
    ports:
     - "1935:1935" 
    volumes:
      - assets:/app/client/dist
      - ./docker-volume/data:/data
      - ./docker-volume/config:/config
    depends_on:
      - postgres
      - redis
    restart: "always"
  postgres:
    image: postgres:13-alpine
    env_file:
      - .env
    volumes:
      - ./docker-volume/db:/var/lib/postgresql/data
    restart: "always"
  redis:
    image: redis:6-alpine
    volumes:
      - ./docker-volume/redis:/data
    restart: "always"
networks:
  default:
    ipam:
      driver: default
      config:
      - subnet: 172.18.0.0/16
volumes:
  assets:

Et ça fonctionne.

Maintenant, ne trouvant pas où ajouter ma configuration en YAML pour l’Object Storage (docker-volume/config/local.production.json est le seul fichier de config hors du conteneur), j’ai décidé d’ajouter ça dans le .env lu par docker compose. Ça donne ça :

PEERTUBE_WEBSERVER_HOSTNAME=peertube.exemple.com
PEERTUBE_OBJECT_STORAGE_ENABLED=true
PEERTUBE_OBJECT_STORAGE_ENDPOINT=s3.bhs.perf.cloud.ovh.net
PEERTUBE_OBJECT_STORAGE_REGION=bhs
PEERTUBE_OBJECT_STORAGE_UPLOAD_ACL_PUBLIC="public-read"
PEERTUBE_OBJECT_STORAGE_UPLOAD_ACL_PRIVATE="private"
PEERTUBE_OBJECT_STORAGE_PROXY_PROXIFY_PRIVATE_FILES=true
PEERTUBE_OBJECT_STORAGE_CREDENTIALS_ACCESS_KEY_ID=mon_cle_id
PEERTUBE_OBJECT_STORAGE_CREDENTIALS_SECRET_ACCESS_KEY=ma_cle_secrete
PEERTUBE_OBJECT_STORAGE_MAX_UPLOAD_PART=5368709120
PEERTUBE_OBJECT_STORAGE_STREAMING_PLAYLISTS_BUCKET_NAME=nom_de_mon_bucket
PEERTUBE_OBJECT_STORAGE_STREAMING_PLAYLISTS_PREFIX=streaming-playlists/
PEERTUBE_OBJECT_STORAGE_STREAMING_PLAYLISTS_BASE_URL=https://peertube.exemple.com/
PEERTUBE_OBJECT_STORAGE_UPLOAD_ACL=private

Tout fonctionne bien pour le transcodage puis l’envoie des fichiers en résultant dans le bucket. Mais dès qu’on recharge la page, impossible pour PeerTube de retrouver la vidéo depuis le bucket. Bref, il peut ajouter des fichiers dans le bucket, mais pas les relire.

J’utilise le fichier original proposé par la doc pour docker comme fichier de config nginx et je me doute bien que le problème vient de là.

Est-ce que j’ai besoin d’un fichier de config supplémentaire pour nginx avec un sous-domaine différent qui ferait office de reverse-proxy et cache entre les clients et le bucket et pointer PEERTUBE_OBJECT_STORAGE_STREAMING_PLAYLISTS_BASE_URL vers ce sous-domaine?
C’est cette méthode que j’utilise avec Mastodon, mais son bucket et son contenu doivent être en public-read pour que le reverse proxy puisse s’y connecter, ce qui m’embête légèrement et que je n’ai pas tellement envie de reproduire avec le bucket pour PeerTube.

Si j’ai bien compris, PEERTUBE_OBJECT_STORAGE_PROXY_PROXIFY_PRIVATE_FILES permet d’activer une fonction de PeerTube permettant de récupérer les fichiers dans le bucket en s’authentifiant?
Toujours si j’ai bien compris, est-ce que ce « reverse proxy intégré » de PeerTube peut récupérer les fichiers dans le bucket privé en s’authentifiant?
Est-ce qu’il existe un exemple de configuration?

Merci !

Hello,

Est-ce que vous pouvez partager l’URL d’une vidéo qui ne fonctionne pas ?

Merci d’accorder de l’intérêt à mon message.

Voici un lien pour l’exemple :point_right: Be Linux - PeerTube

Ne comprenant pas PEERTUBE_OBJECT_STORAGE_PROXY_PROXIFY_PRIVATE_FILES, je l’ai mit à false et modifié PEERTUBE_OBJECT_STORAGE_UPLOAD_ACL pour mettre public à la place de private.

Je viens juste de redéployer (j’ai fait un rôle ansible) sur un VPS public (je faisais mes tests en local avant). Cette fois je n’ai rien modifié dans la configuration initiale, le transcodage, etc, tout est par défaut.

J’espère que ça peut aider à comprendre, car je suis complètement perdu sur ce coup-là.

À savoir, j’ai créé mon bucket de cette façon :
aws s3api create-bucket --bucket nom_de_mon_bucket --region bhs --acl public-read --endpoint-url=https://s3.bhs.perf.cloud.ovh.net
C’est comme ça que je l’avais fait pour Mastodon et ça fonctionne bien.
Les fichiers médias ne semblent plus être un problème à récupérer, mais PeerTube ne semble pas être en mesure de les lire dans son player.

Voici mon fichier de configuration nginx pour medias.tube-test.fedi.quebec :

proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=CACHE:10m inactive=7d max_size=10g;

server {
  listen 80;
  server_name medias.tube-test.fedi.quebec;
  root /var/www/html;
  location / { return 301 https://$host$request_uri; }
}

server {
  listen 443 ssl;
  http2 on;
  server_name medias.tube-test.fedi.quebec;

  ssl_protocols TLSv1.2 TLSv1.3;
  ssl_ciphers HIGH:!MEDIUM:!LOW:!aNULL:!NULL:!SHA;
  ssl_prefer_server_ciphers on;
  ssl_session_cache shared:SSL:10m;
  ssl_session_tickets off;

  ssl_certificate     /etc/letsencrypt/live/medias.tube-test.fedi.quebec/fullchain.pem;
  ssl_certificate_key /etc/letsencrypt/live/medias.tube-test.fedi.quebec/privkey.pem;

  root /var/www/html;

  keepalive_timeout 30;

  location = / {
    index index.html;
  }

  location / {
    try_files $uri @s3;
  }

  set $s3_backend 'https://nom_de_mon_bucket.s3.bhs.perf.cloud.ovh.net';

  location @s3 {
    limit_except GET {
      deny all;
    }

    resolver 213.186.33.99;
    proxy_set_header Host nom_de_mon_bucket.s3.bhs.perf.cloud.ovh.net;
    proxy_set_header Connection '';
    proxy_set_header Authorization '';
    proxy_hide_header Set-Cookie;
    proxy_hide_header 'Access-Control-Allow-Origin';
    proxy_hide_header 'Access-Control-Allow-Methods';
    proxy_hide_header 'Access-Control-Allow-Headers';
    proxy_hide_header x-amz-id-2;
    proxy_hide_header x-amz-request-id;
    proxy_hide_header x-amz-meta-server-side-encryption;
    proxy_hide_header x-amz-server-side-encryption;
    proxy_hide_header x-amz-bucket-region;
    proxy_hide_header x-amzn-requestid;
    proxy_ignore_headers Set-Cookie;
    proxy_pass $s3_backend$uri;
    proxy_intercept_errors off;

    proxy_cache CACHE;
    proxy_cache_valid 200 48h;
    proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;
    proxy_cache_lock on;

    expires 1y;
    add_header Cache-Control public;
    add_header 'Access-Control-Allow-Origin' '*';
    add_header X-Cache-Status $upstream_cache_status;
    add_header X-Content-Type-Options nosniff;
    add_header Content-Security-Policy "default-src 'none'; form-action 'none'";
  }
}

Il faut que le frontal nginx forward correctement le header Range :slight_smile:

2 « J'aime »

Merci pour ta réponse !

Je ne savais pas trop comment faire ça. C’est finalement ChatGPT qui m’a expliqué comment faire.

J’ai ajouté cette ligne dans mon fichier :
proxy_set_header Range $http_range;

Voici donc à quoi ressemble maintenant ce 2e fichier de configuration nginx pour le conteneur webserver :

proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=CACHE:10m inactive=7d max_size=10g;

server {
  listen 80;
  server_name medias.tube-test.fedi.quebec;
  root /var/www/html;
  location / { return 301 https://$host$request_uri; }
}

server {
  listen 443 ssl;
  http2 on;
  server_name medias.tube-test.fedi.quebec;

  ssl_protocols TLSv1.2 TLSv1.3;
  ssl_ciphers HIGH:!MEDIUM:!LOW:!aNULL:!NULL:!SHA;
  ssl_prefer_server_ciphers on;
  ssl_session_cache shared:SSL:10m;
  ssl_session_tickets off;

  ssl_certificate     /etc/letsencrypt/live/medias.tube-test.fedi.quebec/fullchain.pem;
  ssl_certificate_key /etc/letsencrypt/live/medias.tube-test.fedi.quebec/privkey.pem;

  root /var/www/html;

  keepalive_timeout 30;

  location = / {
    index index.html;
  }

  location / {
    try_files $uri @s3;
  }

  set $s3_backend 'https://nom_de_mon_bucket.s3.bhs.perf.cloud.ovh.net';

  location @s3 {
    limit_except GET {
      deny all;
    }

    resolver 213.186.33.99;
    proxy_set_header Host nom_de_mon_bucket.s3.bhs.perf.cloud.ovh.net;
    proxy_set_header Connection '';
    proxy_set_header Authorization '';
    proxy_set_header Range $http_range;   # <-------- AJOUTÉ ICI
    proxy_hide_header Set-Cookie;
    proxy_hide_header 'Access-Control-Allow-Origin';
    proxy_hide_header 'Access-Control-Allow-Methods';
    proxy_hide_header 'Access-Control-Allow-Headers';
    proxy_hide_header x-amz-id-2;
    proxy_hide_header x-amz-request-id;
    proxy_hide_header x-amz-meta-server-side-encryption;
    proxy_hide_header x-amz-server-side-encryption;
    proxy_hide_header x-amz-bucket-region;
    proxy_hide_header x-amzn-requestid;
    proxy_ignore_headers Set-Cookie;
    proxy_pass $s3_backend$uri;
    proxy_intercept_errors off;

    proxy_cache CACHE;
    proxy_cache_valid 200 48h;
    proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;
    proxy_cache_lock on;

    expires 1y;
    add_header Cache-Control public;
    add_header 'Access-Control-Allow-Origin' '*';
    add_header X-Cache-Status $upstream_cache_status;
    add_header X-Content-Type-Options nosniff;
    add_header Content-Security-Policy "default-src 'none'; form-action 'none'";
  }
}

Et ça fonctionne ! :tada:

Merci beaucoup @Chocobozzz !

1 « J'aime »

Je me suis réjouis trop vite…

Ça peut fonctionner dans certains cas, mais dans beaucoup de cas, ça provoque des erreurs CORS.

J’ai essayé toute sorte de configurations différentes sur mon bucket et sur mon reverse proxy nginx, sans succès.

Mon instance, tube.fedi.quebec, est accessible via nginx et ce fichier de configuration : https://raw.githubusercontent.com/Chocobozzz/PeerTube/master/support/nginx/peertube

Si je configure PEERTUBE_OBJECT_STORAGE_PROXY_PROXIFY_PRIVATE_FILES à true, il se passe quoi? PeerTube fait office de proxy entre le bucket et les clients?
Est-ce que le fichier de configuration nginx proposé dans le dépôt de PeerTube est compatible avec cette configuration?
Sinon, est-ce qu’il est adaptable sans avoir a créer un autre serveur?

Sinon, est-ce que je suis sur la bonne piste en configurant un autre serveur (medias.tube.fedi.quebec) faisant office de reverse proxy entre les clients et le bucktet?
Si oui, est-ce qu’il existe un exemple de configuration pour nginx?
Parce que le fichier proposé par Mastodon pour faire ça n’est pas la bonne solution pour le faire avec PeerTube apparemment…

Sinon, ben comment est on fait ça !? :confused:

Oui c’est ça

Oui bien sûr :slight_smile:

Vous pouvez partager le lien d’une vidéo qui ne fonctionne pas ?

D’accord.

Voici mes changements :

J’ai retiré le 2e fichier de configuration nginx qui servait de reverse proxy vers mon bucket (medias.tube.fedi.quebec). Il ne reste que tube.fedi.quebec utilisant le fichier par défaut tel quel.

J’ai modifié certaines variables d’environnement, voici la section se rapportant à l’Object Storage danhs mon .env :

PEERTUBE_OBJECT_STORAGE_ENABLED=true
PEERTUBE_OBJECT_STORAGE_ENDPOINT=s3.bhs.perf.cloud.ovh.net
PEERTUBE_OBJECT_STORAGE_REGION=bhs
PEERTUBE_OBJECT_STORAGE_UPLOAD_ACL_PUBLIC="public-read"
PEERTUBE_OBJECT_STORAGE_UPLOAD_ACL_PRIVATE="private"
PEERTUBE_OBJECT_STORAGE_PROXY_PROXIFY_PRIVATE_FILES=true
PEERTUBE_OBJECT_STORAGE_CREDENTIALS_ACCESS_KEY_ID=ma clé secrete
PEERTUBE_OBJECT_STORAGE_CREDENTIALS_SECRET_ACCESS_KEY=ma clé d’accès
PEERTUBE_OBJECT_STORAGE_MAX_UPLOAD_PART=4294967296
PEERTUBE_OBJECT_STORAGE_STREAMING_PLAYLISTS_BUCKET_NAME=mon-bucket
PEERTUBE_OBJECT_STORAGE_STREAMING_PLAYLISTS_PREFIX=streaming-playlists/
PEERTUBE_OBJECT_STORAGE_STREAMING_PLAYLISTS_BASE_URL=https://tube.fedi.quebec
PEERTUBE_OBJECT_STORAGE_UPLOAD_ACL=public
PEERTUBE_OBJECT_STORAGE_WEB_VIDEOS_BUCKET_NAME=mon-bucket
PEERTUBE_OBJECT_STORAGE_WEB_VIDEOS_PREFIX=web-videos/
PEERTUBE_OBJECT_STORAGE_WEB_VIDEOS_BASE_URL=https://tube.fedi.quebec

Et j’ai modifié le CORS de mon bucket :

{
    "CORSRules": [
        {
            "AllowedHeaders": [
                "*"
            ],
            "AllowedMethods": [
                "GET"
            ],
            "AllowedOrigins": [
                "https://tube.fedi.quebec"
            ],
            "ExposeHeaders": [
                "Access-Control-Allow-Origin"
            ]
        }
    ]
}

… puis (tel que proposé dans la doc de PeerTube) :

{
    "CORSRules": [
        {
            "AllowedHeaders": [
                "*"
            ],
            "AllowedMethods": [
                "GET"
            ],
            "AllowedOrigins": [
                "*"
            ]
        }
    ]
}

Je n’ai plus d’erreur en lien avec CORS, mais ça ne fonctionne pas non plus.

N’importe quelle des deux seules vidéos locales peuvent servir d’exemples : https://tube.fedi.quebec/videos/local

Hier soir, je suis parvenu à lire les vidéos locales sans aucune erreur, mais ça se connectait directement au endpoint S3 d’OVH pour servir les fichiers médias, ce qui me coûterait trop cher en frais egress pour que cette configuration soit envisageable.

Je suis arrivé à ça en supprimant (plus aucune déclaration) ces deux variables d’environnement de mon .env :

PEERTUBE_OBJECT_STORAGE_STREAMING_PLAYLISTS_BASE_URL
PEERTUBE_OBJECT_STORAGE_WEB_VIDEOS_BASE_URL

Je ne m’attendais pas à ce résultat (que ça redirige les clients directement vers le endpoint), puisque j’ai aussi ceci dans mon .env :
PEERTUBE_OBJECT_STORAGE_PROXY_PROXIFY_PRIVATE_FILES=true
En plus de ceci : PEERTUBE_OBJECT_STORAGE_UPLOAD_ACL=private

Je suis complètement perdu. Je ne comprends toujours pas le fonctionnement de PEERTUBE_OBJECT_STORAGE_PROXY_PROXIFY_PRIVATE_FILES et la façon de faire pour créer un reverse proxy avec un cache entre PeerTube et un bucket S3. :confused:

ÉDIT : Oh, je crois avoir compris un détail : proxify ne fonctionne que pour les vidéos dont les auteurs ont choisi de ne pas rendre public lors du téléversement. Et si je comprends toujours bien, si je souhaite un proxy pour TOUTES (public, privé, etc.) les vidéos locales, je dois le faire moi-même, car le fichier par défaut n’est pas en mesure de faire ça avec les vidéos partagées publiquement. J’ai bien compris?

RÉ-ÉDIT : J’ai essayé ça :
PEERTUBE_OBJECT_STORAGE_UPLOAD_ACL_PUBLIC="private"
Avec et sans les deux variables BUCKET_NAME définies.
Ça ne fonctionne pas non plus.

Avec ces settings :

PEERTUBE_OBJECT_STORAGE_PROXY_PROXIFY_PRIVATE_FILES=true
PEERTUBE_OBJECT_STORAGE_UPLOAD_ACL_PUBLIC="public-read"
PEERTUBE_OBJECT_STORAGE_UPLOAD_ACL_PRIVATE="private"
PEERTUBE_OBJECT_STORAGE_UPLOAD_ACL=private
PEERTUBE_OBJECT_STORAGE_STREAMING_PLAYLISTS_BASE_URL=https://tube.fedi.quebec
PEERTUBE_OBJECT_STORAGE_WEB_VIDEOS_BASE_URL=https://tube.fedi.quebec

tout fonctionne parfaitement (proxy au travers tube.fedi.quebec sans erreur) … en autant que l’auteur ait envoyé sa vidéo en Privé.
J’ai même fait le test avec cette vidéo qui ne fonctionne pas : j’ai modifié sa visibilité pour la mettre à Privé et hop, elle était lisible ! Je remet à Public et ça ne fonctionne plus à nouveau. :confused:

Moi j’aimerais que toutes les vidéos locales, en Public comme en Privé, soient servis de cette façon. Toujours en passant par le proxy PeerTube.

Il n’existe pas quelque chose du genre PEERTUBE_OBJECT_STORAGE_PROXY_PROXIFY_PUBLIC_FILES
ou
PEERTUBE_OBJECT_STORAGE_PROXY_PROXIFY_ALL_FILES ?

Je suis désolé mais ce n’est pas possible.

Il y a un soucis avec votre proxy S3 parce que FédiQuébec Tube ne sert pas correctement le fichier m3u8 qui a été uploadé dans s3.

@Chocobozzz : Est-ce que je devrais faire une demande officielle sur GitHub pour cette feature request ou ça n’a aucune chance d’arriver?

Le fichier m3u8 est accessible avec l’URL d’accès direct au bucket (que je ne souhaite pas partager publiquement à cause des frais egress d’OVH).
Il suffit de modifier la visibilité d’une vidéo locale pour Privée, Interne ou Password protected et ça corrige le problème.
Exemple : Je viens de modifier la visibilité de la vidéo en question (FédiQuébec [Intro logo] - FédiQuébec Tube) pour Password protected (mot de passe : s3) et ça fonctionne.
image

C’est pour ça que je trouve ça dommage que PeerTube ne proxify pas tout, ça fonctionnerait ! :face_holding_back_tears:

À tous :
Quelqu’un aurait-il un exemple fonctionnel de configuration nginx pour faire un reverse proxy devant le bucket S3 de PeerTube pour les vidéos publiées publiquement? Quelque chose de simple là, sans authentification nécessaire puisque l’ACL de ces fichiers publiques est public-read.

P.S. Je sens le besoin de corriger certaines choses que j’ai écrites plus haut dans ce fil.
Créer un bucket avec la commande aws s3api create-bucket --bucket nom_de_mon_bucket --region bhs --acl public-read --endpoint-url=https://s3.bhs.perf.cloud.ovh.net était une erreur, car le listing complet du bucket est possible par n’importe qui.
La bonne méthode est celle-ci : aws s3api create-bucket --bucket nom_de_mon_bucket --region bhs --endpoint-url https://s3.bhs.perf.cloud.ovh.net.
C’est les objets qui doivent être en public-read (PEERTUBE_OBJECT_STORAGE_UPLOAD_ACL=public-read).

En l’absence de réponse, je cherche des alternatives et je suis tombé sur ça :

Quelqu’un a déjà utilisé ça? Il semblerait que ça fonctionne aussi avec Wasabi et Minio, donc j’imagine que ça fonctionnera également avec OVH.

Le hic en ce moment, c’est que je n’ai qu’une IP publique, donc je dois choisir entre ça et le conteneur chocobozzz/peertube-webserver pour écouter 80 et 443…

J’ai pas encore compris si nginx-s3-gateway peut à la fois servir de reverse proxy ordinaire pour tube.fedi.quebec en utilisant le fichier du dépot peertube tel quel, et de s3-gateway pour medias.tube.fedi.quebec. Si c’est le cas, ça voudrait dire que le conteneur chocobozzz/peertube-webserver et le proxify ne sont plus nécessaires.

Si j’ai bien compris, ça procurerait un avantage majeur, celui d’utiliser des credentials pour accéder au bucket eb tout temps, y compris pour les vidéos publiques. Donc on pourrait rendre le bucket complètement privé. Plus besoin d’utiliser d’ACL public-read.

À suivre…