From 4603c1759f29b8a1adb3e83d610ca00e778d76bd Mon Sep 17 00:00:00 2001 From: Jonas L Date: Sat, 30 Dec 2023 18:59:15 +0100 Subject: [PATCH] feat!: use nginx to serve media files (#2860) Closes #2522 To reduce the strain on the API service, we moved the media file serving to the Nginx web server. The API is still handling the authentication, but delegates the serving using the `X-Accel-Redirect` header. BREAKING CHANGE: The media file serving is now handled by Nginx instead of the API service. The `storage.path` field is now used in the Nginx configuration, so make sure to update the Nginx configuration file if you change it. --- api/libretime_api/storage/views/file.py | 10 ++++++---- docker-compose.yml | 1 + docker/config.template.yml | 3 ++- docker/config.yml | 3 ++- docker/example/config.yml | 3 ++- docker/nginx.conf | 7 +++++++ docs/admin-manual/configuration.md | 23 ++++++++++++++++++++++- install | 3 ++- installer/config.yml | 3 ++- installer/nginx/libretime.conf | 7 +++++++ 10 files changed, 53 insertions(+), 10 deletions(-) diff --git a/api/libretime_api/storage/views/file.py b/api/libretime_api/storage/views/file.py index fc04b5c24..70d85e4fc 100644 --- a/api/libretime_api/storage/views/file.py +++ b/api/libretime_api/storage/views/file.py @@ -1,7 +1,6 @@ import os -from django.conf import settings -from django.http import FileResponse +from django.http import HttpResponse from django.shortcuts import get_object_or_404 from rest_framework import viewsets from rest_framework.decorators import action @@ -21,5 +20,8 @@ class FileViewSet(viewsets.ModelViewSet): pk = IntegerField().to_internal_value(data=pk) file = get_object_or_404(File, pk=pk) - path = os.path.join(settings.CONFIG.storage.path, file.filepath) - return FileResponse(open(path, "rb"), content_type=file.mime) + + response = HttpResponse() + response["Content-Type"] = file.mime + response["X-Accel-Redirect"] = os.path.join("/api/_media", file.filepath) + return response diff --git a/docker-compose.yml b/docker-compose.yml index 782bc1051..30220f085 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -108,6 +108,7 @@ services: - legacy volumes: - libretime_assets:/var/www/html:ro + - libretime_storage:/srv/libretime:ro - ${NGINX_CONFIG_FILEPATH:-./nginx.conf}:/etc/nginx/conf.d/default.conf:ro icecast: diff --git a/docker/config.template.yml b/docker/config.template.yml index 3bc76ce1f..0551fc673 100644 --- a/docker/config.template.yml +++ b/docker/config.template.yml @@ -31,7 +31,8 @@ general: auth: local storage: - # Path of the storage directory. + # Path of the storage directory. Make sure to update the Nginx configuration after + # updating the storage path. # > default is /srv/libretime path: /srv/libretime diff --git a/docker/config.yml b/docker/config.yml index 1f48968c6..a604a2c6e 100644 --- a/docker/config.yml +++ b/docker/config.yml @@ -31,7 +31,8 @@ general: auth: local storage: - # Path of the storage directory. + # Path of the storage directory. Make sure to update the Nginx configuration after + # updating the storage path. # > default is /srv/libretime path: /srv/libretime diff --git a/docker/example/config.yml b/docker/example/config.yml index 394fbb2d7..27003f397 100644 --- a/docker/example/config.yml +++ b/docker/example/config.yml @@ -31,7 +31,8 @@ general: auth: local storage: - # Path of the storage directory. + # Path of the storage directory. Make sure to update the Nginx configuration after + # updating the storage path. # > default is /srv/libretime path: /srv/libretime diff --git a/docker/nginx.conf b/docker/nginx.conf index 6794d3340..ce30fa59a 100644 --- a/docker/nginx.conf +++ b/docker/nginx.conf @@ -40,4 +40,11 @@ server { proxy_redirect off; proxy_pass http://api:9001; } + + # Internal path for serving media files from the API. + location /api/_media { + internal; + # This alias path must match the 'storage.path' configuration field. + alias /srv/libretime; + } } diff --git a/docs/admin-manual/configuration.md b/docs/admin-manual/configuration.md index a0f36a8ba..4e272a226 100644 --- a/docs/admin-manual/configuration.md +++ b/docs/admin-manual/configuration.md @@ -72,11 +72,32 @@ The `storage` section configure the project storage. ```yml storage: - # Path of the storage directory. + # Path of the storage directory. Make sure to update the Nginx configuration after + # updating the storage path. # > default is /srv/libretime path: "/srv/libretime" ``` +:::caution + +After editing the `storage.path` field, make sure to update the LibreTime Nginx configuration file with the new value. + +In the example below, we are changing the path from `/srv/libretime` to `/mnt/data`: + +```patch + ... + + # Internal path for serving media files from the API. + location /api/_media { + internal; + # This alias path must match the 'storage.path' configuration field. +- alias /srv/libretime; ++ alias /mnt/data; + } +``` + +::: + ## Database The `database` section configure the PostgreSQL connection. diff --git a/install b/install index 1c2d25a6d..e092d3e97 100755 --- a/install +++ b/install @@ -750,7 +750,8 @@ template_file cp_if_different \ "/etc/nginx/sites-available/libretime.conf" \ sed \ -e "s|@@LISTEN_PORT@@|${LIBRETIME_LISTEN_PORT}|g" \ - -e "s|@@LEGACY_WEB_ROOT@@|${LEGACY_WEB_ROOT}|g" + -e "s|@@LEGACY_WEB_ROOT@@|${LEGACY_WEB_ROOT}|g" \ + -e "s|@@STORAGE_DIR@@|${STORAGE_DIR}|g" info "enabling libretime nginx config" ln -s --force \ diff --git a/installer/config.yml b/installer/config.yml index 0f215c2c3..2ac08eafc 100644 --- a/installer/config.yml +++ b/installer/config.yml @@ -31,7 +31,8 @@ general: auth: local storage: - # Path of the storage directory. + # Path of the storage directory. Make sure to update the Nginx configuration after + # updating the storage path. # > default is /srv/libretime path: /srv/libretime diff --git a/installer/nginx/libretime.conf b/installer/nginx/libretime.conf index 1976f74a1..b0aba5d4e 100644 --- a/installer/nginx/libretime.conf +++ b/installer/nginx/libretime.conf @@ -39,4 +39,11 @@ server { proxy_redirect off; proxy_pass http://unix:/run/libretime-api.sock; } + + # Internal path for serving media files from the API. + location /api/_media { + internal; + # This alias path must match the 'storage.path' configuration field. + alias @@STORAGE_DIR@@; + } }