Using CloudFlare Workers as a GeoIP service

Using CloudFlare Workers as a GeoIP service

How to avoid using third party GeoIP service.

CloudFlare has a Workers service similar to AWS CloudFront Functions. It allows requests to be intercepted and processed. One of the possible use case is as your own GeoIP service without signing up for a third-party GeoIP provider.

To do so, go to Workers section in CloudFlare and create your custom sub-domain under workers.dev, for example mydomain.workers.dev. Then create a new service in the sub-domain such as geoip.mydomain.workers.dev.

Once done, you can type the code directly on the dashboard as below:

export default {
  async fetch(request, env) {
    return await handleRequest(request)
  }
}

async function handleRequest(request) {
  const apiKey = 'AAAAAA'; // Enter your preferred API key.
  if (request.method == 'POST' 
      && request.headers.get('x-api-key') == apiKey) {
    const country = request.cf && request.cf.country ? request.cf.country : '';
    return new Response(JSON.stringify({
      'COUNTRY': country,
    }), {
      status: 200,
      headers: {
        'content-type': 'application/json;charset=UTF-8',
        'Access-Control-Allow-Origin': '*',
      },
    });
  } else if (request.method == 'OPTIONS') {
    return new Response(null, {
      headers: {
        'Access-Control-Allow-Origin': '*',
        'Access-Control-Allow-Methods': 'POST,OPTIONS',
        'Access-Control-Allow-Headers': 'x-api-key, content-type',
        'Access-Control-Max-Age': '86400',
      },
    });
  } else {
    return new Response(null, {
      status: 405,
      statusText: 'Method Not Allowed',
    });
  }
}

You can add an API Key for authentication to prevent unauthorised use.

Do note that CloudFlare Workers has daily limit of 100k requests and any request above that limit will either be blocked or pass-thru depending on your configuration. This limit applies whether the authentication fails or pass. You should only use this free plan service when you are sure you will not exceed 100k daily requests.

Once the worker is deployed, you can call it like below:

fetch('https://geoip.mydomain.workers.dev/', {
  method: 'POST',
  headers: {
    'Content-type': 'application/json; charset=UTF-8',
    'x-api-key': 'AAAAAA'
  }
})
.then(res => res.json())
.then(console.log)

You can also route this worker to your own domain, such as geoip.mydomain.com. Just go to your domain in the dashboard, create a CNAME for geoip and then route the worker to it.