Cloudflare is one of the most popular CDNs around. Thanks to free bandwidth and good features it is possible to run high-traffic sites relatively cheaply on Cloudflare.
However, using Cloudflare to optimize images may increase the cost simply because the pricing of Cloudflare Images is based on the number of origin images, transformations and the number of requests.
Offloading image optimization to ImageEngine may allow you to still utilize Cloudflare's free bandwidth while serving optimized images.
Cloudflare's caching policy
For images, Cloudflare has an aggressive default cache policy based on the file extension. Moreover, Vary
header is not honored. In short, this means that by default images can only be optimized to the same format as it is at the origin.
The alternative is to use Transform Rules, Cache Rules, or Cloudflare Workers to optimize images better.
General flow
The image request from the client first hits the CDN which has the ImageEngine delivery address configured as origin. Upon a cache miss, the CDN makes a request to its origin; ImageEngine. ImageEngine detects the proper optimization algorithm to use. If the image is not in ImageEngine cache, ImageEngine fetches it from the (actual) origin. The response is cached with a cache key computed in the same way both on ImageEngine and the CDN.
The challenge for ImageEngine is to decide the best possible way to optimize an image while it is still cachable for the CDN in front.
To address this, ImageEngine works in a "default" mode and an "informed" mode.
Default mode
ImageEngine can detect the CDN making the request and based on that identify how the image can be optimized yet still compliant with the default caching strategy of the CDN.
Informed mode
Informed mode is when ImageEngine is informed that the CDN making the request has implemented ImageEngine support in a specific manner, ensuring that the cache key is computed the same way both in ImageEngine and in the CDN.
Available modes for Cloudflare
Identifier | Description |
cloudflare,0 |
The default mode. Applied automatically when ImageEngine is the origin of Cloudflare. ImageEngine assumes that Cloudflare is configured with the "Standard" cache policy, which includes the query string in the cache key. |
cloudflare,1 |
Informed mode, with workers integration. This identifier is actively set in all requests from Cloudflare to ImageEngine. If used, this must follow the documented approach in this article. |
cloudflare,2 |
Informed mode, with Cloudflare cache bypass. This identifier is actively set in all requests from Cloudflare to ImageEngine. If used, this must follow the documented approach in this article. |
Default Mode: cloudflare,0
When ImageEngine detects that Cloudflare is in front, ImageEngine will only optimize the image to its original format and not perform any resizing. This is because Cloudflare only considers the request URL in its cache key algorithm by default.
ImageEngine will still work as usual with URL directives either set by the client or using Transform Rules in Cloudflare.
Transform Rules
With transform rules, it is possible to alter the URL (which is in the cache key) based on values in the HTTP header.
To enable format conversion, one rule for each format must be defined. To create a transform rule, go to "Rules" -> "Transform Rules" and hit "Create rule" under the "Rewrite URL" tab.
- Give the rule a name.
- Choose "Custom filter expression", and input this expression:
(http.host eq "hostname.com" and any(http.request.headers["accept"][*] contains "webp"))
(replace "hostname.com" with your own host). This expression checks if theAccept
header advertises WEBP support. - Choose "Rewrite to..." and supply a static string according to the directives documentation for ImageEngine. In this case
imgeng=/f_webp
will be appended to any request to ImageEngine, resulting in a WEBP image being served.
Cache Rules
Cache Rules may be useful to enable lightweight device detection. Cloudflare offers a feature to categorize the requesting device as a mobile, tablet, or desktop. Based on this, ImageEngine can downsize a huge origin image more to a mobile device than a Desktop device.
To create a cache rule which forwards device type to ImageEngine navigate to "Caching" -> "Cache Rules" and click "Create rule".
- Give the rule a descriptive name. "device types", for example.
- Under "When incoming requests match…" define the appropriate condition when the rule will execute. Usually, some generic definitions like when
hostname
is equal to your hostname is OK. - Scroll down to the Cache key heading and enable "Cache by device type":
After this rule is deployed, Cloudflare will send the device type to ImageEngine in the CF-Device-Type
header.
Informed Mode with Cloudflare Workers: cloudflare,1
With Cloudflare Workers it is possible to programmatically compose the cache key Cloudflare will use in its cache.
This means that more ImageEngine features can be utilized, such as format conversion, resizing, and dynamic compression.
Note: Cloudflare offers two ways to customize the cache key in workers:
- Customize the cache key using
fetch()
.
This feature is only available on Cloudflare Enterprise plan.
If you are on the Cloudflare Enterprise plan, here is a gist with a worker usingfetch()
. - Customize the cache key using the Cloudflare cache API.
This is available on all Cloudflare plans. However, if your site is set up with tiered cache, the cache API is not available to workers. Using fetch() is then the only option.
This gist that may serve as a starting point for the ImageEngine integration using the Cloudflare cache API.
You may customize the code samples to your needs (use at your own risk), however, some functionality is critical:
ImageEngine URL
const imageEngineURL = https://${IMAGEENGINE_DELIVERY_ADDRESS}${path};
This is the complete image url as if it was fetched through ImageEngine directly. Make sure that IMAGEENGINE_DELIVERY_ADDRESS
is the correct delivery address as shown in the ImageEngine control panel. In the example gist, the delivery address is held in an environment variable.
Cache key
This section defines the headers needed to compute the cache key. This part ensures that both Cloudflare and ImageEngine use the same cache key.
const cacheKey = url+request.headers.get('Accept')
+request.headers.get('Accept')
+request.headers.get('sec-ch-width')
+request.headers.get('sec-ch-dpr')
+request.headers.get('sec-ch-viewport-width')
+request.headers.get('ect')
+request.headers.get('save-data')
+request.headers.get('sec-ch-form-factor');
imgeng-inputcdn
request header
This header must be sent with the cache miss request to ImageEngine! The header informs ImageEngine which cache key computation strategy to use.
If this header is not present the cache will likely be polluted and wrong image variants may be served to end users.
originRequest.headers.set("imgeng-inputcdn", "cloudflare,1");
Set up the worker
Follow Cloudflare's documentation to get started with workers.
Once the worker is deployed to Cloudflare, it's listed under "Workers and Pages" in the left menu.
The worker has already got a "route", typically ending with "*.workers.dev". For this worker to be invoked on requests to your website, an additional route must be added.
Click "Add route" under the "Trigger" tab.
Add a route that will trigger the worker. Usually, this is the hostname/domain used on your website to serve images followed by /*
. For example images.example.com/*
.
Alternatively, if images are served from a specific path, the route could be example.com/images/*
.
Read more about routes in the Cloudflare documentation.
The "Zone" is the Zone where the hostname in the route is defined.
Clicking "Add route" will make the worker execute for the specified route.
Informed Mode with cache bypass: cloudflare,02
You can also configure Cloudflare to bypass cache entirely, and simply proxy all traffic to ImageEngine. This setup has two major advantages:
- All ImageEngine features available.
- Use Cloudflare network features like WAF, DDoS, domain management etc.
To enable this mode, follow these steps.
1. Set the imgeng-inputcdn
request header
To let ImageEngine know that Cloudflare cache is bypassed, the header imgeng-inputcdn
must be added with the value cloudflare,2
Navigate to Rules->Transform rules and click the "Modify Request Header" tab.
In the example above, the header is added to all requests matching the path /images
. Configure this trigger to match your needs. The trigger must match all requests to ImageEngine.
2. Create a cache rule to bypass the cache
Next, create the rule to bypass the cache. Navigate to "Cachign" -> "Cache rules" to create a new rule.
Make sure that the condition when this rule is triggered, matches the rule for the custom header in step 1).
Next, select "Bypass cache" and save the rule.
Now, all requests to /images
will bypass the cache, optimized and served by ImageEngine.
Benefits summarized
We've seen how ImageEngine can be used together with Cloudflare to optimize images and at the same time use Cloudflare for caching. This setup has several benefits:
All Cloudflare features available
In addition to serving the cached images from Cloudflares fast and global CDN, other features such as WAF, DDOS protection, and statistics are available.
Reduced, more predictable cost
Compared to Cloudflare Images cost, which is not based on bandwidth but the number of origin images and requests, ImageEngine offers a cheaper (and better) solution because the ImageEngine pricing is not based on requests, variants, or origin images. ImageEngine pricing is based on bandwidth, but because Cloudflare is serving all cache hit traffic, the bandwidth needed on the ImageEngine plan will be just a fraction of the total image traffic to the website.
The setup described above, enables you to serve optimized images while still enjoying the free Cloudflare bandwidth.
Better image optimization
Cloudflare Images offers rudimentary image optimization and managing the images and transformations may be cumbersome. With ImageEngine no upload or predefined transformations is necessary.
Comments
0 comments
Please sign in to leave a comment.