ブログサイトをAWSで公開する

- ブログサイトの公開方法は、`GitHub Pages` やその他無料サービスなどあるようですが、
ここではAWSを使ってブログサイトを公開する方法を紹介します。  
- AWSを使う理由は、自由度の高さと運用費用の安さです。  
- AWS利用開始１年未満であれば無料枠で運用できますし、１年経過後でも月額10円未満程度で運用できます。

## この記事の目的

- ブログサイトをAWS のS3とCloudFrontを利用して公開します。
- 公開中のサイトが以下です。  
<https://docusaurus.plant11.com>

## 👇これより先は下記記事の内容を前提とします

- [Docusaurus でブログサイトを作成する](https://docusaurus.plant11.com/docusaurus/docusaurus)

## 導入手順

- 本家AWSの説明サイトがあります。  
[CloudFront を使用して、Amazon S3 でホストされた静的ウェブサイトを公開するにはどうすればよいですか?](https://aws.amazon.com/jp/premiumsupport/knowledge-center/cloudfront-serve-static-website/)
<https://docs.aws.amazon.com/ja_jp/AmazonCloudFront/latest/DeveloperGuide/getting-started-secure-static-website-cloudformation-template.html#deploy-secure-static-website-cloudformation>
- 他にも説明サイトがいろいろあります。
<https://dev.classmethod.jp/articles/sap-exam-study-1-2/>
<https://dev.classmethod.jp/articles/distributing-s3-content-with-cloudfront/>
<https://qiita.com/NaokiIshimura/items/46994e67b712831c3016>

## デプロイの効率化

サイトをビルドし、S3へアップロードする処理をpythonで作成しました。

`deploy.py`

```python:deploy.py
import os
import subprocess
import boto3
import pathlib

def clear_before():
    s3 = boto3.client('s3')
    bucket_name = "your.bucket.name"
    response = s3.list_objects_v2(Bucket=bucket_name, Prefix="docusaurus/")
    if 'Contents' in response:
      contents = response['Contents']
      for content in contents:
        print("delete:" + content['Key'])
        s3.delete_object(Bucket=bucket_name,Key=content['Key'])

def upload(prefix,file):
    print("filename:" + file.name)
    #print(file.name.split(".")[-1])
    ext = file.name.split(".")[-1]
    content_type="text/html"
    if ext == "txt":
      content_type="text/plain"
    elif ext == "ico":
      content_type="image/x-icon"
    elif ext == "svg":
      content_type="image/svg+xml"
    elif ext == "js":
      content_type="application/javascript"
    elif ext == "css":
      content_type="text/css"
    print("content_type:" + content_type)
    s3 = boto3.client('s3')
    
    key_value = file.name
    if(len(prefix)):
      key_value = prefix + "/" + file.name
    
    with open(file, 'rb') as f:
        res = s3.put_object(
            Body=f,
            Bucket="your.bucket.name",
            Key=key_value,
            ContentType=content_type,
        )

if __name__ == '__main__':
    cmd = ["npm", "run", "build"]
    subprocess.run(cmd,cwd=".",shell=True)

    clear_before()

    files = pathlib.Path("build").glob("**/*")
    for file in files:
      if pathlib.Path.is_file(file):
        dir_prefix = "docusaurus/" + str(file.parent).replace("\\","/")[len("build/"):]
        if dir_prefix.endswith('/'):
          dir_prefix = dir_prefix[:-1]
        upload(dir_prefix,file)

```

## `index.html`参照エラーの回避

CloudFrontでDocusaurusのサイトを公開すると、`index.html`が参照できないことにより、画面遷移の際に画面表示エラーが発生します。  
![image](https://user-images.githubusercontent.com/38905609/179429157-773789e5-98fc-4043-b7d2-5d6947eb64ff.png)

AWSからもこの問題に対する解決方法が公開されています。  
[index.html を追加してファイル名を含まない URL をリクエストする](https://docs.aws.amazon.com/ja_jp/AmazonCloudFront/latest/DeveloperGuide/example-function-add-index.html)  

具体的手順を以下に記載します。  

### Lambdaの作成

CloudFrontへ適用するLambda関数はバージニア北部リージョンで作成する必要があります。  
`lambda_function.py`

```python:lambda_function.py
import json

def lambda_handler(event, context):
    request = event['Records'][0]['cf']['request']
    print(request['uri'])
    
    if request['uri'].endswith("/"):
        request['uri'] += "index.html"
        print(request['uri'])
    elif not '.' in request['uri']:
        request['uri'] += "/index.html"
        print(request['uri'])
        
    return request
```

### CloudFrontへの適用

Lambda関数のコンソールから、Lambda@Edge へのデプロイを指定します。
![image](https://user-images.githubusercontent.com/38905609/179429407-e8d3be57-1fa8-4068-ba8a-449df4bcea3e.png)

Lambda@Edge へのデプロイ。
![image](https://user-images.githubusercontent.com/38905609/179429560-bd0848b7-db60-4c45-bf13-2bac7cfbc12e.png)

## 👇前提記事

- [Docusaurus でブログサイトを作成する](https://docusaurus.plant11.com/docusaurus/docusaurus)

## 👇関連記事

## 👇参考URL

- [CloudFront を使用して、Amazon S3 でホストされた静的ウェブサイトを公開するにはどうすればよいですか?](https://aws.amazon.com/jp/premiumsupport/knowledge-center/cloudfront-serve-static-website/)
- <https://docs.aws.amazon.com/ja_jp/AmazonCloudFront/latest/DeveloperGuide/getting-started-secure-static-website-cloudformation-template.html#deploy-secure-static-website-cloudformation>
- <https://dev.classmethod.jp/articles/sap-exam-study-1-2/>
- <https://dev.classmethod.jp/articles/distributing-s3-content-with-cloudfront/>
- <https://qiita.com/NaokiIshimura/items/46994e67b712831c3016>
- [index.html を追加してファイル名を含まない URL をリクエストする](https://docs.aws.amazon.com/ja_jp/AmazonCloudFront/latest/DeveloperGuide/example-function-add-index.html)