Search code examples
node.jssecuritynetworkingproxyvideo-streaming

Proxying a HLS (.m3u8) video streaming server


I don't have too much knowledge about proxies but I do understand them a bit, I have a CDN which serves my video files in hls format, lets call it mycdn.com, I also have a proxy server myproxy.com, for security reasons mycdn rejects all the requests which are not from myproxy, the only reason I have this proxy is to append custom header in each request, so for every .m3u8 and .ts i wanna send some custom data, the problem with this setup is, I consume 2x the network bandwidth, assuming my client requests for 1gb of video, I first ask it from proxy, proxys asks its from cdn, cdn gives it to proxy, proxy gives it to client, atleast this is what I feel is happening, which effectively consumes 2gb of data per gb of video streamed, I have some code written in nodejs, what methods can i follow to incur alomst no bandwidth cost at proxy, I am fine with whatever data it takes to add those extra headers.

router.use(
  '/:resolution/:videoId',
  (req, res, next) => {
    // @ts-ignore
    req.customParams = {
      resolution: req.params.resolution,
      videoId: req.params.videoId,
    };
    next();
  },
  createProxyMiddleware({
    target: `https://mycdn.com/somevideoid`,
    changeOrigin: true,
    preserveHeaderKeyCase: true,
    selfHandleResponse: true,
    pathRewrite: (path, req) => {
      // @ts-ignore
      return `/${req.customParams.resolution}/${req.customParams.videoId}`;
    },
    on: {
      proxyRes: (proxyRes, req, res) => {
        res.writeHead(proxyRes.statusCode || 400, proxyRes.headers);
        proxyRes.pipe(res);
      },
    },
  }),
);

Solution

  • I also have a proxy server myproxy.com, for security reasons mycdn rejects all the requests which are not from myproxy

    Kinda defeats the whole purpose of the CDN, doesn't it? You should reconsider your application's architecture so that it doesn't need this proxy at all. Clients should be able to fetch directly from your CDN.

    the only reason I have this proxy is to append custom header in each request, so for every .m3u8 and .ts i wanna send some custom data

    Nowhere in your code are you adding custom headers...

    the problem with this setup is, I consume 2x the network bandwidth

    Well, yeah, and it's not so great for your users too, who undoubtedly now have pointless overhead with yet another layer inserted in via your Node.js application, which is not hosted all over the world like your CDN would be.

    I have some code written in nodejs, what methods can i follow to incur alomst no bandwidth cost at proxy

    Don't proxy. That's it.

    Look, you've defeated pretty much the whole reason for using CDN, and not only that but the main reason for HLS as well. If you were going to serve your video from Node.js in any case, you could just be serving video streams directly via HTTP and then you could have skipped all the overhead and added latency of HLS. You've made basically the worst of all worlds tradeoffs here.

    And again, nowhere in your code are you adding headers. You're rewriting the URL, that's it, which doesn't require proxying. You could have added those parameters client-side. Worst case scenario, if they had to come from server-side, you could use a 307 redirect with Location: header in the response, but even that just adds extra overhead. And, to have the client tell you these player statistics every, single, segment, is really a total waste of time and resources.

    Separate your concerns. Let the CDN do the file serving for your HLS stream. Whatever logging or other things you're doing with this other data, do it out-of-band from the video stream.