AWSでWebApp公開する (FastAPI in EC2)

# やりたいこと

* AWS の何らか (今回は EC2) を使って、外部に公開できる (されている) サーバを用意する
* 用意したサーバで、WebApp (今回は FastAPI) を公開する
* (WebApp に限らず、httpd (Apache) で Web ページ公開できる)
* AWS の無料枠内で完結させる

データベースに特化したサービスや、Web サーバに特化したサービスなどもあり、それらを活用する方法もありますが、今回は EC2 単品で完結させ、「とりあえず動くようにしてみる」ことを目標にします。

AWS のアカウントは準備できているという前提で話を進めます。

**2022/05/14追記：**
アップデートされ、インスタンス作成の UI が変わったようです。
記事の画像は旧 UI です。

# 軽く EC2 や AWS の話

EC2 というのは、AWS において仮想サーバを利用できるサービスです。EC2 の仮想サーバのことはインスタンスと呼ばれます。

自宅での自家サーバに比べ、AWS などのレンタルサーバ (仮想サーバ) の良い所は、Amazon社で適切に管理されている物理マシンを利用でき、自宅でハードウェアを管理する必要が無い所、様々なネットワーク設定などを、ハードウェアを自分でいじることなく制御できる所ですね。

# EC2 インスタンスの作成

## リージョン設定

AWS コンソールの「サービス」から、「コンピューティング -> EC2」押下で EC2 のダッシュボードを開きます。

![img00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540894/8c7b8b91-168e-be53-8e3e-eb1e9166e82f.png)

![img01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540894/80baa641-beea-704d-2c1e-f7fe705b47e3.png)

画面右上から、リージョン (サーバの所在位置) を設定します。

日本に住んでいて、かつ特別な事情が無ければ、「アジアパシフィック (東京 or 大阪)」を選ぶと良いです。一般に、距離的に近い方がアクセス速度が早いです。

![img02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540894/4b720b66-5d79-ecd5-fd31-682a6d5e5502.png)

## セキュリティグループ設定

画面左のメニューから「セキュリティグループ」を選択します。セキュリティグループは、EC2 のファイアウォール的なものです。

![img03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540894/9658ed6d-4cce-ffac-83a0-9944d7427912.png)

デフォルトのグループが 1つあります。
これを利用することもできますが、ここでは新しく 1つグループを作成します。画面右上の「セキュリティグループを作成」を押下します。

適当なグループ名、説明を設定します。VPC はデフォルトで問題ありません。

![img04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540894/be8a0203-e057-dc44-875d-670a1c513a78.png)

インバウンドルール (外からサーバに対する通信) は、サーバの操作のため SSH (22) に加え、用途によって必要なポートを開けます。今回は WebApp へのアクセスのため「カスタムTCP」で、FastAPI デフォルトの 8000 ポートを開けます。

![img05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540894/3baa1bee-d349-9fae-f113-4102f32aac31.png)

Apache などでのアクセスをする場合は、8000 の代わりに HTTP (80) を開けます。

ソースに 0.0.0.0/0 (Anywhere-IPv4) を設定すると、誰からでもアクセス可能になります。より安全をとるのであれば、自身のグローバル IP を調べ、その IP からのアクセスのみを設定しましょう。

![img06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540894/870d57dd-3c5b-03c9-c406-82cb913e3427.png)

アウトバウンドルール (サーバ内から外に対する通信) は、特に事情が無ければ「すべてのトラフィック」で問題無いです。これにより、APT や YUM、PIP コマンドなどでのダウンロードが行えます。

![img07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540894/cc3425c8-738e-7929-2915-401ad039eed2.png)

## インスタンス作成

インスタンスのダッシュボードから「インスタンスを起動」を押下します。

無料枠で利用できる AMI (OS) は、Amazon Linux の他に Ubuntu や Windows Server などがあります。特に事情やこだわりが無ければ Amazon Linux で問題無いでしょう。

![img08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540894/3775ccd3-f7ce-0caa-ee8b-ff7e01c761bc.png)

インスタンスタイプでは、サーバのスペックを決められます。無料枠で使えるのはデフォルトで選ばれているものだけなので、今回はそのままにします。

![img09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540894/635acb98-e9cd-6ed0-695f-2ab76c668fba.png)

インスタンスの詳細設定はデフォルトのままにします。

ストレージの追加では、無料使用枠では汎用 SSD を 30GB まで利用できます。無料使用枠ではマグネティックストレージも利用できますが、SSD の方が良いでしょう。

終了しなければ消されませんが、一応「終了時に削除」のチェックは外しておきます。

![img10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540894/cb4a7c6c-96de-45c2-12ec-84453429b6d5.png)

タグの追加の設定は何もせずに次に進みます。

セキュリティグループは、「既存のセキュリティグループを選択する」を選び、さきほど作成したセキュリティグループを選択します。

![img11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540894/7578ec0c-4fbc-76eb-3fa4-dd206eec7e4f.png)

最後に、確認画面が出てきますので、確認して「起動」を押下します。

その次に、キーペアの設定が出てきます。キーペアというのは、簡単に言えばインスタンスの操作 (SSH 接続) でアクセスするにあたって必要なキー (ファイル) です。「新しいキーペアの作成」で、適当なキーペア名を設定します。

![img12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540894/3afd5a7e-e1c6-d7c2-b2aa-d21dd275cc0e.png)

(この後の方法によっては不要にはなりますが、)**「キーペアのダウンロード」から `xxx.pem` ファイルのダウンロードを忘れずに行い、また、このファイルが漏洩しないように保管してください。**

以上でインスタンス作成完了です。少しの間待つと、インスタンス状態が実行中に変わります。

![img13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540894/d2b491f4-bab3-770e-973b-e8a9903cafee.png)

# インスタンスの操作 (SSH 接続)

レンタルサーバの操作をするには、遠隔操作を用いる他ありません。EC2 Instance Connect または OpenSSH を用いて、インスタンスに SSH 接続します。

## EC2 Instance Connect (ブラウザ) で接続

ブラウザ上でターミナル操作ができる方法です。追加でアプリなどを用意する必要が無いため、最も手軽に利用できます。

さきほど作成したインスタンス (操作したいインスタンス) を選択した状態で、画面右上の「接続」を押下します。すると、4つの接続方法を確認できる画面に移ります。

![img15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540894/75c262c1-e8e0-a4c0-e5df-71c8f965006e.png)

「EC2 Instance Connect」タブが選ばれた状態にし、右下の「接続」を押下します。何か別の設定をしていなければ、ユーザはデフォルトの「`ec2-user`」のままで問題ありません。すると、新しいブラウザタブが開き、そこからインスタンスをターミナル操作できます。

**2022/05/14追記：**
選択した AMI (OS) によっては、デフォルトのユーザ名が `admin` になることもあるみたいです。

![img16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540894/7a08d330-cc59-48e6-eb99-eb2abbb90404.png)

## OpenSSH で接続

OpenSSH は、Linux や Windows10 においてプリインストールされている SSH クライアントです。すなわち、自前環境の SSH クライアントや端末からアクセスする方法になります。

![img17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540894/5a0a7cdd-48d8-db68-a1aa-ada174ee3fac.png)

さきほど取得したキーファイル (`xxx.pem`) のアクセス権限を変更します。これを行わないと、公開範囲の広いアンセキュアなキーと判定され、利用できなくなってしまいます。

```sh
chmod 400 xxx.pem
```

キーの準備ができたら、説明にある通りのコマンドを実行して接続できます。

```sh
# デフォルトのユーザ名によって ec2-user は変更する
ssh -i "xxx.pem" ec2-user@ec2-000-000-000-000.ap-northeast-1.compute.amazonaws.com
```

ローカルファイルをインスタンスへコピーするには、SCP コマンドを利用します。

```sh
# デフォルトのユーザ名によって ec2-user は変更する
scp -i "xxx.pem" ./any-file ec2-user@ec2-000-000-000-000.ap-northeast-1.compute.amazonaws.com
```

# 何か作ってアクセスしてみる

## FastAPI

> セキュリティグループで 8000 ポートを解放し、FastAPI でデフォルトの 8000 ポートを使う前提です。

初めに、FastAPI の動作に必要な最低限のパッケージを入れます。

```sh
pip3 install fastapi uvicorn
```

適当に JSON を応答するルートを作成し、実行します。

```fapi.py
from fastapi import FastAPI
import uvicorn

app = FastAPI()

@app.get("/")
def index():
  return {"hello": "from AWS"}

if __name__ == "__main__":
  uvicorn.run("fapi:app", host="0.0.0.0", port=8000, reload=True)
```

```sh
python3 fapi.py
```

適当なブラウザからアクセスしてみます。インスタンスの詳細表示から、「パブリック IPv4 DNS」または「パブリック IPv4 アドレス」を確認し、このアドレスのいずれかをブラウザの URL 欄に入力します。

![img13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540894/d2b491f4-bab3-770e-973b-e8a9903cafee.png)

ここで、ポートを 8000 と指定するのをお忘れなく。

```txt
http://ec2-000-000-000-000.ap-northeast-1.compute.amazonaws.com:8000/
または
http://000.000.000.000:8000
```

正しくできていれば、ブラウザに JSON データが表示されます。

![img18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540894/dddad09c-b625-6f2e-ca89-67bb7386d770.png)

## httpd (Apache)

> セキュリティグループで 80 ポートを解放している前提です。

httpd をインストールします。

```sh
sudo yum install httpd
```

`systemctl` コマンドから起動します。一応、自動起動しないようにしておきます。

```sh
sudo systemctl start httpd
sudo systemctl disable httpd
```

FastAPI と同様の URL に、ブラウザからアクセスします。今度はポート指定をせずにアクセスします。

```txt
http://ec2-000-000-000-000.ap-northeast-1.compute.amazonaws.com/
または
http://000.000.000.000
```

正しくできていれば、httpd のデフォルトページが表示されます。

![img19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540894/ec7c5aa7-3ddc-8e5f-6001-a5d1f934a42d.png)

せっかくなので、適当な自作ページに変えて確認してみます。

```sh
sudo sh -c 'echo "<h1>Hello from AWS</h1>" > /var/www/html/index.html'
```

![img20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540894/0147b432-fc3d-b049-96fe-44723e304fb4.png)

# インスタンスの起動/停止

使わないときは、インスタンスを停止させておきましょう。もう使うことが無いようであれば、「インスタンスを終了」を選択し、インスタンスを削除します。

![img21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540894/37339a59-5027-28b8-96f0-552b7b9c2421.png)