Cloudflare adds the CF-IPCountry header to all incoming requests, other CDNs may have something similar.
You can the headers incoming in balancer traffic:
[12:25:19] [email protected]:/home/markfelton# varnishlog | grep CF-IPCountry
- ReqHeader CF-IPCountry: JP
- ReqHeader CF-IPCountry: JP
- ReqHeader CF-IPCountry: JP
- ReqHeader CF-IPCountry: JP
- ReqHeader CF-IPCountry: US
- ReqHeader CF-IPCountry: JP
- ReqHeader CF-IPCountry: JP
- ReqHeader CF-IPCountry: US
- ReqHeader CF-IPCountry: US
- ReqHeader CF-IPCountry: DE
- ReqHeader CF-IPCountry: JP
- ReqHeader CF-IPCountry: CZ
- ReqHeader CF-IPCountry: DE
- ReqHeader CF-IPCountry: CN
- ReqHeader CF-IPCountry: JP
- ReqHeader CF-IPCountry: GB
- ReqHeader CF-IPCountry: FR
PHP can access these headers:
$country_code = $_SERVER["HTTP_CF_IPCOUNTRY"];
If you want to avoid a Drupal bootstrap, consider using .htaccess. This example from StackOverflow shows how: https://serverfault.com/questions/357716/can-apache-conditionally-perform-a-rewrite-from-a-custom-http-header
Important note: You may need to Vary it so that Varnish and Cloudflare won't cache it.
Sample code for .htaccess
<IfModule mod_rewrite.c>
RewriteEngine on
<IfModule mod_setenvif.c>
<IfModule mod_headers.c>
# SetEnv (mod_env) gets applied after mod_rewrite does,
# however, mod_setenvif gets applied before!
SetEnvIf CF-IPCountry ^ LANDING_PAGE=default
SetEnvIf CF-IPCountry ^(GB)$ LANDING_PAGE=gb_site
SetEnvIf CF-IPCountry ^(FR)$ LANDING_PAGE=fr_site
SetEnvIf CF-IPCountry ^(US)$ LANDING_PAGE=us_site
SetEnvIf CF-IPCountry ^(AU)$ LANDING_PAGE=au_site
RewriteCond %{ENV:LANDING_PAGE} ^us_site$
RewriteRule ^ https://www.mysite.com/us_site [L,R=301,E=VARY_ON_CF_IPCountry]
RewriteCond %{ENV:LANDING_PAGE} ^default$
RewriteRule ^ https://www.mysite.com/ [L,R=301,E=VARY_ON_CF_IPCountry]
Header always append Vary CF-IPCountry env=VARY_ON_CF_IPCountry
</IfModule>
</IfModule>
</IfModule>
</FilesMatch>
For a javascript-based implementation consider something like this: https://www.drupal.org/docs/8/creating-custom-modules/adding-stylesheets-css-and-javascript-js-to-a-drupal-8-module#configurable
Instruct dynamic page cache to create page variations based CF-IPCountry header. For example, in hook_page_attachments() $page['#cache']['contexts'][] = 'headers:cf-ipcountry';
There is yet another option — Cloudflare Custom Cache Keys that can be used with page rules. This makes your CF caching more granular when the origin generates different responses based on something other than the URL.
Cloudflare has ~180 data centers around the world so it is a great platform for "serverless" computing:
For an 101-level overview, start with this blog post: https://blog.cloudflare.com/introducing-cloudflare-workers/
At a high-level, Workers allow you to
- Improve cache hit rate, for example by rewriting incoming requests
- Streamline how your applications communicate with an increasing number of APIs
- Reduce dependencies on origin infrastructure
- Collect analytics without running code in the user's browser
- Deliver a better user experience tailored to users of device or network (continent, region, etc)
- Route different types of requests to different origin servers
- Mitigate the impact of malicious bots on infrastructure
- Build "server-less" applications that rely entirely on web APIs
- Much more (ask for a demo)
Using the Country-specific example, with Workers, you can implement locale-based redirects (E.g. if visitor country is Germany based on the Accept-Language header).
Workers have surpassed custom VCL (cVCL) in virtually every use case pertaining to business/application logic.
Workers have the advantage of being written in a more developer-friendly language (javascript, instead of the C-like language used by VCL). There is an interactive playground to test your logic and ideas. Here's a link to the Playground: https://cloudflareworkers.com/#12a9195720fe4ed660949efdbd9c0219:https://tutorial.cloudflareworkers.com
The existing library of Recipes includes examples for customers doing a "VCL to Workers" conversion: https://developers.cloudflare.com/workers/recipes/vcl-conversion/conditionally-changing-a-url/
Here's a code example for blocking by Country IP that could be adapted to other business logic... https://developers.cloudflare.com/workers/recipes/country-blocking/
The Workers equivalent to the CF-IPCountry is the cf. object https://workers.cloudflare.com/docs/reference/runtime/apis/fetch/#the-cf-object
The Recipe Exchange is another place to find recipes: https://blog.cloudflare.com/cloudflare-workers-recipe-exchange/
More resources: https://developers.cloudflare.com/workers/recipes/ https://github.com/cloudflare/worker-examples https://community.cloudflare.com/tags/workers https://developers.cloudflare.com/workers/api/