Creating a simple nginx local media server for in-browser playback.


Last updated: July, 2017.

A simple means to serve media locally (and even perhaps over the Internet), is to create a simple web server to index and serve the files in a directory.

This can be improved by converting all content served to formats playable by modern browsers.

This guide covers the installation of nginx for this purpose, and using ffmpeg to convert media to a browser-playable format.



1. Create your media directory.

mkdir ~/media/

chmod -R 755 ~/media/

All files and sub-directories inside of this directory will be served by the server.


2. Install and configure nginx.

sudo apt update && sudo apt install nginx


Option 1 - Using TLS (HTTPS).

If you intend to open this server to the Internet, TLS is a requirement. Inside of your local network, however, TLS is not so much of a requirement.

There's no disadvantage to using TLS beyond the increased number of configuration steps.

This guide instructs you to generate a self-signed certificate. If you can acquire a trusted certificate, skip the relevant steps and alter the nginx configuration file accordingly.

Note that browsers will dispaly a bypassable error if you use a self-signed certificate.


Generate a private key.

sudo openssl ecparam -genkey -name secp384r1 > /etc/ssl/private/privkey.pem

Generate a self-signed certificate.

sudo openssl req -new -x509 -key /etc/ssl/private/privkey.pem -out /etc/ssl/certs/cert.pem -days 3650

Restrict permissions on the private key and certificate.

sudo chown root: /etc/ssl/private/privkey.pem

sudo chown root: /etc/ssl/certs/cert.pem

sudo chmod 600 /etc/ssl/private/privkey.pem

sudo chmod 600 /etc/ssl/certs/cert.pem

Create an nginx configuration file.

sudo nano /etc/nginx/conf.d/default.conf

Use the template below.

server {
    # Listen on port 443, enable TLS, and HTTP/2.
    listen 443 ssl http2;
    ssl on;

    # Certificate and private key for TLS.
    ssl_certificate  /etc/ssl/certs/cert.pem;
    ssl_certificate_key  /etc/ssl/private/privkey.pem;

    # TLS options.
    ssl_session_timeout 1d;
    ssl_session_cache shared:SSL:50m;
    ssl_session_tickets off;

    # Modern TLS protocol and ciphers.
    ssl_protocols TLSv1.2;
    ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256';
    ssl_ecdh_curve secp384r1;
    ssl_prefer_server_ciphers on;

    # Enable HSTS.
    add_header Strict-Transport-Security "max-age=63072000";

    # Various other standard security headers.
    add_header Referrer-Policy "no-referrer";
    add_header X-Content-Type-Options "nosniff";
    add_header X-Frame-Options "DENY";
    add_header X-XSS-Protection "1; mode=block";

    # CSP to only allow local content.
    add_header Content-Security-Policy "default-src 'self'; frame-ancestors 'none'; sandbox";

    # Optionally, if your (trusted) certificate supports it, enable OCSP.
    # ssl_stapling on;
    # ssl_stapling_verify on;
    # ssl_trusted_certificate /etc/letsencrypt/ecdsa/example.com/0001_chain.pem;

    location / {
        # Media location.
        root /home/example/media;

        # Turn on file indexing.
        autoindex on;
    }

    # Your local DNS resolver.
    resolver 192.168.0.100;
}

# Redirect HTTP to HTTPS.
server {
   listen 80;
   return 301 https://$host$request_uri;
}

Restart nginx.

sudo service nginx restart


Option 2 - Using plaintext only (HTTP).

Create an nginx configuration file.

sudo nano /etc/nginx/conf.d/default.conf

Use the template below.

server {
    # Listen on port 80.
    listen 80;

    # Various standard security headers.
    add_header Referrer-Policy "no-referrer";
    add_header X-Content-Type-Options "nosniff";
    add_header X-Frame-Options "DENY";
    add_header X-XSS-Protection "1; mode=block";

    # CSP to only allow local content.
    add_header Content-Security-Policy "default-src 'self'; frame-ancestors 'none'; sandbox";

    location / {
        # Media location.
        root /home/example/media;

        # Turn on file indexing.
        autoindex on;
    }

    # Your local DNS resolver.
    resolver 192.168.0.100;
}

Restart nginx.

sudo service nginx restart


Optionally - Use authentication.

Depending on the content you're serving, you may want to use password authentication.

This is absolutely required if you're serving copyrighted material to the Internet, or to a large local network.

To securely implement password authentication, it's realistically required that you use TLS.


Install apache2-utils.

sudo apt update && sudo apt install apache2-utils

Create a user. For example, alice.

sudo htpasswd -c /etc/nginx/.htpasswd alice

You can remove - c to add additional users, although there's no reason to add additional users in this configuration.

sudo htpasswd /etc/nginx/.htpasswd bob

Alter your nginx configuration file location block.

sudo nano /etc/nginx/conf.d/default.conf

Alter only the location block as below.

location / {
    # Media location.
    root /home/example/media;

    # Turn on file indexing.
    autoindex on;

    # Enable basic authentication.
    auth_basic "Password required.";
    auth_basic_user_file /etc/nginx/.htpasswd;
}

Restart nginx.

sudo service nginx restart


3. Convert media to formats playable by modern browsers.

Install ffmpeg.

sudo apt update && sudo apt install ffmpeg


Video media.

The standard video format supported by modern browsers is the MP4 using the H.264 video codec and the AAC audio codec.

Using ffmpeg, convert a single video file.

ffmpeg -i example.mkv -vcodec h264 -acodec aac example.mp4

Using a bash script to convert all AVI and MKV files in a directory (excluding sub-directories).

#! /bin/bash

# Replace spaces with underscores. This is required for bash compatibility.
for file in *;
do
    mv "$file" `echo $file | tr ' ' '_'` ;
done

# Convert AVI and MKV files to H264/AAC MP4 files.
for i in *.avi *.mkv;
do
    ffmpeg -i $i -vcodec h264 -acodec aac $i.mp4;
done

# Move old files.
mkdir original
mv *.avi original/
mv *.mkv original/

Audio media.

Many audio formats are supported natively by most browsers. AAC and MP3 are, however, guaranteed to be supported by all modern browsers.

Using ffmpeg, convert a single audio file to AAC.

ffmpeg -i example.wav -acodec aac example.m4a

Or, MP3.

ffmpeg -i example.wav -acodec mp3 example.mp3

You could also manipulate the bash script for video conversion to perform conversion on audio files.


4. You are done.

Congratulations! You can now browse and play content in a browser by navigating to the IP address or hostname of your chosen system.



Comments are provided by Disqus. To respect user privacy, Disqus is only loaded on user prompt.

I recommend uBlock Origin to protect against Disqus tracking and advertising.