The handleProxyRequest function provides the main functionality of the reverse proxy system. It receives an incoming request and forwards it to a target URL. Various adjustments are made to process the request and return the response to the client.
Originally, this Cloudflare reverse proxy was developed for customising third-party hosted shop pages, but as it is extremely flexible, it can also be used for any other purpose. Special focus is placed on the manipulation of CSP headers to enable the integration of external resources and to prevent the blocking of external resources as well as the precise injection of HTML content into the page.
In addition, it was important during development that it will be possible to overwrite specific routes and thus define new routes.
It is recommended to use Cloudflare Wrangler to deploy the worker. To do this, simply clone the Git repository and then adapt the wrangler.toml file and the index.js file to your own requirements. A real domain can then be assigned to the worker in the Cloudflare settings (Workers & Pages).
git clone https://github.com/valentinwinkelmann/Cloudflare-Reverse-Proxy-Worker.git [your-name]
cd [your-name]
npm installNow adapt the
wrangler.tomlfile and also theindex.jsfile to your needs.
# wrangler.toml
name = "reverse-proxy" # name of the worker
main = "src/index.js"
compatibility_date = "2023-11-10"
[limits]
cpu_ms = 5
[vars]
REVERSE_PROXY_SOURCE = "https://targetpage.com" # the URL of the target page
REVERSE_PROXY_TARGET = "https://newpage.com" # the URL of the new pagewrangler login # if not yet logged in
npm start # for testing
npm deploy # to deployThat's all, your reverse proxy is now ready to use. You can deploy future changes at any time with npm deploy. π
request: This is the request object that contains all the information about the incoming request.targetUrl: This is the URL to which the request is to be forwarded.config: This is an optional configuration object that contains various settings for handling the request. If no configuration object is provided, an empty object is used.
The configuration object can contain various properties to adjust the behaviour of the handleProxyRequest function. Here are some examples:
-
trustedScriptSrc: An array of URLs that are considered trusted sources for scripts. -
trustedStyleSrc: An array of URLs that are considered trusted sources for stylesheets. -
scriptSrc: An array of objects containing information about scripts to be inserted into the page. Each object should contain the propertiessrc(the URL of the script) andtarget(the location where the script should be inserted). -
styleSrc: An array of objects containing information about stylesheets to be inserted into the page. Each object should contain the propertiessrc(the URL of the stylesheet) andtarget(the location where the stylesheet should be inserted). -
htmlInjection: An array of objects containing information about HTML content to be inserted into the page. Each object should contain the propertiesselector,position,content,routes,excludeStatusCodeandincludeStatusCode. -
clientsideUrlRewrite: A Boolean value that specifies whether the URL should be rewritten on the client side or not.
router.all('*', (request, env) => {
const url = new URL(request.url);
const targetUrl = env.REVERSE_PROXY_SOURCE + url.pathname + url.search;
return handleProxyRequest(request, targetUrl, {
trustedScriptSrc: [
"src.trusted-domain.com"
],
trustedStyleSrc: [
"src.trusted-domain.com",
"fonts.googleapis.com"
],
scriptSrc:
[
{src: `https://${url.hostname}/src/urlRewrite.js`, target: "body"}
],
styleSrc:
[
{src: "https://src.trusted-domain.com/css/style.css", target: "head"}
],
htmlInjection:
[
{selector: "body", position: "outside-after", content: "<h1>Injected HTML</h1>"},
{selector: "body", position: "inside-before", content: "<h1>Injected HTML</h1>"},
{selector: "body", position: "outside-after", content: "<h1>Injected HTML ONLY ON POSTS</h1>", routes: ["/posts"]},
{selector: "body", position: "inside-before", content: "<h1>Injected HTML ONLY ON SINGLE POST</h1>", routes: ["/p/*"], excludeStatusCode: [404]},
{selector: "body", position: "inside-before", content: "<h1>This single post has a 404</h1>", routes: ["/p/*"], includeStatusCode: [404]},
],
clientsideUrlRewrite: true
});
});In this example, the
handleProxyRequestfunction is used to handle all incoming requests and forward them to a specific target URL. Various configuration options are used to adjust the behaviour of the function. The index.js file already contains an example configuration.
In the case of the original use I thought of, it was necessary to rewrite client-side generated links. Since our reverse-proxy target is a React app, some links are only generated at runtime. This function can be used to generate a JavaScript that contains a list of from -> to value pairs. To use this JavaScript, it is possible to provide it yourself via a custom route. An example of such an application could look like this:
router.get('/src/urlRewrite.js', (request, env) => {
const currentHost = new URL(request.url).hostname;
const rewriteScript = getClientSideUrlRewriteScript([
{ from: env.REVERSE_PROXY_SOURCE + "/l/", to: `https://${currentHost}/l/` },
//...
]);
return new Response(rewriteScript, {
headers: { 'content-type': 'application/javascript' },
});
});In this example, the
getClientSideUrlRewriteScriptfunction is used to generate a JavaScript that contains a list offrom->tovalue pairs. This JavaScript is then provided via a custom route.
valuePairs: This is an array of objects containing information about the URL rewrite. Each object should contain the propertiesfrom(the URL to be replaced) andto(the URL to replace the original URL).
Many sites legitimately block Cloudflare from accessing their pages via a reverse proxy. However, if these providers allow us to use a custom domain via CNAME, we can use a workaround that allows us to reach the site via a reverse proxy. All we have to do is set up a subdomain that points to the target URL as CNAME. We can then use this subdomain as the target URL. In some cases, this is possible because the respective provider protects its own domains from reverse proxy requests, but our custom domains are not subject to any specific protection measures. An example of such a configuration could look like this:
username.example.com <-[CNAME]-> temp.ourdomain.com <-[reverse proxy]-> ourdomain.com
This project has been developed by @VWGameDev and is published under the MIT licence.
- Itty Router : Copyright (c) 2020 Kevin R. Whitley
I assume no liability for any damages that may result from the use of this project and provide this project without warranty of any kind. I also expressly point out that the use of reverse proxies should only be done with the permission of the operator of the target URLs. Furthermore, I do not guarantee the functionality, security or reliability of this project. However, I am happy to receive any feedback and pull requests.