Saturday, March 2, 2013

Plex Web Proxy

Plex Media Server works excellently by itself as a server, and the various client interfaces they have.  DLNA, Android, Windows, Mac all have excellent clients for this server.  In addition, they provide a web interface which can be served from the same system as the server.  

Plex provides their own account management via their MyPlex website.  You can use these credentials to access other Plex members' libraries who have shared their servers with you.  Since these credentials are needed in addition to my users' usual LDAP solution, I was hoping to put the Plex Web client behind my Nginx proxy and use Basic HTTP Authentication.  I was successful, unfortunately, the Web client doubles as the server management client if the source ip address of the request matches the local system. Unless I want users managing my account, probably not a good idea. 

The second reason I wanted to put Plex Web behind the proxy was so that I could put it inside of a subdomain, like www.domain.com/plexweb.  Unfortunately, Plex does not yet provide a way to provide a different context path behind a proxy.

The third reason to put Plex Web behind the proxy was to secure it with my SSL certificate and https.  This is easily doable, as is proxying to the default Plex Web port of 32400, to keep the request URLs a little cleaner, and just use the same hole in the NAT as regular https.

The first thing that is necessary is to tweak the Nginx configuration to properly proxy all the necessary subdomains used by the Plex Web http API.  In addition, Plex Web HAS to remain at the root domain.  However, I still want to use the root domain my web server frontpage.  The idea is to look for http headers specific to the Plex Web requests, proxy those to the Plex server, and proxy home requests to the subdomain /home, where a simple homemade web page will reside. 

The first step is to properly redirect the root domain, so edit /etc/nginx/sites-enabled/default, add the home section, and change the root location to the following:
location ^~/home {
    root /var/www/home;
}

location ^~ / {
    set $test "true";
    #If the web request contains either of these 2 headers, unset the flag
    if ($http_x_plex_product) {
        set $test "false";
    }
    
    if ($http_x_plex_protocol) {
        set $test "false";
    }

    #if the flag is still set, redirect all requests to /home location
    if ($test = "true") {
        rewrite ^(.*)$   /home$1 last;
    }

    #otherwise, we have a Plex header, redirect to plex
    proxy_pass http://www.domain.com:32400;
    proxy_redirect http:// https://;
}
After a little packet sniffing, I determined the set of subdomains needed by Plex, so that I only have to forward those requests. These may change as Plex updates their API. Add the following sections to  /etc/nginx/sites-enabled/default under the main server section. This could probably be done with a single location and an or'd regex, but from what I read, this may be faster.
#PlexWeb Section
location ^~ /:/ {
   proxy_pass http://www.domain.com:32400/:/;
   proxy_redirect http:// https://;
}
location ^~ /web {
   proxy_pass http://www.domain.com:32400/web;
   proxy_redirect http:// https:/
   proxy_redirect http:// https://;/;
}
location ^~ /system {
   proxy_pass http://www.domain.com:32400/system;
   proxy_redirect http:// https://;
}
location ^~ /library {
   proxy_pass http://www.domain.com:32400/library;
   proxy_redirect http:// https://;
}
location ^~ /servers {
   proxy_pass http://www.domain.com:32400/servers;
   proxy_redirect http:// https://;
}
location ^~ /channels {
   proxy_pass http://www.domain.com:32400/channels;
   proxy_redirect http:// https://;
}
location ^~ /identity {
   proxy_pass http://www.domain.com:32400/identity;
   proxy_redirect http:// https://;
}
location ^~ /photo {
   proxy_pass http://www.domain.com:32400/photo;
   proxy_redirect http:// https://;
}
location ^~ /pms {
   proxy_pass http://www.domain.com:32400/pms;
   proxy_redirect http:// https://;
}
location ^~ /video {
   proxy_pass http://www.domain.com:32400/video;
   proxy_redirect http:// https://;
}
This is unfortunately an incomplete solution.  The protocol that Plex uses over location /:/ actually uses WebSockets.  As such, the above solution to tunnel/proxy Plex kinda works, but the client keeps thinking it's disconnected.  Not sure what effect this has.  It will be necessary to use the feature just made available last month to version 1.3.13 of Nginx. Upgrading to this development version currently breaks my other proxying (subsonic, ldap-manager), so for now, I am disabling Plex proxying until they work out the kinks. However, if Plex proxy is all you need, just change the /:/ to 
location ^~ /:/ {
    proxy_pass http://www.domain.com:32400/:/;
    proxy_redirect http:// https://;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
}

No comments:

Post a Comment