warren-bank / HLS-Proxy

Node.js server to proxy HLS video streams
http://webcast-reloaded.surge.sh/proxy.html
GNU General Public License v2.0
244 stars 75 forks source link

Run proxy from a subfolder #37

Closed wimme closed 10 months ago

wimme commented 10 months ago

I would like to use this proxy on an existing website. I'm not allowed to open additional ports. So I was thinking to proxy incoming requests via our webserver to this HLS proxy. This seems to be possible by specifying the host and port in the --host option (as said here).

As I want to offer the website and the HLS proxy on the same host:port, I would need to run this HLS proxy from a sub folder.

https://host:443/proxy/* --> webserver --> HLS proxy on port 8080
https://host:443/* --> webserver --> website

Is this possible?

warren-bank commented 10 months ago
  1. if your current web server happens to use Node.js with Express.js
    • then HLS-Proxy can be used as standard middleware.. at any route you like
    • examples
  2. otherwise, what you suggest is perfectly doable
    • of course, your current web server will need the ability to intercept and conditionally reverse proxy requests
    • this functionality could either be:
      • directly supported by the web server
      • for example, my modifications to serve make this possible off-the-shelf
      • implemented by a plugin or module that the web server does support
      • for example: Apache supports _modproxy that should make this simple to configure
      • implemented by a cgi-script in a language that the web server does support
      • for example: PHP, perl, ...
wimme commented 10 months ago

It's indeed possible to do conditionally reverse proxy requests on the web server (we have this already working on Windows IIS). But will HLS-Proxy be able to correctly rewrite the urls in the m3u8 file to include the sub folder? Is this configurable? Because internally it runs on port 8080 (for example) without a sub folder. Additional question, can the web server also handle the HTTPS encryption? Will --host "mydomain.com:443" output the urls in the m3u8 as HTTPS?

warren-bank commented 10 months ago
  1. start HLS Proxy behind the firewall on an unused/unprotected port (ex: 8080)
     hlsd -v 3 --host "serve.local:80" --port 8080
  2. configure the web server that hosts serve.local:80 to reverse proxy a particular custom route

     NO_UPDATE_CHECK='1'
    
     serve --config 'serve.json' --cors --listen 'tcp:0.0.0.0:80'
    • example: serve.json config file

      {
       "renderSingle":  false,
       "cleanUrls":     false,
       "trailingSlash": false,
       "etag":          false,
       "symlinks":      false,
       "logReq":        true,
       "logRes":        true,
      
       "redirects": [
         {
           "engine":        "regex",
           "source":        "^/(hls-proxy/.+)$",
           "destination":   "http://localhost:8080/$1",
           "flags":         "",
           "decode":        false,
           "terminal":      true,
           "preserveQuery": false,
           "preserveHash":  false,
           "proxy":         true
         }
       ]
      }
    • extra example: Apache .htaccess file

      RewriteEngine On
      
      RewriteRule "^/?(hls-proxy/.+)$" "http://localhost:8080/$1" [P,L]
  3. test:

     video_url='https://demo.unified-streaming.com/k8s/features/stable/video/tears-of-steel/tears-of-steel.ism/.m3u8'
     curl -s --insecure "$video_url"
    
     video_url=$(echo -n "$video_url" | base64 --wrap=0)'.m3u8'
     video_url="http://serve.local/hls-proxy/${video_url}"
     # http://serve.local/hls-proxy/aHR0cHM6Ly9kZW1vLnVuaWZpZWQtc3RyZWFtaW5nLmNvbS9rOHMvZmVhdHVyZXMvc3RhYmxlL3ZpZGVvL3RlYXJzLW9mLXN0ZWVsL3RlYXJzLW9mLXN0ZWVsLmlzbS8ubTN1OA==.m3u8
     curl -s "$video_url"
  4. watch video in browser

notes:

wimme commented 10 months ago

Thanks for all the info. I created the following reverse proxy rule on the web server:

https://host/hls-proxy/(.*) --> webserver --> http://hlsproxy:8080/hls-proxy/{R:1}

What I was missing was that I had to put the subfolder in the HLS proxy URL. I can confirm, the leading path in the request gets echoed back, so running it from a sub folder seems to work fine!

The remaining issue I have is to handle the HTTPS encryption on the front-end web server.

Requesting url: https://host/hls-proxy/aHR0cHM6Ly90ZXN0LXN0cmVhbXMubXV4LmRldi94MzZ4aHp6L3gzNnhoenoubTN1OA==.m3u8

This results in:

#EXTM3U
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=2149280,CODECS="mp4a.40.2,avc1.64001f",RESOLUTION=1280x720,NAME="720"
http://host:80/hls-proxy/aHR0cHM6Ly90ZXN0LXN0cmVhbXMubXV4LmRldi94MzZ4aHp6L3VybF8wLzE5MzAzOTE5OV9tcDRfaDI2NF9hYWNfaGRfNy5tM3U4.m3u8
...

I can't auto-redirect it to HTTPS because the website uses HTTPS, so it gets blocked in the browser: "Mixed Content: The page at '<URL>' was loaded over HTTPS, but requested an insecure XMLHttpRequest endpoint '<URL>'. This request has been blocked; the content must be served over HTTPS."

I can probably workaround this by configuring the certificates in the HLS proxy directly, although it's not ideal.

warren-bank commented 10 months ago

hmm.. good point.

as you say, it isn't ideal.. but it would work to:

  1. run an instance of HLS Proxy to service public port 80:
     hlsd -v 3 --host "serve.local:80" --port 8080
  2. run another instance of HLS Proxy to service public port 443:
     hlsd -v 3 --tls --host "serve.local:443" --port 8081
  3. add a reverse proxy rule for each:
     http://host:80/hls-proxy/(.*)   --> webserver --> http://localhost:8080/hls-proxy/{R:1}
     https://host:443/hls-proxy/(.*) --> webserver --> https://localhost:8081/hls-proxy/{R:1}

alternatively, maybe I should:

In which case:

  1. run an instance of HLS Proxy to service public port 443:
     hlsd -v 3 --host "serve.local:443" --port 8080
  2. add a single reverse proxy rule:
     https://host:443/hls-proxy/(.*) --> webserver --> http://localhost:8080/hls-proxy/{R:1}

I can't imagine this easter-egg of an exception biting anybody unexpectedly. Thoughts?

warren-bank commented 10 months ago

note (to self)..

the touchpoint for making this change is here

for example:

  result.redirected_base_url = `${ (is_secure || (host && host.endsWith(':443'))) ? 'https' : 'http' }://${host || req.headers.host}${expressjs.get_base_req_url(req) || matches[1] || ''}`
warren-bank commented 10 months ago

v3.4.1 adds that change.. it's already available on npm

wimme commented 10 months ago

Awesome, this is great. Tested and deployed, works perfect. Thanks, very much appreciate your effort on this.