Running Plex from a Docker Container on Ubuntu 16.04 LTS / 16.10

Updated 24/12/16 : Plex now have an official Docker container, this guide has been updated to use this.

Updated 28/03/17 : Automatic updates not working on your container when restarting? Make sure you specify the correct tag for the docker image. If you are a plexpass subscriber pull the “plexinc/pms-docker:plexpass” image, if not pull the “plexinc/pms-docker:public” image.

Updated 22/05/17: Issue with NFS volumes not being mounted when docker service started led to media being unavailable without container/ docker restart. Changing volumes passed-through to container to include “:shared” resolves this issue.

I’ve been looking at the merits of moving my Plex server workload from a dedicated KVM/QEMU virtual machine to a docker container on the host server itself. The reasons for doing this were as below:

  • Reducing the administrative overhead of updating an additional operating system
  • Reducing the compute overhead of running an additional operating system on top of the host O/S

An additional benefit of running Plex in this manner is that on restarting the container the latest version of Plex is automatically pulled and deployed, making updates in future very, very simple.

This guide assumes you have installed docker as outlined here: http://www.cb-net.co.uk/linux/installing-docker-on-ubuntu-16-04-lts-16-10/

Downloading / Deploying the Container

To download and deploy the container you will need:

  • A storage location for the Plex configuration directory – this is persistent, i.e. it will survive containers being deleted/ recreated. The size of this will vary based on how large your media library is. On libraries with several terabytes of media you looking at tens of gigabytes of storage.
  • One or multiple mount points/ folder locations that contains your media (in this example there are multiple “-v” definitions that represent paths to TV shows, movies etc. you can have as many of these as you want)

Note below, I have used the “plexinc/pms-docker:plexpass” docker image to ensure automatic updates on container restart work. If you are not a plexpass subscriber ensure you change this to “public.” If you do not specify a tag, automatic updates on the container will not work.

# Pull the linuxserver/plex docker image
sudo docker pull plexinc/pms-docker:plexpass

# Get a Plex Claim Token by going to this URL and replace <CLAIM> below
# https://www.plex.tv/claim/

# Create a new linuxserver/plex docker container
docker create \
--name plex \
--net=host \
-e TZ=Europe/London \
-e PUID=1000 -e PGID=1000 \
-e PLEX_CLAIM="<CLAIM>" \
-v <path to config>:/config \
-v <path to music>:/data/music:shared \
-v <path to tv series>:/data/tvshows:shared \
-v <path to movies>:/data/movies:shared \
-v <path to home videos>:/data/homevideos:shared \
plexinc/pms-docker:plexpass

# Configure docker container to always update
docker update --restart=always plex

# Start the plex container
docker start plex

You’ll notice I have defined volumes as “:shared” which enables NFS volumes passed-through to the container to be mounted after the container starts without issue.

You can now browse to http://<docker host IP>:32400 and login using you plex.tv account.

If you want to use the PlexPass version of Plex modify the server settings and restart the container using the command shown below.

Managing the Plex Container

# Start the plex container
sudo docker start plex
# Stop the plex container
sudo docker stop plex
# Hard-stop the plex container
sudo docker kill plex
# Restart (and auto-update) the plex container
sudo docker restart plex
# List all running containers
sudo docker ps
# List all running AND non-running containers
sudo docker ps -a
# Remove the plex container (note you can redploy and will not lose anything/ config wise)
sudo docker rm plex
# Remove the linuxserver/plex docker image
sudo docker rmi linuxserver/plex
# Review logs for plex container
sudo docker logs -f plex

Installing Docker on Ubuntu Server 16.04 LTS / 16.10

I’ve been looking at moving some of my application/ process workloads from KVM/ QEMU Virtual Machines to docker containers – simply to reduce unnecessary overhead and complexity.

Installing docker on Ubuntu Server 16.04 or 16.10 is surprisingly straight-forwards, it is also possible (from my experience) to run docker alongside KVM/QEMU on the host server, as well as running docker containers within KVM/QEMU virtual machines.

# Update host O/S
sudo apt-get update
sudo apt-get install apt-transport-https ca-certificates

# Create apt source for docker
sudo apt-key adv \
--keyserver hkp://ha.pool.sks-keyservers.net:80 \
--recv-keys 58118E89F3A912897C070ADBF76221572C52609D 
echo "deb https://apt.dockerproject.org/repo ubuntu-xenial main" | sudo tee /etc/apt/sources.list.d/docker.list

# Pre-reqs installation
sudo apt-get update
sudo apt-get install linux-image-extra-$(uname -r) linux-image-extra-virtual

# Install docker
sudo apt-get update
sudo apt-get install docker-engine
sudo service docker start

# UFW config
sudo ufw status

# If UFW enabled modify /etc/default/ufw
vi /etc/default/ufw
DEFAULT_FORWARD_POLICY="ACCEPT"

# Set docker to start on boot
sudo systemctl enable docker

Changing the guacamole MySQL User Password

From an SSH shell execute the following commands to change the MySQL user password:

mysql -u root -h localhost -p'<root password>'
USE guacamole;
SET PASSWORD FOR 'guacamole'@'localhost' = PASSWORD('<new password>');

Now modify /etc/guacamole/guacamole.properties ensuring you update the value for “mysql-password: <password>”

# MySQL properties
mysql-hostname: localhost
mysql-port: 3306
mysql-database: guacamole
mysql-username: guacamole
mysql-password: <password>

Finally restart tomcat8

systemctl restart tomcat8

Creating an SMB / CIFS Share on Ubuntu 16.04 LTS

As part of my KVM/QEMU setup I needed to be able to copy media from a Windows PC to a Linux Ubuntu Server, for ease I wanted to do this via SMB/ CIFS – I was also using NFS for linux <> linux file sharing, so opted to use the same bind mount point for both NFS and SMBD.

Relevant /etc/fstab entries as below:

# Physical drive mount point
/dev/sdb1 /mnt/media1 ext4 defaults 0 2

# Media1; NFS/ SMBD mountpoint
/mnt/media1 /export/media1 none bind 0 0

Install smbd on Ubuntu server:

apt-get install samba
cp /etc/samba/smb.conf ~
vi /etc/samba/smb.conf

Create a samba login for your user account – in my case, my linux user account was “chris” – you will use this to access the share form your windows client (expect a prompt for username/ password when you browse to the share):

sudo smbpasswd -a chris

Configure smbd – modify paths/ username accordingly:

vi /etc/samba/smbd.conf
# add this to the bottom of the file

[Media]
comment = My Share
path = /export/media1
browsable = yes
valid users = chris
read only = no
create mask = 0755

Finally, start SMBD and set to start automatically on boot – once started, you should be able to browse to “\\<IP/DNS Name of Ubuntu Server>”

# start smbd
service smbd restart

# enable smbd on boot
systemctl enable smbd

Creating and Managing VMs in Ubuntu Server 16.10

I recently bought and setup a Asrock DeskMini with a i5 6400 (will take any desktop S1151 65W CPU), 16GB RAM and an SSDs to act as a KVM/ QEMU host at home. At some point I’ll share the end-to-end setup, but for now suffice to say I am really happy with this very flexible and tiny box of computing power!

I did however want to share some useful VM setup and management commands I have been using, some useful background information:

  • Host O/S Ubuntu Server 16.10 – with “Virtual Machine host” option select at install time.
  • Network configuration as below
apt-get install -y bridge-utils

cat /etc/network/interfaces

 # The loopback network interface
 auto lo
 iface lo inet loopback

 # The primary network interface
 auto br0
 iface br0 inet static
             address 192.168.1.240
             netmask 255.255.255.0
             broadcast 192.168.1.255
             gateway 192.168.1.1
             dns-nameserver 192.168.1.1
             bridge_ports enp0s31f6
             bridge_stp off
             bridge_fd 0
  • Storage layout as below:
 sdb
 ├─sdb4 /var/kvm/images
 ├─sdb2 [SWAP]
 ├─sdb3 part /
 └─sdb1 part /boot/efi

Install virtinst:

apt-get install virtinst

Create directories to store vhd files and iso files used for installing VMs

mkdir -p /var/kvm/images/vm
mkdir -p /var/kvm/images/iso

 

Creating New Virtual Machines

Ubuntu Server 16.04 LTS (from an ISO)

First download Ubuntu server 16.04 LTS ISO:

cd /var/kvm/images/iso
wget http://releases.ubuntu.com/16.04.1/ubuntu-16.04.1-server-amd64.iso

Create the virtual machine – requires the use of sudo – this machine will have 4 vCPUs, 4GB RAM and a 32GB vhd.

virt-install \
 --virt-type=kvm \
 --hvm \
 --name vlinux1 \
 --ram 4096 \
 --disk path=/var/kvm/images/vm/vlinux1.qcow2,size=32,bus=virtio,format=qcow2 \
 --vcpus=4 \
 --os-type linux \
 --os-variant ubuntu16.04 \
 --network bridge=br0 \
 --graphics vnc,listen=0.0.0.0 \
 --noautoconsole \
 --console pty,target_type=serial \
 --cdrom /var/kvm/images/iso/ubuntu-16.04.1-server-amd64.iso

Complete the installation using TightVNC (or another VNC client) to connect via <kvmhostip>:59000

Once completed, the virtual machine will shutdown. Once shutdown the VNC graphics will no longer function, even when you restart the mahcine.

You can configure persistent VNC-based graphics by modifying the XML file associated with the virtual machine – stored under /etc/libvirt/qemu/

vi /etc/libvirt/qemu/vlinux1.xml

# Now remove all lines relating to <graphics> and replace with single line as below:

<graphics type='vnc' port='-1' autoport='yes' listen='0.0.0.0'/>

When you start the machine, you’ll be able to reconnect via VNC. The port number automatically increments for every VM configured like this – based on the order in which the machines start up/ are started up.

 

Managing Virtual Machines

Use virsh to manage and configure VMs – examples below – all require the use of sudo.

# List powered-on / running virtual machines
virsh list --all

# Start / power-on virtual machine "vlinux1"
virsh start vlinux1

# Reset virtual machine "vlinux1"
 virsh reset vlinux1

# Hard power-off virtual machine "vlinux1"
virsh destory vlinux1

# Shutdown virtual machine "vlinux1"
 virsh shutdown vlinux1

# Remove from inventory virtual machine "vlinux1"
 virsh undefine vlinux1

# Set power-on at host start-up for virtual machine "vlinux1"
 virsh autostart vlinux1

# Display VM information for virtual machine "vlinux1"
virsh dominfo vlinux1

 

Debian Linux 8 – Installing KDE Plasma 5.x Graphical Desktop

Plasma is, in my opinion, one of the best looking graphical desktops for Linux, for more information on KDE Plasma itself see here: https://www.kde.org/workspaces/plasmadesktop/

Note that deploying plasma on Debian 8.x requires that you move from the “stable” branch to “testing” branch. What does this mean? See here: https://wiki.debian.org/DebianTesting

Be sure to fully review what will be installed / removed as part of this upgrade. Rollback will be very “challenging!”

# First upgrade to non-stable "testing" variant of Debian Linux
sudo cp /etc/apt/sources.list ~/
sudo sed -i -e 's/jessie/testing/g' /etc/apt/sources.list
sudo apt-get update
sudo apt-get upgrade
sudo reboot

# Upgrade any remaining packages
sudo apt-get update
sudo apt-get dist-upgrade
sudp reboot

# Install plasma desktop, when prompted for desktop environment selection, choose "sddm"
sudo apt-get install plasma-desktop sddm
sudo reboot

# Cleanup unused packages
sudo apt-get autoremove

I’ve tested and can confirm that, unlike Gnome, Plasma 5.x works when using x11rdp to connect remotely.

Guacamole RDP en-gb Keyboard Mapping

Disclaimer – I have copied this solution straight out of the following https://glyptodon.org/jira/browse/GUAC-1031

Like me, you may want to add the en-gb keyboard mapping to guacamole’s RDP capability so that your @ and “” key-combinations work as expected! To do this you need to perform the following, prior to running “make” during the installation of guacamole-server.

Already installed guacaole-server? You can recompile and install “over the top” of your current guacamole-server – just be sure to run “make clean” before executing “make” and “make install”.

# Crate a new en-gb Keyboard Mapping File
vi ~/incubator-guacamole-server/src/protocols/rdp/keymaps/en_gb_qwerty.keymap

parent "base"
name "en-gb-qwerty"
freerdp "KBD_UNITED_KINGDOM"
 
map -altgr -shift 0x29 0x02..0x0D ~ "`1234567890-="
map -altgr -shift 0x10..0x1B ~ "qwertyuiop[]"
map -altgr -shift 0x1E..0x28 0x2B ~ "asdfghjkl;'#"
map -altgr -shift 0x56 0x2C..0x35 ~ "\zxcvbnm,./"
 
map -altgr +shift 0x29 0x02..0x0D ~ "¬!"£$%^&*()_+"
map -altgr +shift 0x10..0x1B ~ "QWERTYUIOP{}"
map -altgr +shift 0x1E..0x28 0x2B ~ "ASDFGHJKL:@~"
map -altgr +shift 0x56 0x2C..0x35 ~ "|ZXCVBNM<>?"
 
# Keys requiring AltGr
#
map +altgr -shift 0x29 ~ "¦"


# Add to make file, so that it is included
vi ~/incubator-guacamole-server/src/protocols/rdp/Makefile.am

# Modify this section so that it looks as-below
rdp_keymaps = \
 keymaps/base.keymap \
 keymaps/failsafe.keymap \
 keymaps/de_de_qwertz.keymap \
 keymaps/en_us_qwerty.keymap \
 keymaps/fr_fr_azerty.keymap \
 keymaps/it_it_qwerty.keymap \
 keymaps/ja_jp_qwerty.keymap \
 keymaps/sv_se_qwerty.keymap \
 keymaps/en_gb_qwerty.keymap

You can now run make and make install / continue with the deployment as outlined in my other posts.

Guacamole 0.9.10-incubating; Install with MySQL on Debian 8.6 / Ubuntu 16.x

I’d now recommend using this updated guide to deploy guacamole using Docker images. This is *much* easier, and by default you’ll get the latest version.

Use the script below to deploy required-prereqs and install mysql, tomcat8 and guacamole on your target Debian 8.6 client – be sure to change any references of “<password>” to suit your environment.

I have tested this on both Debian 8.6 and Ubuntu 16.04; this is intended for use on a fresh OS, with no prior versions of mysql, tomcat or guacamole. Your run this at your own risk!

# Set blank mysql root password for unattended install of mysql
debconf-set-selections <<< 'mysql-server mysql-server/root_password password'
debconf-set-selections <<< 'mysql-server mysql-server/root_password_again password'

# Install Guacamole server pre-reqs including MySQL
apt-get install -y libjpeg-dev libcairo2-dev libossp-uuid-dev libpng12-dev libfreerdp-dev libssh2-1-dev libssh-dev libwebp-dev libpulse-dev libavcodec-dev libavutil-dev libswscale-dev libpango1.0-dev libvncserver-dev maven tomcat8 tomcat8-admin tomcat8-user default-jdk default-jre java-common mysql-server libtool dh-autoreconf git libvorbis-dev

# Secure your mysql deployment - follow the defaults, but set a secure password as it is currently blank!
mysql_secure_installation

# Prepare the database and user needed for guacamole, you'll need your root <password> for a new MySQL user named "guacamole"
mysql -u root -p<password>
 CREATE DATABASE guacamole;
 CREATE USER 'guacamole'@'localhost' IDENTIFIED BY '<password>';
 GRANT SELECT,INSERT,UPDATE,DELETE ON guacamole.* TO 'guacamole'@'localhost';
 FLUSH PRIVILEGES;
 quit
 
# Download and install guacamole server
cd ~
git clone https://github.com/apache/incubator-guacamole-server
cd incubator-guacamole-server
autoreconf -fi
./configure --with-init-dir=/etc/init.d
make
make install
mkdir -p /etc/guacamole/extensions 
mkdir -p /etc/guacamole/lib

# Download and package guacamole client
cd ~
git clone https://github.com/apache/incubator-guacamole-client
cd incubator-guacamole-client
mvn package

# MySQL Database Preparation
cd ~/incubator-guacamole-client/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql
cat schema/*.sql | mysql -u root -p guacamole

# Copy MySQL guacamole extension to /etc/guacamole/extensions/
cp ~/incubator-guacamole-client/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/target/guacamole-auth-jdbc-mysql-0.9.10-incubating.jar /etc/guacamole/extensions/

# Download and deploy MySQL Connector-J to /etc/guacamole/lib/
cd ~
wget https://cdn.mysql.com//Downloads/Connector-J/mysql-connector-java-5.1.40.tar.gz
tar -zxvf mysql-connector-java-5.1.40.tar.gz
cd mysql-connector-java-5.1.40
cp mysql-connector-java-5.1.40-bin.jar /etc/guacamole/lib/

# TomCat WebApp and guacamole environment deployment
cd ~/incubator-guacamole-client/guacamole/target
cp guacamole-0.9.10-incubating.war /etc/guacamole/guacamole.war 
ln -s /etc/guacamole/guacamole.war /var/lib/tomcat8/webapps/
mkdir /usr/share/tomcat8/.guacamole
touch /etc/guacamole/guacamole.properties
ln -s /etc/guacamole/guacamole.properties /usr/share/tomcat8/.guacamole/
echo GUACAMOLE_HOME=/etc/guacamole >> /etc/default/tomcat8

# Create guacamole.properties 
### Change the <password> here!
echo '# MySQL properties' > guacamole.properties
echo 'mysql-hostname: localhost' >> guacamole.properties
echo 'mysql-port: 3306' >> guacamole.properties
echo 'mysql-database: guacamole' >> guacamole.properties
echo 'mysql-username: guacamole' >> guacamole.properties
echo 'mysql-password: <password> >> guacamole.properties

# Resolve freerdp directory issues present when running guacamole on Debian 8.6
mkdir /usr/lib/x86_64-linux-gnu/freerdp
ln -s /usr/local/lib/freerdp/guac* /usr/lib/x86_64-linux-gnu/freerdp/

ldconfig
systemctl daemon-reload

systemctl start tomcat8
/etc/init.d/guacd start

systemctl enable tomcat8
systemctl enable guacd

You can now browse to guacamole using the following URL and credentials guacadmin/guacadmin – note the trailing slash on the URL, without this you will get a HTTP 404 error!
http://localhost:8080/guacamole/

Take a look at my nginx reverse proxy guide for guacamole.

Ugrading Gucamole 0.9.9 to 0.9.10-incubating

Use the process below to upgrade your guacamole deployment, backed by a mysql database from version 0.9.9 to 0.9.10-incubating. ***If you have an older version this guide is not for you.***

All commands tested on Debian 8.6, Jessie – be sure to check the following post for any related pre-reqs/ libraries:

Guacamole 0.9.10-incubating; Install with MySQL on Debian 8.6

Firstly stop all guacamole related services:

systemctl stop tomcat8
systemctl stop guacd

Upgrade the client, extensions and database:

# Compile the client
cd ~
git clone https://github.com/apache/incubator-guacamole-client
cd incubator-guacamole-client
mvn package

# MySQL Database Upgrade Process ### From 0.9.9 ONLY ###
cd ~/incubator-guacamole-client/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/schema/upgrade
cat upgrade-pre-0.9.10.sql | mysql -u root -p guacamole

# TomCat WebApp Upgrade Process
cd ~/incubator-guacamole-client/guacamole/target
rm /var/lib/tomcat8/webapps/guacamole.war
rm -r /var/lib/tomcat8/webapps/guacamole
rm /etc/guacamole/guacamole.war
cp guacamole-0.9.10-incubating.war /etc/guacamole/guacamole.war 
ln -s /etc/guacamole/guacamole.war /var/lib/tomcat8/webapps/

# MySQL Extension Upgrade Process
rm /etc/guacamole/extensions/guacamole-auth-jdbc-mysql*
cp ~/incubator-guacamole-client/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/target/guacamole-auth-jdbc-mysql-0.9.10-incubating.jar /etc/guacamole/extensions/

Now upgrade server component:

# Server Upgrade
cd ~
git clone https://github.com/apache/incubator-guacamole-server
cd incubator-guacamole-server
autoreconf -fi
./configure --with-init-dir=/etc/init.d
make
make install

# Reload libraries and service files
ldconfig
systemctl daemon-reload

Finally, restart all services – you should now be able to resume using guacamole.

systemctl start guacd
systemctl restart tomcat8

Plex and the Privacy VPN Conundrum ; nginx to the rescue!

As an advocate in Internet Privacy I use a VPN configured on my router to obfuscate my browsing habits. My one bugbear with this solution has always been that Plex doesn’t work (well / if at all) in this scenario, and even when it does it’s slower due to the additional encryption / hops the VPN adds to the mix.

I’ve read countless “solutions” to this, for me, this is one of the easier – albeit you need to have either a VM to hand or a spare low-power x86 device and your own custom domain.

I recently started using nginx to proxy guacamole, on a dedicated, VPN-bypassed client. This got me thinking… could I proxy my remote Plex server (that was behind the VPN) via a dedicated VM running nginx? The answer, of course, was yes.

The example deployment / configuration below was completed on a Debian 8.6 Jessie install however, once you have nginx installed the configuration steps will be the same.

I’ve tested this solution with the Android Plex App, as well as the Plex Web App – no issues found to date!

First, lets install nginx and configure it to run on boot:

apt-get install -y curl

touch /etc/apt/sources.list.d/nginx.list

echo 'deb http://nginx.org/packages/debian/ jessie nginx' >> /etc/apt/sources.list.d/nginx.list

echo 'deb-src http://nginx.org/packages/debian/ jessie nginx' >> /etc/apt/sources.list.d/nginx.list

curl http://nginx.org/keys/nginx_signing.key | apt-key add -

apt-get update
apt-get install -y nginx

/etc/init.d/nginx start
systemctl enable nginx

We will harden the nginx server as we progress through the configuration. Firstly, lets block malicious agents – this is uniform across both HTTP and HTTPS configurations:

vi /etc/nginx/blockuseragents.rules

Contents of this file below:

map $http_user_agent $blockedagent {
default 0;
~*malicious 1;
~*bot 1;
~*backdoor 1;
~*crawler 1;
~*bandit 1;
}

SSL Configuration (needs an SSL certificate, try StartSSL – it’s free!)

Honestly – there is no good reason not to deploy an HTTPS-enabled reverse proxy. StartSSL certificates are free for personal use. Without this you’d be sending your Plex account username and password across the internet unencrypted.

*** Using these instructions, you do not need to add these certificates to plex itself.***

First, let’s address weak Diffie-Hellman (DH) key exchange parameters:

cd /etc/nginx/ssl
# This will take *an age* to complete
openssl dhparam -out dhparams.pem 4096

Now we’ll create the nginx .conf file for your server as below, be sure to change the relevant servername.

vi /etc/nginx/conf.d/domain.com.conf

Contents as below – be sure to review relevant SSL certificate files required in order to start nginx, these will vary by third-party CA.

include /etc/nginx/blockuseragents.rules;

# Hardening as-per https://gist.github.com/plentz/6737338
server_tokens off;
add_header X-Frame-Options SAMEORIGIN;
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
add_header Strict-Transport-Security "max-age=31622400; includeSubDomains; preload";

# Define upstream Plex server location - change this for your env
upstream plex-upstream {
 # change plex-server.example.com:32400 to the hostname:port of your plex server.
 # this can be "localhost:32400", for instance, if Plex is running on the same server as nginx.
 server 192.168.1.250:32400;
}

# Redirect http traffic for plex.domain.com to https - LAN only
server {
 if ($blockedagent) {
 return 403;
 }
 if ($request_method !~ ^(GET|HEAD|POST)$) {
 return 444;
 }
 listen 80;
 server_name plex.domain.com;
 return 301 https://$server_name$request_uri;
}

# Plex Reverse Proxy HTTPS server
server {
 if ($blockedagent) {
 return 403;
 }
 if ($request_method !~ ^(GET|HEAD|POST|PUT)$) {
 return 444;
 }
 listen 443 ssl;
 server_name
 tv
 plex
 plex.domain.com;

 ssl_dhparam /etc/nginx/ssl/dhparams.pem;
 ssl_certificate /etc/nginx/ssl/1_www.plex.domain.com_bundle.crt;
 ssl_certificate_key /etc/nginx/ssl/plex_ssl.key;
 ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
 ssl_prefer_server_ciphers on;
 ssl_ciphers "EECDH+ECDSA+AESGCM EECDH+aRSA+AESGCM EECDH+ECDSA+SHA384 EECDH+ECDSA+SHA256 EECDH+aRSA+SHA384 EECDH+aRSA+SHA256 EECDH+aRSA+RC4 EECDH EDH+aRSA RC4 !aNULL !eNULL !LOW !3DES !MD5 !EXP !PSK !SRP !DSS !RC4";

 # Hardening as-per https://gist.github.com/plentz/6737338
 ssl_session_cache shared:SSL:50m;
 ssl_session_timeout 5m;
 resolver 8.8.8.8;
 ssl_stapling on;
 ssl_trusted_certificate /etc/nginx/ssl/1_plex.domain.com_bundle.crt;

 # As-per https://forums.plex.tv/discussion/224138/proper-reverse-proxy-for-nginx
 large_client_header_buffers 4 8k;

 # set some headers and proxy stuff.
 proxy_set_header Host $http_host;
 proxy_set_header X-Real-IP $remote_addr;
 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
 proxy_set_header X-Forwarded-Proto $scheme;
 proxy_redirect off;
 proxy_buffering off;

 location /:/websockets/notifications {
 # if a request to / comes in, 301 redirect to the main plex page.
 # but only if it doesn't contain the X-Plex-Device-Name header
 # this fixes a bug where you get permission issues when accessing the web dashboard
 if ($http_x_plex_device_name = '') {
 rewrite ^/$ https://$http_host/web/index.html;
 }

 # As-per https://forums.plex.tv/discussion/224138/proper-reverse-proxy-for-nginx
 proxy_http_version 1.1;
 proxy_set_header Upgrade $http_upgrade;
 proxy_set_header Connection "upgrade";
 proxy_read_timeout 86400;

 # proxy request to plex server
 proxy_pass http://plex-upstream;
 }
 location / {
 proxy_pass http://plex-upstream;
 }
}

Install, configure and enable ufw:

# Install Uncomplicated Firewall
apt-get install ufw

# Allow HTTPS from anywhere
ufw allow https
# Allow HTTP from anywhere - change LAN IP address range and server IP
ufw allow from 192.168.1.0/24 to 192.168.1.248 port 80
# Allow HTTPS
ufw allow https

For added security you can rate-limit new connections on port 443 – this *may* help reduce the chances of a brute force attack against your plex login page:

# Add just above the COMMIT line in this file /etc/ufw/before.rules
# Rate-limiting for HTTPS connections
vi /etc/ufw/before.rules
-A ufw-before-input -p tcp --dport 443 -i eth0 -m state --state NEW -m recent --set
-A ufw-before-input -p tcp --dport 443 -i eth0 -m state --state NEW -m recent --update --seconds 2 --hitcount 20 -j DROP

You’ll then need to do one of two things:

  1. Install a dynamic dns client on your linux box and configure an appropriate A record
  2. Use dynamicdns on your router and configure an appropriate A record

When done, create a CNAME entry in your personal domain name that points to the dynamic DNS A record. I.e. if you used the config file above, and had a dynamic DNS A record of “myrouter.dyndns.com” and your personal domain is “domain.com” then your CNAME would be:

plex.domain.com pointing to myrouter.dyndns.com

Test your SSL config using the following free service: https://www.ssllabs.com/ssltest/

Finally, within Plex, under Settings | Server | Network (Show Advanced) ensure you populate the “Custom server access URLs” with (using URL from example config above – change as-per your environment/ needs):

https://plex.domain.com