Skip to content

Instantly share code, notes, and snippets.

@markf3lton
Created July 22, 2019 18:09
Show Gist options
  • Save markf3lton/c811d993d1bcbc210a9464d8a5a9d4bd to your computer and use it in GitHub Desktop.
Save markf3lton/c811d993d1bcbc210a9464d8a5a9d4bd to your computer and use it in GitHub Desktop.
Approaches to geolocation

Geolocation strategies

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

PHP can access these headers:

$country_code = $_SERVER["HTTP_CF_IPCOUNTRY"];

.htaccess

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>

Javascript

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 Workers

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/

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment