Akamai EdgeWorkersでアクセス元の国に基づきリダイレクトを行う

# 1. はじめに
## 1.1. この記事の目的
今日、多様なサービスがインターネットを経由して提供されています。サービスの仕様を検討する際に、ユーザーがどの国からアクセスしたかに応じ、異なるWebページや機能を提供したい、というようなケースは比較的多く存在しているのではないでしょうか。

様々な実現方式がありますが、この記事ではAkamai EdgeWorkersを利用した方法を紹介します。

具体的には、アクセス元の国に基づき、異なるリダイレクト処理を行う仕組みを説明します。

この仕組みは、例えば、ある航空券予約サイトがグローバルに提供されている場合、カナダからのアクセスにはカナダ離発着の便を取り扱うサイトにリダイレクトさせるといったことができます。

なお、この仕組み自体は、Akamai TechDocsに掲載されているEdgeWorkers チュートリアルの1つである"[Redirect pages based on location](https://techdocs.akamai.com/edgeworkers/docs/redirect-pages-based-on-location)"に記載があります。

## 1.2. この記事の対象読者
この記事の対象読者は以下を想定しています。
- アクセス元の国に基づき異なるWebページや機能を提供する方法を模索されている方、もしくはそういった方法の提案を行う立場の方
- Akamai EdgeWorkersとAkamai配信設定を実装し検証可能な権限と環境をお持ちの方（必須ではありませんが、本記事を確認しながらご自身の検証環境でハンズオン頂くとより理解が深まる内容になっています）

## 1.3. Akamai EdgeWorkersを利用するメリット
実はこの機能自体、Akamaiの配信設定のみでも実現することは可能です。
一方で、EdgeWorkersを用いることで以下のようなメリットを得ることができます。
- メンテナンス性の向上（この仕組みを変更する際にAkamai配信設定の編集が不要）
- 学習コストの低減（一般的な技術であるJavaScriptにて機能を実装可能）

※Akamaiの提供するサービスの特徴を利用して本処理を実現する、より一般的なメリットは記事の最後に記載しました。

# 2. Webシステム構成概要
## 2.1. Webシステム構成概要図
まず、今回紹介するAkamai Edgeworkersを利用したWebシステム構成の全体像を確認します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2728604/55e02966-54be-8fc0-b359-dfe5055ab0e0.png)

## 2.2. 基本的な処理の流れ
エンドユーザーはまずAkamaiのCDN(正確にはEdge Server）に接続する構成になっています。
キャッシュできないコンテンツは、Akamai CDNを経由しOriginからコンテンツを取得します。
キャッシュ可能なコンテンツは、キャッシュがあればAkamai CDNよりコンテンツを取得します。
キャッシュがない場合やキャッシュの有効期限が切れている場合は、Akamai CDNを経由しOriginからコンテンツを取得します。
ここまではAkamaiのCDNを利用したごく一般的なWebシステムの処理の流れです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2728604/a6a257b1-82d9-b536-2d2c-25eed524b9ce.png)


## 2.3. アクセス元の国に基づく処理の流れ
次にアクセス元の国に基づく処理の流れ、すなわちAkamai EdgeWorkersがユーザーがどの国からアクセスしたかを判別しそれぞれに応じたリダイレクト処理を行う部分について確認していきます。
エンドユーザーからアクセス元の国に基づく処理を行うURL(path)にリクエストが来ます。Akamai CDNのEdgeWorkersコードが実行され、ユーザーがどの国からアクセスしたかを識別します。識別結果に基づいて国ごとにリダイレクト先のURLを生成し、そのURLへのリダイレクトをブラウザに指示する応答を返します。
このようにAkamai CDNによる一般的な処理とは異なり、Akamai EdgeWorkersがリクエスト内容を確認し、然るべきリダイレクト応答をするという処理となります。またこの処理に限定して言えばOriginシステムは必要ありません。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2728604/8511813c-0063-757c-d94a-afc1ba5a16a6.png)


## 2.4. 実現できること
この仕組みにより、以下のようなことが実現されます。

- カナダのユーザーにはトップレベルドメインをcaに変換したURLへリダイレクト
- イギリスのユーザーにはトップレベルドメインをco.ukに変換したURLへリダイレクト
- それ以外の国のユーザーにはトップレベルドメインをcomに変換したURLへリダイレクト

なお、アクセス元の国の識別はAkamai Edge Serverから見た送信元IPアドレス（ユーザーのIPアドレス）をInputに、Akamaiが持つEdgeScapeのデータを基に行なっています。EdgeScapeとは一言でいえば国情報データベースです。IPアドレスがどの国、都市に属するかといった情報を参照し利用することができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2728604/6da9b263-9bf6-dbb0-9c82-8748a4ad0de1.png)


# 3. EdgeWorkersとAkamai配信設定の実装方法
## 3.1. 前提構成
それでは実際に上記のAkamai EdgeWorkersの仕組みをWebシステム上に構築していきます。AkamaiのCDNを利用したWebシステムがすでに存在していることを前提とします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2728604/2ee43ab3-e756-58b9-1559-12ba8bc1eca9.png)

この仕組みを実装するにあたりOriginシステム側に変更は必要ありません。AkamaiのCDNで利用している配信設定の変更作業と、EdgeWorkersの新規設定作成により実現可能となります。
## 3.2. EdgeWorkersの実装
### 3.2.1. EdgeWorker IDの作成
まずEdgeWorker IDを作成します。EdgeWorker IDとは、「あるAkamai EdgeWorkersのコードを実行するための実行環境」のようなイメージと捉えてください。実行したいコードごとにEdgeWorker IDを用意し、それぞれのコードをデプロイ/処理させます。この作成が終わった時の構成イメージは以下のとおりです。

EdgeWorker IDが作成されていますが、実行するためのコードがデプロイされていません。またAkamai CDN上でどの配信設定とも関連付いておらず、まだ利用されることはありません。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2728604/03680ffc-04bc-efae-4358-e60b6848ed28.png)

手順は以下のとおりです。

Akamai Control Center（以下ACC）にアクセスします。アクセスしたら左上の☰をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2728604/8bbffb9d-6d78-3602-04bc-d7ec76e17b96.png)
次にCDN > EdgeWorkersリンクをクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2728604/19326bd1-d3e3-8b07-37ca-3f487da8b29a.png)

Create EdgeWorker IDをクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2728604/c6c54a4e-ea13-8a90-8285-f64929e36bc7.png)
ポップアップしたウィンドウにて必要事項を入力し、Create EdgeWorker IDボタンをクリックします。

（補足）

- Name: 任意の名前を入力します。将来複数のEdgeWorker IDを利用する際の識別性などを考慮します。
- Group: 自身の権限のあるグループの中から選択します。主に本EdgeWorker IDの管理をどのグループに属するユーザーにて実施するかという観点で選択します。
- Contact ID: 基本的に選択肢は1つしかないはずです。複数表示される場合はACC管理者に確認の上選択します。
- Resource tier: Dynamic ComputeとBasic Computeが選択可能です。それぞれリソースの制限が異なります。各リソースの制限は[こちら](https://techdocs.akamai.com/edgeworkers/docs/resource-tier-limitations)より確認可能です。検証/ハンズオン目的であればBasic Computeでも問題ありません。（コストの違いについてはACC管理者に確認してください）
- Description: 必要に応じ入力します。（空欄でもOK）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2728604/1173343c-df05-7be4-df46-30e5ed4fab59.png)

### 3.2.2. EdgeWorkers コードの作成
次に先ほど作成した、EdgeWorker ID（実行環境）で実際に動作させるコードを作成します。この作成が終わった時の構成イメージは以下のとおりです。

EdgeWorker ID上のコードがありますが、まだAkamai CDN上でactiveな状態にありません。またAkamai CDN上でどの配信設定とも関連付いておらず、まだ利用されることはありません。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2728604/3c33c4ca-f608-0399-1f29-a064d6e9fdd8.png)

手順は以下のとおりです。

まず、自身の端末ローカルで以下2つのファイルを作成します。

- マニフェストファイル（bundle.json）
```json
{
    "edgeworker-version": "1.0.0",
    "description" : "Perform redirect"
}
```

- ソースファイル（main.js）
```js
/*
(c) Copyright 2023 Akamai Technologies, Inc. Licensed under Apache 2 license.
Version: 0.1
Purpose:  Using EdgeScape geo data, redirect user to country specific content
Repo: https://github.com/akamai/edgeworkers-examples/tree/master/redirect-geo
*/

//Define the top level domain mapping for Canada, the U.S., and UK.
const tldMap = {
  CA: '.ca',
  GB: '.co.uk',
  US: '.com'
};

//Implement onClient request as the first event before caching occurs.
export function onClientRequest (request) {
 
  //Create a subdomain from the host of the incoming request. 
  const subDomain = request.host.split('.')[0];

  //Create a domain from the host of the incoming request.  
  const domain = request.host.split('.')[1];

  //Determine the top level domain based on the request's country of origin.
  let tld = tldMap[request.userLocation.country];

  //Set the default domain to .com.
  if (tld === undefined) {
    tld = '.com';
  }

  //Build up new domain based on the location of the request. For example, .ca for Canada.
  const redirectDomain = subDomain + '.' + domain + tld;

 
  //Check the incoming domain to see if the incoming domain is different from the built up domain.
  if (request.host !== redirectDomain) {

    //Redirect to new host. If a redirect is required, return the location header with the new domain in the response.
    request.respondWith(302, {
      Location: [request.scheme + '://' + redirectDomain + request.url]
    }, '');
  }
}
```
EdgeWorker IDにこれらのファイルをアップロードするためには、tarで1つのファイルにまとめ、それをgzip圧縮したファイル（拡張子tgz）にする必要があります。これは以下のコマンドにて実行します。（filename.tgzがアップロードするファイルになります）
```
tar -czvf filename.tgz main.js bundle.json
```

次に、ACCに戻り先ほど作成したEdgeWorker IDをクリックします。

Create versionボタンをクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2728604/4bf2a476-99e9-3fa2-b163-7ca740d519df.png)

ポップアップした画面にて、先ほど作成したfilename.tgzをDrag and dropします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2728604/a64b9dc7-d3c0-ade0-bd50-bcbdf38329dc.png)

Drag and dropが完了したら、Create versionボタンをクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2728604/912b6dc4-9e9a-a1b3-9930-d979639ec0c8.png)

### 3.2.3. EdgeWorkers コードのStagingデプロイ
コードの作成（EdgeWorker IDにコードを登録する作業）が終わったら、Akamai CDN上で実行する準備をします。

具体的にはAkamai Staging ネットワークへのデプロイを行います。この作業が終わった時の構成イメージは以下のとおりです。

EdgeWorker ID上のコードがあり、Akamai CDNのStaging ネットワークでactiveな状態です。ただ、Akamai CDN上でどの配信設定とも関連付いておらず、まだ利用されることはありません。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2728604/0362069b-eeb4-0bb2-dbc3-e6f19c58025f.png)


ここで、Akamai Production / Staging ネットワークについて補足しておきます。Akamai Productionネットワークは本番用プラットフォームです。Akamai CDNを利用した際、エンドユーザーが利用する環境です。Akamai Stagingネットワークは試験用プラットフォームです。エンドユーザーが利用することはありません。特殊な方法でStagingネットワークのEdge ServerのIPを調べ、検証用端末のhostsファイルに手動登録することでアクセスが可能になります。設定方法の詳細はこちらの[記事](https://community.akamai.com/customers/s/article/Stagingrxdxn?language=en_US)をご確認ください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2728604/6fcabd0d-3926-acaa-4b9a-1083dee14910.png)


手順の解説に戻ります。

ACCに戻り、作成中のEdgeWorker IDのコードを作成したVersion（上記手順を実施している場合は1.0.0）の右端Actionsリンクをクリックし、展開されるメニューよりActivate Versionをクリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2728604/d6450241-4ce7-36f2-af23-fedace87d4db.png)

ポップアップする画面から、Stagingを選択し、Activate versionボタンをクリックします。（ボタンクリック後5分前後でStagingデプロイが完了します）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2728604/bc1924f1-a798-d40f-82f0-70a2b6ad059a.png)

## 3.3. Akamai配信設定の実装
### 3.3.1. Akamai配信設定へのEdgeWorkers Behaviorの追加＆Staging デプロイ
Akamai Stagingネットワークに、コードのデプロイが完了し、EdgeWorkersコードの実行準備が整いました。あとはAkamai CDNの配信設定とこのEdgeWorker IDを紐付けることで利用可能な構成に変更していきます。この作業が終わった時の構成イメージは以下のとおりです。

EdgeWorker ID上のコードがあり、Akamai CDNのStaging ネットワークでactiveな状態です。またAkamai CDN上の配信設定と関連付いており、利用可能な構成になっています（Akamai Stagingネットワーク限定）。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2728604/00812a22-045d-93ff-dedf-bb516301e65e.png)


手順は以下のとおりです。

EdgeWorkersのコードを実行させたいhost名を持つ配信設定を開き、新規versionを作成します。

その上で以下のようなルールを作成します。作成後、この配信設定もAkamai Stagingネットワークに展開します。

（補足）

- ルール名: 任意の名前をつけます（以下例ではlocationBasedRedirectという名前にしています）
- Criteria: EdgeWorkersのコードを実行させたい条件を設定します（以下例では、pathが/locationBasedRedirectだったら、という条件としています）
- Behaviors: EdgeWorkersビヘイビアを追加/有効化します。また作成したEdgeWorker IDと紐付けます
- ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2728604/5b6ecddd-41d8-5040-73f0-b3cd0cb8b59b.png)

## 3.4. 動作検証
EdgeWorkersのコードを実行し動作検証する準備が整いました。早速動作検証をしてみます。

以下のcurlコマンドを利用し、Akamai Stagingネットワークにて動作確認をしてみます。(Akamai Stagingネットワークについては、3.2.3.章参照）
```
curl https://[subdomain].[yourdomain].work --connect-to ::[subdomain].[yourdomain].work.edgekey-staging.net -H "Pragma: akamai-x-ew-debug" -sD -  -sD -
```
curlコマンドより、以下の結果が出力されます。
```
HTTP/1.1 302 Moved Temporarily
Location: https://[subdomain].[yourdomain].com/locationBasedRedirect
Content-Type: text/html
Content-Length: 0
Date: [Date]
Connection: keep-alive
X-Akamai-EdgeWorker-onClientResponse-Info: ew=[EdgeWorker ID] v:[EdgeWokrer ID name]; status=UnimplementedEventHandler
X-Akamai-EdgeWorker-onClientRequest-Info: ew=[EdgeWorker ID] v1.0.0:[EdgeWokrer ID name]; status=Success
X-Akamai-Staging: ESSL
```

上記の結果より以下のことがわかります。

- Locationヘッダ: リダイレクト先のURLを確認可能です。（curlコマンドでアクセスしたFQDNに対し、トップレベルドメインが.comに変換されていることが確認できます）
- X-Akamai-EdgeWorker-onClientRequest-Infoヘッダ: 実行されたEdgeWorker ID/version/name、そして実行statusが確認できます。
- X-Akamai-Stagingヘッダ: Akamai Stagingネットワークを利用している場合に表示されるヘッダです。Akamai Stagingネットワークに接続できていることが確認可能です。




今回実現したい処理は「アクセス元の国に基づくリダイレクト」です。

アクセス元の国が変わると、リダイレクト処理（リダイレクト先URL）は本当に変わるのでしょうか。




ACCには、様々な国からcurlコマンドを実行するためのtoolが用意されています。このツールを利用し、今回実現したい処理を検証してみます。

ACCにアクセスする前に、以下のdigコマンドにて、Akamai Stagingネットワーク上のEdge ServerのIPを調べておきます。(Akamai Stagingネットワークについては、3.2.3.章参照）

```
dig [subdomain].[yourdomain].work.edgekey-staging.net +short
```
次にACCにアクセスします。アクセスしたら左上の☰をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2728604/e973abbf-76a6-faab-1368-7a837b4fd9d6.png)

次にSupport> Edgediagnosticsリンクをクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2728604/27ec99df-039e-4f87-6a1c-6893d9690d82.png)

toolリンクをクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2728604/30032beb-3312-2bc6-99bf-c322011dc50b.png)

Request Content(CURL)リンクをクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2728604/11b4252f-2078-b73a-8a1e-7581f070982d.png)

URLにEdgeWorkersコードを実行するためのURLを入力します（例：https://[subdomain].[yourdomain].work/locationBasedRedirect）

Sourceには任意の場所を選択します。カナダユーザーにはカナダドメインへリダイレクトされることを確認するため、Torontoを選択します。

Spoof to edge server IPには、digコマンドで事前に調べたAkamai StagingネットワークのEdge Server IPを入力します。

それ以外はdefaultのままで問題ありません。Submitボタンをクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2728604/241ccb7e-c891-9e1f-862d-12fce391488a.png)

Submitボタンを押すと、Curl結果が表示されます。

Locationヘッダに含まれるリダイレクト先URLのFQDNを確認すると、トップレベルドメインが.caになっていることがわかります。

アクセス元の国に基づきリダイレクト先が変わったことを確認できました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2728604/85665f06-6dea-0660-f305-23782aae5cdc.png)

## 3.5. 本番リリース
通常の開発作業においては、動作検証（機能テストやリグレッションテスト）が問題なく完了したらAkamai Productionネットワークにデプロイします。
まず、EdgeWorker ID(今回作成したversion）をAkamai Productionネットワークにデプロイします（このタイミングでは本番サービスにアクセス元の国に基づく処理は適用されません）。
次に、Akamai配信設定をAkamai Productionネットワークにデプロイします。このタイミングでアクセス元の国に基づく処理が実サービスに適用されます。エンドユーザーも利用可能な構成になります。

# 4. さいごに
このように、Akamai EdgeWorkersを利用することで、アクセス元の国に基づく処理を簡単に実装することが可能です。今回実施した処理はリダイレクトでしたが、リダイレクト以外にも異なる処理を行うことは可能です。

また、Akamaiを利用しアクセス元の国に基づく処理を実現することで以下のメリットを得ることができます。

- ユーザーの近い場所でアクセス元の国を判別し処理を実行できる（レイテンシー/処理速度の向上）
- Originシステムの負荷/コスト削減（Originシステムでアクセス元の国に基づく処理を実現した場合と比べて）
- IPアドレスとgeoの紐付けのデータはAkamaiが管理・維持しているため、アクセス元の国の識別のためのデータ管理・運用面の考慮が不要
- Akamai CDN同様、インフラ運用の考慮が不要（EdgeWorkersで動かすコードとAkamai配信設定の管理のみで良い）