カスタムエラーページを試してみた

## Custom Error Page 試してみた

今回は Build 2023で発表された新機能のうち、App Service の Custom Error Page(preview) を実際に試してみました。

Preview 版ということもあり、罠にはまる部分も楽しんでいただければ幸いです。

「実際に手元の環境でテストする際の注意点だけ知りたい！」という場合は、最後のまとめ部分をご参照ください。

## 目次
[チュートリアルに沿って403エラーを再現してみる](#チュートリアルに沿って403エラーを再現してみる)
[カスタムエラーページの前提条件](#カスタムエラーページの前提条件)
[ファイルをアップロード](#ファイルをアップロード)
[画像をいれて作ってみた](#画像をいれて作ってみた)
[まとめ](#まとめ)

___
## チュートリアルに沿って403エラーを再現してみる
まずは、[403エラー時のカスタムエラーページについてのチュートリアル](https://github.com/Azure/app-service-linux-docs/blob/master/HowTo/configure_custom_error_page.md)を見ながら、実際に403 エラーを再現します。こちらは Azure Portal からアクセス制限を行うことで簡単に設定することができます。

https://github.com/Azure/app-service-linux-docs/blob/master/HowTo/configure_custom_error_page.md


- まず【ネットワーク】の "受信トラフィックの構成" からアクセス制限に移ります

<img width="600" alt="network settings" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3642174/f9e673cc-7483-c3d9-b315-6c63d5913575.png">
<br>

- 【アクセス制限】の "一致しないルールのアクション" を拒否に設定し、追加をクリック

<img width="600" alt="access deny" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3642174/7391f759-cb9d-7cd6-bd1d-72f4d9204dab.png">

- 右側に "規則の追加" ウィンドウが出てくるので、アクションを拒否、優先度とIPアドレスブロックを設定し、"規則の追加" をクリックします。

:::note info
<details><summary>IP アドレスブロックの設定方法</summary><div>
"/0" を設定すると全ての公開アクセスを選択しているのと同義となり、それを拒否することで、インターネットからのすべてのアクセスがブロックされます。<br>
* テストのためだけであれば、"任意のIPアドレス/0" にしても構いません。
</div></details>
:::

<img width="200" alt="add rule" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3642174/c9326309-f7c3-e147-6f9b-e20c72e8b906.png">
<br>
<br>
これでアクセス制限が設定され、すべてのインターネットアクセスが拒否されました。

概要ブレードにもどり、アプリのURL(既定のドメイン)をクリックすると、規定の 403 エラーが表示されます。

<img width="600" alt="default 403error" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3642174/b399ac36-1955-0dbd-0ba4-a6e6c5623adf.png">

これで 403 エラーページを確認するための設定は完了しました。

今回はチュートリアルに沿って、アクセス制限を構成しましたが、

:::note info

**【アクセス制限】の "パブリックアクセスを許可する" のチェックボックスを外すだけでも 403 エラーは出すことができます。**
:::


## カスタムエラーページの前提条件
エラーを再現することができたので、今度はこれをカスタムエラーページに差し替えます。
カスタムエラーページを使用するためには Premium 以上の App Service プランを使用する必要があります。

今回は "premium V3" の中で一番お手頃な "premium V3 P0V3" 使用します。

<img width="600" alt="premium V3 P0V3" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3642174/0b297b24-31b2-a730-532c-47b785d242be.png">

アプリもしくは App Service プランの【スケールアップ】から プランを選択し、
さぁ、これであとはファイルをアップロード・・・

と思ったところで、

<font color="red">「この SKU はカスタムエラーページをサポートしていません」</font>

というメッセージが出ていることに気づきました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3642174/557d9bb9-d950-fd37-3199-073d3aea3a6c.png)

試しにこのままファイルをアップロードしてみましたが、設定を保存するところで、案の定エラーが返ってきてしまい、この機能を使うことはできませんでした。

どうやらエラーメッセージから察するに、SKUによって 2023年12月現在 "premium V3 P0V3" ではカスタムエラーページをサポートしているかが変わってくるようです。

そのため、試しに、"Premium V2" を選択してみました。

こちらを選択したところ、特に問題なく設定することができました。

## ファイルをアップロード

App Service のカスタムエラーページは、【構成】ブレードからHTML ファイルをアップロードするだけで簡単に使用することができます。

HTML ファイルは自分で作る必要があるため、テスト用に簡単なHTMLファイルを作成し、ローカルで確認します。

<img width="600" alt="multi byte html" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3642174/4207d400-36d5-439d-c7e1-f2476c7cfd0d.png">

ローカル上では問題なく表示させることができました。

アップロードするファイルの準備ができたので、【構成】から "エラーページ（プレビュー）" をクリック

<img width="600" alt="error preview " src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3642174/978ddff2-5519-e355-406b-613cb2b1fd19.png">

<br>

作成したHTMLファイルを指定してアップロードしようとすると・・・

**なんと "アップロード" ボタンがアクティブになりません！**<br>
<img width="600" alt="non active " src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3642174/7e4b347e-3996-5f1e-6b9e-88726b1596a1.png">


色々試してみたところ、現在、カスタムエラーページは日本語などの全角 （マルチバイト） 文字には対応していないようでした

特にエラーメッセージは出てこず、ただアップロードボタンがアクティブにならないだけなので、注意が必要です。そのため、コメントなどに日本語が入っている場合は削除しましょう。

::: note warn

**マルチバイト文字については 2023年12月現在対応していないようです。**

:::

日本語のページを表示させるためには画像ファイルを使う必要がありそうなので、ひとまず英語のみのHTMLファイルを作成します。


<details><summary>サンプルコード</summary><div>

```html

<!DOCTYPE html>
<html>
<head>
    <title>403 Forbidden</title>
    <style>
        body {
            font-family: 'Arial', sans-serif;
            background-color: #f4f4f4;
            text-align: center;
            padding: 50px;
            display: flex; 
            justify-content: center; 
            align-items: center; 
            height: 100vh; 
            margin-top: -50px; 
        }
        h1 {
            color: #ff6347;
            font-size: 60px;
        }
        p {
            color: #333;
            font-size: 24px; 
        }
        .container {
            background-color: white;
            padding: 20px;
            border-radius: 8px;
            display: inline-block;
            box-shadow: 0 0 10px rgba(0,0,0,0.1);
        }
    </style>
</head>
<body>
    <div class="container">
        <h1>403 Forbidden</h1>
        <p>Sorry... your access is restricted.</p>

        <p>Advent Calendar 2023</p>
    </div>
</body>
</html>

```
</div></details>

上記の HTML ファイルを 403 エラーページとしてアップロードして設定を保存します。

その後、【概要】ブレードに戻り、App の URL をクリックすると・・・


<img width="600" alt="403error success " src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3642174/51a643d8-032a-e460-0d88-f232be53d9fd.png">

無事、表示することができました。

## 画像をいれて作ってみた

ここまでで、カスタムエラーページを作ることには成功しましたが、せっかくなので画像をいれたページも試してみようと思います。

Base64 エンコードを使って、HTML ファイル内に画像を格納する方法も考えましたが、**「カスタムエラーページとしてアップロードできるファイルは 10KB まで」** という制限があるため、こちらは使えません。

そこで今回は、blob コンテナーの中に画像を入れて、その URL を参照する方法で表示させてみることにしました。

### blob コンテナーに画像を格納する

まずは、ストレージアカウントを作成します。

この時、**「すべてのネットワークからのパブリックアクセスを有効にする」** を選択してください。

すでに作成済みのストレージアカウントを使用する場合は、【ネットワーク】ブレードから変更することができます。

<img width="600" alt="create storage account" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3642174/96b29d69-7c8f-c68f-3829-3f369b5b4794.png">

ストレージアカウントを作成したら【コンテナー】ブレードから画像を入れる BLOBコンテナーを新たに追加します。

<img width="600" alt="create container" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3642174/3270225d-27ab-359b-99d8-484419f5bdab.png">

作成したコンテナを作成し、アップロードボタンを押して 使いたい画像をアップロードします。コンテナーに新しいファイルが入ったことを確認したら、ファイル名をクリック。各種情報が表示されるので、URLが作成されているのでコピーします。

<img width="600" alt="upload to container" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3642174/a1d7eb5a-0326-3127-bc7a-13f002d4e1af.png">

これが画像の URL なので、この URL をHTMLファイルに埋め込みます


::: note info
<details><summary>サンプルコード</summary><div>

```html

<!DOCTYPE html>
<html>
<head>
    <title>403 Forbidden</title>
    <style>
        body {
            font-family: 'Arial', sans-serif;
            background-color: #78a5ee;
            text-align: center;
            padding: 50px;
        }
        h1 {
            color: #ff6347;
            font-size: 50px;
        }
        p {
            color: #333;
            font-size: 20px;
        }
        .container {
            background-color: white;
            padding: 20px;
            border-radius: 8px;
            display: inline-block;
            box-shadow: 0 0 10px rgba(0,0,0,0.1);
        }
    </style>
</head>
<body>
    <div class="container">
        <h1>
            403error<br>
        Custom Error Page
        </h1>
        <h2>Forbidden</h2>
    <img src="画像ファイルのURL" alt="403error">

</body>
</html>

```

</div></details>
:::

サンプルコードを使用する場合は、URL を使いたい画像の URL に変更してください。

作成した HTMLファイルをカスタムエラーページとしてアップロードします。

設定を保存し、アプリのURLを表示させると・・・
<br>
<br>


<br>


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3642174/5f0f1a18-358e-243e-667d-2ce3d55e36bd.png)
<br>
表示させることができました！
<br><br>

### コンテナーの使用時の注意点
コンテナーに画像をアップロードして、そのURLをHTML から参照する場合、ストレージアカウントのパブリックアクセスを許可し、BLOB 専用の匿名読み取りアクセスを設定したコンテナーを使用します。この場合、読み取りについては不特定多数に許可する設定となるため、セキュリティに注意が必要です。

実際に使用される場合は、ロールの適切な設定、機密データとの隔離、読み取り専用ロックなど、セキュリティに十分配慮した上で行ってください。

https://learn.microsoft.com/ja-jp/azure/azure-resource-manager/management/lock-resources?tabs=json

## まとめ
### App Service のカスタムエラーページ使用条件
- Premium 以上のプランを選択する
- シングルバイト（半角）で作成した HTML ファイルをアップロードする

### 403エラーページのテスト方法
 - アプリのアクセス制限でパブリックアクセスを制限する
 - ブラウザ上からアクセスする


<br><br>

初投稿を読んでいただき、ありがとうございました。
<br>
**良いお年を！**