Workers Reverse Proxy Assets

Hi,

I am trying to set cloudflare workers up as a reverse proxy. Aim is to have
mysite.com/ to load data from tahini.feast-it.com and
mysite.com/suppliers to load data from tahini.feast-it.com/suppliers and
mysite.com/login to load data from platform.feast-it.com.

There will be other routes for both of these, but this is enough for an example hopefully. Both of these are apps hosted on Vercel.
I have two basic workers that look like

addEventListener('fetch', event => {
  event.respondWith(handleRequest(event.request))
})

async function handleRequest(request) {
  const url = new URL(request.url)
  const hostname = 'https://tahini.feast-it.com'
  return fetch(`${hostname}${url.pathname}`)
}

They are loading the site (see https://testing.feastit.co.uk/) but everything in _next/static/* and external images are not loading. They just error with 522 if you look in the console.

Everything I can find points me to the most basic “Conditional Routing” example, which doesn’t contain this logic. All of the examples are really basic and I can’t find any decent, fleshed out reverse proxy with workers code.
Ideally I want a reverse proxy with assets and caching if anybody has an example?

I have also just noticed if I access it via the workers.dev url, it works totally fine.

Also my DNS setup for this subdomain is

I’m trying to solve the same problem, I think. We have a React app served under mydomain.com.
We want any requests to mydomain.com/newapp to server a second React app served that is available under newapp.mydomain.com. The code below works for the first click - it serves the newapp under the base domain. The problem is that the browser still knows it’s coming from newapp.mydomain.com and is adding that to the links - then we get issues trying to navigate to different domain. In essence, we are trying to mimic a NGINX reverse proxy. Any help would be greatly appreciated.

async function handleRequest(request) {
  const base = 'https://newapp.mydomain.com'
  const url = new URL(request.url)
  const { pathname, search, hash } = url
  // Rebuild the url to request from newapp.mydomain.com
  const destinationURL = base + pathname + search + hash
  
  let response

  if (pathname.startsWith('/newapp') ) {
    const originalResponse = await fetch(destinationURL)

    response = new Response(originalResponse.body, {
      status: originalResponse.status,
      headers: originalResponse.headers,
    })
  } else {
    response = await fetch(request)
  }

  return response
}

addEventListener("fetch", event => {
  event.respondWith(handleRequest(event.request))
})

It’s easier to use url.href if you want to reconstruct the original URL.
Notice that hashes are not passed to servers, only url parameters.

The problem here is probably that different contents have different content headers and types.

To be able to proxy all of it, you’ll need quite a lot of boilerplate to handle the situations.

For example, to proxy an image you cannot use response.body to fetch it using fetch, you’d need to stream the binary data, know which image type it is and set the appropriate headers for that specific image type.

Check this project for clues:

1 Like