Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to configure nginx to properly serve mp4 videos to Safari?

I'm attempting to use a video tag to display video in safari.

Here is my snippet of html:

<video autoplay="" muted="" loop="" preload="auto" poster="http://my.ip.add.ress/static/my_video_image.jpg">
    <source src="http://my.ip.add.ress/static/my_video.mp4" type="video/mp4" />
    <source src="http://my.ip.add.ress/static/my_video.webm" type="video/webm" />
</video>

The static files (css, js, images) are being served up properly.

The problem I run into is when safari requests the video, nginx is supposed to return a 206 partial content response. However, it returns a 200 OK with the whole video (I think the whole file is returned). But safari didn't request the whole video, it requested a range of the video using the range header.

So this causes the video to not play in Safari. As it sits, my current setup works in Chrome and Firefox.

I'm using nginx to serve the video content. I'd like to avoid using a 3rd party server as this is for a small project :).

My question is how do I properly setup nginx to serve videos to safari? I know that nginx is ignoring the range header in the request. Is there a way to tell nginx to pay attention to that header?

Here is my nginx config in /etc/nginx/sites-available/myproject:

server {
    listen 80;
    server_name my.ip.add.ress;

    location = /favicon.ico { access_log off; log_not_found off; }
    location /static/ {
        alias /home/website/my_python_virtual_env/my_project/static_folder_containing_mp4_videos/;
    }

    location / {
        # gunicorn to django
        include proxy_params;
        proxy_pass http://unix:/run/gunicorn.sock;
    }
}

Here is the request:

Request
Range: bytes=0-1
Accept: */*
Connection: Keep-Alive
Accept-Encoding: identity
DNT: 1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/11.1.2 Safari/605.1.15
Referer: http://my.ip.add.ress/
X-Playback-Session-Id: 97A1EC54-85A3-42A1-8EA2-8657D03058B6

Here is the response:

Response
Content-Type: video/mp4
Date: Thu, 13 Sep 2018 17:48:40 GMT
Last-Modified: Wed, 12 Sep 2018 22:20:39 GMT
Server: nginx/1.14.0 (Ubuntu)
Content-Length: 10732143
Connection: keep-alive
X-Frame-Options: SAMEORIGIN

On sites that do have video working, the request/response looks like this:

Request
GET /big_buck_bunny.mp4 HTTP/1.1
Range: bytes=0-1
Host: clips.vorwaerts-gmbh.de
Accept: */*
Connection: keep-alive
Accept-Encoding: identity
Accept-Language: en-us
DNT: 1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/11.1.2 Safari/605.1.15
X-Playback-Session-Id: C2EAAF63-1230-44A9-9A16-6332C1EDEBF0


Response
HTTP/1.1 206 Partial Content
ETag: "5416d8-47f21fa7d3300"
Content-Type: video/mp4
Date: Thu, 13 Sep 2018 17:28:47 GMT
Last-Modified: Tue, 09 Feb 2010 02:50:20 GMT
Server: cloudflare
Content-Length: 2
Expires: Fri, 13 Sep 2019 17:28:47 GMT
Connection: keep-alive
Content-Range: bytes 0-1/5510872
Set-Cookie: __cfduid=d2776dbf7a6baaa1b2f2572d600deda141536859727; expires=Fri, 13-Sep-19 17:28:47 GMT; path=/; domain=.vorwaerts-gmbh.de; HttpOnly
Vary: Accept-Encoding
Cache-Control: public, max-age=31536000
CF-RAY: 459c5511b243a064-SLC
CF-Cache-Status: HIT
like image 583
teewuane Avatar asked Sep 13 '18 18:09

teewuane


People also ask

What is Nginx Sendfile?

By default, NGINX handles file transmission itself and copies the file into the buffer before sending it. Enabling the sendfile directive eliminates the step of copying the data into the buffer and enables direct copying data from one file descriptor to another.

What is root in Nginx config?

The default Nginx directory on Debian is /var/www/nginx-default . The root is the default location.


1 Answers

I feel silly posting this but here was my problem.

My nginx instance was not setup to serve the media. Anything from /media/ was being served by django. Django does not properly serve mp4 videos for safari because it doesn't work with Range requests. It will serve them properly enough for chrome to work though! ;)

The fix was simple. Add the location entry for /media/ to my nginx.conf file for the website.

server {
    listen 80;
    server_name my.ip.add.ress;

    location = /favicon.ico { access_log off; log_not_found off; }

    # still have to have this location entry to serve the static files...
    location /static/ {
        alias /home/website/my_python_virtual_env/my_project/static_folder_containing_static_files/;
    }

    # Added this location entry to nginx, my videos were NOT in the static folders, they were in the media folders. I feel dumb but hopefully this will help someone else out there!
    location /media/ {
        alias /home/website/my_python_virtual_env/my_project/media_folder_containing_mp4_videos/;
    }


    location / {
        # gunicorn to django
        include proxy_params;
        proxy_pass http://unix:/run/gunicorn.sock;
    }
}
like image 163
teewuane Avatar answered Oct 16 '22 10:10

teewuane