[小ネタ] Azure Static Web Apps のフリープランでリダイレクトだけするサイトを用意する

とある案件で Azure Static Web Apps (Freeプラン / 連携リポジトリ無し) で他のサイトへ転送するだけのページを作成したので備忘録として作成方法をメモしておきます。

## デプロイまでおおまかな流れ

- HTTPリダイレクトだけを行うサイトプロジェクトを作成
- Azure Static Web Apps の箱を作成し、デプロイトークンを入手
  - **同サービスの構築手順によくあるGitHubリポジトリやCI/CDフローは不要です**
- サイトプロジェクトをデプロイトークンを使って Azure Static Web Apps にデプロイ

## Azure Static Web Apps 用のサイトプロジェクトを作成する

### ファイルセットアップ

Node.js プロジェクトとしてサイトプロジェクトをセットアップします。[^1]

[^1]: ここではプロジェクトローカルに `@azure/static-web-apps-cli` をバージョン固定で入れるために `package.json` を作成していますが（実際にはいくつかデプロイ用のスクリプトもnpm scriptsに記述したほうが便利でしょう）、 `package.json` 抜きでグローバルに `npx @azure/static-web-apps-cli` をインストール＆実行しても問題ありません。

```sh
# プロジェクトの初期化 (適当な package.json を生やせるならどれでもいいです)
$ npm init

# 記事執筆時点では @2.0.2 で確認済 (Node.js: 22.9.0)
$ npm install -D @azure/static-web-apps-cli
```

`@azure/static-web-apps-cli` 用にデプロイ設定のJSONを以下のように定義してあげます。

```json:swa-cli.config.json
{
  "$schema": "https://aka.ms/azure/static-web-apps-cli/schema",
  "configurations": {
    "myredirectsite": {
      "appLocation": "src",
      "outputLocation": "src"
    }
  }
}
```

上記ファイルを置く代わりに、 `npx @azure/static-web-apps-cli init` コマンドでも同じようなファイルを作成できます。特にビルドなどはしないので `appLocation` も `outputLocation` も `"src"` を指定しています。

最後に `src/` ディレクトリに以下の2つのファイルを置きます。[後者のJSONファイル](https://learn.microsoft.com/ja-jp/azure/static-web-apps/configuration)にはきちんとしたリダイレクト先を書いてください。

```html:src/index.html
<!-- どうせ表示されないので中身は何でもいいが無いと文句を言われるので作成 -->
```

```json:src/staticwebapp.config.json
{
  "routes": [
    {
      "route": "/*",
      "redirect": "https://example.com/this-site-has-moved/",
      "statusCode": 301
    }
  ]
}
```

### ローカルでの実行確認

作成したサイトの動作試験をローカル環境にて行います。

```sh
$ npx @azure/static-web-apps-cli start
...

Azure Static Web Apps emulator started at http://localhost:4280. Press CTRL+C to exit.
```

実際にリダイレクトされるか確認してみましょう。

```sh
$ curl -v http://localhost:4280
...
* Request completely sent off
< HTTP/1.1 301 Moved Permanently
< Location: https://example.com/this-site-has-moved/
< Date: Wed, 15 Jan 2025 05:25:11 GMT
< Connection: keep-alive
< Keep-Alive: timeout=5
< Content-Length: 0
```

あとはこれをAzure Static Web Apps にデプロイするだけです。


## Azure Static Web Apps (Freeプラン) でデプロイ先を用意する

Azure Portal (`Static Web Apps`) 上から手動で用意してもいいですが、Terraformの定義を載せておきます。

```terraform:azure_static_site.tf
resource "azurerm_static_web_app" "main" {
  name = "myredirectsite"

  resource_group_name = "リソースグループ名"
  location            = "eastasia"

  sku_tier = "Free"
  sku_size = "Free"
}
```

上記で作成したリソースを作成したら、リソースの `api_key` 属性もしくは、Azure Portal上から該当リソースの `Manage deploy token` から**デプロイ用のトークンをコピーしておきましょう。**

### Azure Static Web Apps にカスタムドメインを設定する

通常は作成したサイトにカスタムドメインが必要と思われるので、その設定例のTerraform定義も載せておきます。DNSゾーンもAzureで管理している前提です。

```terraform:azure_static_site_custom_domain.tf
resource "azurerm_static_web_app_custom_domain" "main" {
  static_site_id  = azurerm_static_site.main.id
  domain_name     = "mycustomdomain.example.org"
  validation_type = "dns-txt-token" # TXTトークンの場合はApexドメインでも認証可能
}

resource "azurerm_dns_txt_record" "main" {
    resource_group_name = "リソースグループ名"

    zone_name = "example.org"
    name      = "mycustomdomain"
    ttl       = 300

    record {
        value = azurerm_static_site_custom_domain.main[each.key].validation_token
    }
}

resource "azurerm_dns_a_record" "main" {
    resource_group_name = "リソースグループ名"

    zone_name = "example.org"
    name      = "mycustomdomain"
    ttl       = 300

    target_resource_id = azurerm_static_site.main.id
}
```

ちなみに、**Freeプランの場合は1つしかカスタムドメインが設定できない** ので注意しましょう。

## Azure Static Web Apps にデプロイする

先ほどのNode.jsプロジェクトに戻って、Azure Static Web Apps にデプロイを行います。

```sh
$ export SWA_CLI_DEPLOYMENT_TOKEN=前の手順でコピーしたデプロイトークン
$ export SWA_CLI_DEPLOY_ENV=production

# デプロイ実行！
$ npx @azure/static-web-apps-cli deploy
...
Deploying to environment: production
...
Deploying project to Azure Static Web Apps...
✔ Project deployed to https://whatever-goes-here-xxxxx.x.azurestaticapps.net 🚀
```
以下がポイントです。

- デプロイトークン(`SWA_CLI_DEPLOYMENT_TOKEN`)だけでデプロイ先のアプリは勝手に特定されます
- デプロイ環境名(`SWA_CLI_DEPLOY_ENV`)を指定しないと、サイトのプレビュー環境にデプロイされてしまうので、必ず指定しましょう

デプロイ結果をチェックしてみましょう。

```sh
$ curl https://mycustomdomain.example.org
...
* Request completely sent off
< HTTP/2 301 
< date: Wed, 15 Jan 2025 08:03:23 GMT
< location: https://example.com/this-site-has-moved/
< content-length: 0
<
```

問題なさそうです！

## まとめ

カスタムドメイン付きの Azure Static Web Apps（Freeプラン）でリダイレクトのみを行うサイトをGitHubなど無しでデプロイする方法を見てきました。サイトが閉鎖した際などに安価なサイトクローズ通知方法として使えるかもしれませんし、リダイレクト抜きでも通常のSPAなどデプロイする際にも使えるでしょう。