Domain fronting with Cloudflare Pages

I'm trying to replace one part of an existing website (hosted more traditionally) with a Cloudflare Pages site that has functions support as well, the functions are existing workers code I already have in deployment. From what I can see the recommended way to also serve static site with workers code is to transition it to pages but I'm finding some problems with it. Specifically my current worker is using routes (https://developers.cloudflare.com/workers/configuration/routing/routes/) to only run on specific paths and sometimes also pass through the request to the origin as necessary. I don't see both triggering on specific paths and passing to the origin being possible with Cloudflare Pages and Functions (custom domains only supports DNS records it seems and no pass through is documented to be possible). Essentially POST https://example.com/foo currently goes to the worker first then either get processed there and returned or forwarded to the origin to respond, I want to keep this behaviour. At the same time I want to add GET https://example.com/bar to serve a static page from Cloudflare Pages while GET https://example.com will still go through to my origin. I hope that is clear. What are my options here?
Cloudflare Docs
Routes · Cloudflare Workers docs
Routes allow users to map a URL pattern to a Worker. When a request comes in to the Cloudflare network that matches the specified URL pattern, your …
17 Replies
Hard@Work
Hard@Work3mo ago
So just to confirm, when you say "passed to the origin", do you mean passing it to Pages, or to a separate origin?
limzykenneth
limzykenneth3mo ago
To the same origin but not on cloudflare, ie. it is doing fetch(req) or ctx.passThroughOnException()
Cloudflare Docs
Context (ctx) · Cloudflare Workers docs
The Context API in Cloudflare Workers, including waitUntil and passThroughOnException.
Hard@Work
Hard@Work3mo ago
In the case of Pages, it is the origin, so you can't have a secondary origin behind it You would need to have a separate DNS record to point to/fetch(which would also incur requests)
limzykenneth
limzykenneth3mo ago
That's what I thought, so I can't use Pages in this case then? Should I use Workers Site for hosting the static page or is that deprecated and will be removed soon?
Hard@Work
Hard@Work3mo ago
It's deprecated, in the sense that it is no longer supported by Cloudflare. However, it doesn't rely on any features that aren't public anyway, so as long as you are willing to take that risk, you can use Sites indefinitely
limzykenneth
limzykenneth3mo ago
Does that mean the [site] key in wrangler.toml will still continue to work or am I better off going with a more custom solution for deployment of static files?
Hard@Work
Hard@Work3mo ago
Is your origin an A/AAAA Record, or a CNAME?
limzykenneth
limzykenneth3mo ago
A Record
Hard@Work
Hard@Work3mo ago
What you can do is create a separate DNS record for your origin, then fetch it from within your Functions Like so:
export function onRequestGet() {
...
const originRes = await fetch("https://your.origin.dns.record", {
cf: {
resolveOverride: "https://your.pages.dns.record",
}
});
}
export function onRequestGet() {
...
const originRes = await fetch("https://your.origin.dns.record", {
cf: {
resolveOverride: "https://your.pages.dns.record",
}
});
}
You can even put a Firewall Rule on top of https://your.origin.dns.record, which prevents anyone but your Function from requesting your origin directly
limzykenneth
limzykenneth3mo ago
Hmm...I'm not sure I understand this. Say I have my origin at https://example.com with A record to an IP address and I only need the static Cloudflare Pages on https://example.com/bar. Would I be deploying the pages to https://bar.example.com instead then use resolveOverride in the fronting worker to resolve requests to https://example.com/bar to https://bar.example.com? If that's the idea I guess it could work but I slightly prefer doing just one deployment of a worker/pages instead of deploying twice, once the domain fronting worker and another for the pages. I'll need to think about my setup a bit I guess.
Hard@Work
Hard@Work3mo ago
It would be the other way around. https://example.com would be your Pages Project, then Functions proxy all requests except those to https://example.com/bar to https://bar.example.com(with the resolveOverride)
limzykenneth
limzykenneth3mo ago
Do you mean the Functions will resolve all requests except for https://example.com/bar to my origin's A record IP address with resolveOverrride? Instead of https://bar.example.com since I have no reason to deploy there if the pages is to be on https://example.com
Hard@Work
Hard@Work3mo ago
No, you would still require an A record on bar.example.com. Functions cannot fetch IP addresses directly
// fetches to https://example.com
export function onRequest({ request }) {
...
const originRes = await fetch("https://bar.example.com", {
...request
cf: {
resolveOverride: "https://example.com",
}
});
}
// fetches to https://example.com
export function onRequest({ request }) {
...
const originRes = await fetch("https://bar.example.com", {
...request
cf: {
resolveOverride: "https://example.com",
}
});
}
limzykenneth
limzykenneth3mo ago
Right I think I get it now, so I'll point my origin IP to bar.example.com instead and deploy the pages to example.com then use resolveOverride to proxy the request as needed, if that is the gist of it?
Hard@Work
Hard@Work3mo ago
Yup. You can also add a WAF Rule to block all requests not from your Functions
limzykenneth
limzykenneth3mo ago
I guess that can possibly work as well. Will need to think about whether to go with this or workers site maybe. Thanks!
Hard@Work
Hard@Work3mo ago
I would say Pages is probably the smoother option here, though it isn't ideal that you would still have to pay for requests that are forwarded directly to the origin
Want results from more Discord servers?
Add your server