Worker Requests to Origin are Stopped by Cloudflare Challenges

I believe my resizing workers are unable to fetch raw images from my original server, because my Cloudflare firewall rules see the edge server is in a country I’ve configured to present a challenge page.

Scenario: A user from a country I’ve put on a firewall “challenge” list is present with a challenge page. Even when the user meets and passes the challenge page, the worker attempting to access the origin image is being blocked with yet another, internal challenge page.

I can understand Cloudflare protecting any request before it gets to the worker, but Cloudflare’s own workers should never be presented with a Cloudflare challenge page! Basically, Cloudflare should always implicitly trust its own edge servers, regardless of the country they reside in.

Below is the error I get when my image resizing worker tries to access an image, when the request is made from a Cloudflare edge server located in a country for which I’ve requested a challenge page.

In response to a request to https://www.example.com/sample.jpg:

status: 502
statusText: Bad Gateway
headers: {}
redirected: false
url: 
webSocket: null

I cannot seem to get around this. I cannot use direct IP access to my origin server, as Cloudflare workers are not allowed direct IPs. Lifting all security for the origin image in page rules has not helped.

Any ideas?

Here is my worker code:

addEventListener("fetch", (event) => {
	event.respondWith(
		handleRequest(event.request).catch(
			(err) => new Response(err.stack, { status: 500 })
		)
	);
});

async function handleRequest(request) {

	const ORIGIN = 'https://www.example.com/'; // origin of the images, with trailing slash

	// Parse request URL to get access to query string
	const url = new URL(request.url);

	const path = url.pathname;  // get path and file part of URL
	console.log('path: '+path);

	// Cloudflare-specific options are in the cf object.
	const options = { cf: { image: {} } };

	// Set defaults
	options.cf.image.width = 600;   // default to something not too monstrous
	options.cf.image.fit = 'scale-down';
	options.cf.image.sharpen = 0.6;
	options.cf.image.quality = 95;
	options.cf.image.background = '#FFFFFF';

	const imageURL = ORIGIN + 'images/sample.jpg';	// get origin server's full path to image, hardcoded here for simplicity

	// Build a request that passes through request headers,
	// so that automatic format negotiation can work.
	const imageRequest = new Request(imageURL, {
		headers: request.headers,
	});

	// Returning fetch() with resizing options will pass through response with the resized image.
	let response = await fetch(imageRequest, options);

	// Reconstruct the Response object to make its headers mutable.
	response = new Response(response.body, response);

	if (response.ok || response.status == 304) {
		response.headers.set(
			'Cache-Control',
			'public, max-age=0, immutable',
		);

		// Set Vary header
		response.headers.set('Vary', 'Accept');

		return response;
	} else {
		return new Response(
			`Could not fetch the image — the server returned HTTP error:
status: ${response.status}
statusText: ${response.statusText}
headers: ${JSON.stringify(response.headers)}
redirected: ${response.redirected}
url: ${response.url}
webSocket: ${response.webSocket}

... in response to a request to ${imageURL}`,
			{
				status: 400,
				headers: {
					'Cache-Control': 'no-cache',
				},
			},
		);
	}
}

This has been fixed, or at least the workaround is good enough.

A Cloudflare tech couldn’t reproduce this, but suggested a workaround to make a new firewall rule before my country challenge rule. The rule looks for a URI containing my origin image (“images/sample.jpg”) and sets the action to “Allow”. I had mistakenly believed a page rule set to “Disable Security” would accomplish the same thing.

This topic was automatically closed 3 days after the last reply. New replies are no longer allowed.