サルでもできる!? Rails6 のアプリをAWS EC2にデプロイするまでの全手順【後半】（独自ドメイン, HTTPS化, S3, CloudFront）

この記事では，画像投稿機能の付いた `Rails 6` のアプリを `AWS EC2` にデプロイするまでの全過程を解説します。

[【前半】](https://qiita.com/take18k_tech/items/5710ad9d00ea4c13ce36) でRailsアプリのデプロイはひとまず完了しましたが，まだまだすべきことがたくさんあります。続きも気を抜かずに頑張りましょう！

章 | タイトル
--- | ---
 | [【前半】](https://qiita.com/take18k_tech/items/5710ad9d00ea4c13ce36)
1章 | はじめに
2章 | VPC
3章 | RDS
4章 | EC2
5章 | サーバー構築
6章 | デプロイ(Capistrano)
 | 【後半】 <-- こちら
7章 | 独自ドメイン
8章 | HTTPS化(ACM, ALB)
9章 | デプロイ関連事項
10章 | S3
11章 | CloudFront
12章 | 削除方法

## 7. 独自ドメイン

Railsアプリを公開することができましたが，現状では2つ大きな問題を抱えています。

- サイトの URL が不自然
  - `google.com` のような `独自ドメイン` ではない
- HTTPSではない
  - Google Chrome で「このサイトへの接続は保護されていません」という警告が出る

まずは前者から解決していきましょう。

`aws-sample-app.com` のような URL でアクセスできるようにするには， `ドメイン` を取得する必要があります。

`ドメイン` は有料ですが，こだわらなければ初年度は数百円程度で取得できます。

この記事では昔から代表的な `レジストラ` である「お名前.com」で取得する前提で解説します。

### 7.1 ドメインの購入

- 「お名前.com」にアクセス
  - https://www.onamae.com/

- 検索窓に取得したいドメイン名を入力し，「検索」ボタンをクリック
  - ドメインに使用できる文字は「半角英数字」と「ハイフン `-`」です
  - 「アンダースコア `_`」 は使用できません

![7_1a.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431142/f18ae5fa-b5ae-2ee5-76e5-d26a113c3a1a.png)

- `.com` などのドメインを選択し，「料金確認へ進む」ボタンをクリック
  - 自動選択されているチェックを外し忘れないように注意しましょう
  - こだわりがなければ初年度の安いドメインを取得してもよいでしょう

- 購入処理を行って下さい。「Whois情報公開代行」は必須ですが，その他のオプションは全て不要です
  - 「サーバー」は「利用しない」をチェック
  - 「Whois情報公開代行メール転送オプション」などは全てチェック不要

- 「お申し込みを受け付けました。」と表示されたら「ドメインの設定はこちら」のリンクをクリック

【備考】後に続きの操作をおこないますので，他のタブで続きの作業を進めて下さい

【注意】初めて「お名前.com」を利用される方は，「メールアドレスの認証手続き」に関するメールが届くと思います。認証しませんと2週間後にドメインを使用できなくなりますので，届いたメールは一通り目を通して下さい。

#### 自動更新の解除

初期設定では，ドメインの更新期限日を過ぎますと自動更新・自動課金されます。

2年目以降は料金が高くなるドメインが多いですので，自動更新を解除したい場合は以下の操作を行ってください。

- 「お名前.com」のページ上側にあるタブの「ドメイン」を選択

- 「更新画面から移動する」をクリック

- アプリで使用するドメインを選択

![7_1b.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431142/8d447b78-b630-0ab1-bb65-e1bc8ba8c6f2.png)

- 「自動更新」ボタンをクリック

![7_1c.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431142/c41d2e16-fb57-6b9d-1354-400bd2190930.png)

- 「確認画面へ進む」をクリック

- 「自動更新設定申込内容」の項目が「解除する」になっていることを確認の上，「規約に同意し、上記内容を申し込む」ボタンをクリック

![7_1d.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431142/de1a3397-1cd6-f932-e98d-3bed668e661c.png)

- 「解除する」ボタンをクリック

- 「ドメイン一覧」のタブをクリック

【備考】後に続きの操作をおこないますので，続きの作業は他のタブで進めて下さい

### 7.2 IPアドレスとドメインの関連付け

- [(公式) Amazon Route 53](https://aws.amazon.com/jp/route53/)

`Route 53` を利用することで，先ほど購入した `ドメイン` を `IPアドレス` に変換することができます。

通常の使用範囲内ならば月100円もかかりません。

- `AWS` の画面左上の「サービス」を開き、検索欄に「route」と入力し、「Route 53」を選択

- 「ホストゾーンの作成」ボタンをクリック

キー | 値
--- | ---
ドメイン名 | 取得したドメインを記載
説明 - オプション | アプリ名_domain
タイプ | パブリックホストゾーン

![7_2a.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431142/31b5146a-c6dc-12c8-f3c8-7f6cf2844ddf.png)

- 「ホストゾーンの作成」ボタンをクリック

- タイプが「NS」の方の「値/トラフィックのルーティング先」に表示されている4つを `ネームサーバー` としてメモしておいて下さい
  - 【要注意】メモする際に，それぞれの最後についている「ドット `.`」は削除して下さい！

![7_2b.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431142/0540c23f-6810-907c-a3c9-e3a67d9b8edb.png)

### 7.3 ネームサーバーの変更

先ほど残しておいた「お名前.com」に移動して下さい

（タブを閉じてしまった場合は，再度「お名前.com」にアクセスし，ログインして下さい）

- 「ドメイン一覧」の中から取得した「ドメイン名」を選択

- 「ネームサーバー情報」の項目の「ネームサーバーの変更」をクリック

![7_3a.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431142/a71296f6-c84d-c9e0-b922-c05ae9fbe318.png)

- 「2.ネームサーバーの選択」をクリック

- 「その他」タブをクリックし，「その他のネームサーバーを使う」の方にチェックを入れ，先ほどメモした4つの `ネームサーバー` をコピペして下さい
  - 先ほど注意しました通り，最後についている「ドット `.`」は入力しないで下さい

![7_3b.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431142/aa240bb7-f80e-7dc2-6e90-85397b88ce09.png)

### 7.4 ネームサーバーの確認

ローカル環境のターミナルから以下を実行して下さい。

```zsh:ローカル環境のターミナル
dig ドメイン名 NS +short
```

登録した4つのドメインが入っていればOKです。（順番が入れ替わっていてもOK）

デフォルトの2つしか入っていない場合は，しばらく待ってから再度先ほどのコマンドを実行しましょう。

### 7.5 ドメインの適用

- `AWS` の `Route 53` の先ほどの続きの画面から，「レコードを作成」をクリック

キー | 値
--- | ---
レコード名 | ※入力しない
値 | `Elastic IP` を入力
レコードタイプ | A

![7_5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431142/35d28993-eba4-08c9-11f9-6b62f2cb6479.png)

これで準備が完了です。まずは，ローカル環境のターミナルから以下を実行して下さい。

```zsh:ローカル環境のターミナル
curl -I ドメイン名
```

最初に `HTTP/1.1 200 OK` もしくは `HTTP/1.1 302` が出れば正常です。

前回は `Elastic IP` でなければアクセスできませんでしたが，今度は `ドメイン名` でアクセスできる状態になっています。

ブラウザから `ドメイン名` でアクセスし， `スーパーリロード` して下さい。（ショートカットキーは `command + shift + r`）

## 8. HTTPS化(ACM, ALB)

次はこちらの問題に対処していきましょう。

- HTTPSではない
  - Google Chrome で「このサイトへの接続は保護されていません」という警告が出る

【備考】 `ELB` の `Application Load Balancer(ALB)` を利用しますので，月2000円程度の費用がかかります。

![8_0.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431142/b4606718-4d78-998b-4be1-4cb03d9e8b5c.png)

### 8.1 ACM

- [(公式) AWS Certificate Manager(ACM)](https://aws.amazon.com/jp/certificate-manager/)

`HTTPS化` には，まず， `SSL/TLS サーバー証明書` を取得する必要があります。

`Let's Encrypt` で取得する方法が有名ですが，AWSを利用する場合は `SSL/TLS サーバー証明書` を `ACM` で取得し， `ALB` に関連付けるのが一般的な手法です。作業が楽で，更新の手間も不要になります。

`ALB` と関連付けますので， `ACM` 自体は無料で利用できます。

- `AWS` の画面左上の「サービス」を開き、検索欄に「acm」と入力し、「Certificate Manager」を選択

- 「証明書のプロビジョニング」の「今すぐ始める」ボタンをクリック

- 「パブリック証明書のリクエスト」を選択した状態で「証明書のリクエスト」ボタンをクリック

- 「この証明書に別の名前を追加」をクリック

- 取得した「ドメイン名」と「*.ドメイン名」を入力

- 「次へ」ボタンをクリック

![8_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431142/72017c81-9363-7c9e-6623-0ca64eee20b9.png)

- 「DNS の検証」を選択した状態で「次へ」ボタンをクリック

タグ名 | 値
--- | ---
Name | アプリ名_alb

- 「確認」ボタンをクリック

- 「確定とリクエスト」ボタンをクリック

- 「続行」ボタンをクリック

### 8.2 DNS検証用の CNAME レコード追加

- ドメインの欄のプルダウンを開き，「Route 53 でのレコードの作成」ボタンをクリック
  - 2つ表示されていますが，どちらか片方のみでOKです
  - プルダウンが表示されない場合は，一度リロードして下さい

![8_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431142/ca75a5ae-4282-6441-1c8d-301325003a0e.png)

- 「作成」ボタンをクリック

【注意】 `8.3` は先に行っても問題ありませんが， `8.4` 以降の作業は，状況が「検証保留中」から「発行済み」に変わってから行って下さい

### 8.3 ALB 用のセキュリティグループの作成

- [(公式) Elastic Load Balancing(ELB)](https://aws.amazon.com/jp/certificate-manager/)

【構成内容】 `クライアント` --(HTTP or HTTPS)--> `ALB` --(HTTP)--> `EC2`

`ELB` の内の `ALB` (Application Load Balancer) を使用し，先ほど取得した `SSL/TLS サーバー証明書` を使用できるように設定していきましょう。

`ALB` は `EC2` の前にリクエストを受け，（一般には複数の） `EC2` に分散します。このことを踏まえたセキュリティグループを作成しましょう。

- 画面左上の「サービス」を開き、検索欄に「ec2」と入力し、「EC2」を選択

- `EC2` 画面左のメニューバーの「セキュリティグループ」を選択し，「セキュリティグループを作成」ボタンをクリック

キー | 値
--- | ---
セキュリティグループ名 | アプリ名\_alb\_security\_group
説明 | アプリ名\_alb\_security\_group
VPC | アプリ名_vpc

「インバウンドルール」の「ルールを追加」を2回クリック

キー | 値
--- | ---
タイプ | HTTP
プロトコル | TCP ※自動選択
ポート範囲 | 80 ※自動選択
ソース | 任意の場所 （0.0.0.0/0 と ::/0 が表示）
説明 |  ※空白でOK

キー | 値
--- | ---
タイプ | HTTPS
プロトコル | TCP ※自動選択
ポート範囲 | 443 ※自動選択
ソース | 任意の場所 （0.0.0.0/0 と ::/0 が表示）
説明 | ※空白でOK

![8_3a.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431142/0c9af904-23d9-e5ad-8ae5-2ab0984cbb1a.png)

「アウトバウンドルール」は `デフォルトの設定を削除した後` 「ルールを追加」をクリックし，以下を追加

![8_3b.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431142/f6837800-e680-b01d-33af-764503b24f04.png)

キー | 値
--- | ---
タイプ | HTTP
プロトコル | TCP ※自動選択
ポート範囲 | 80 ※自動選択
ソース | カスタム: アプリ名\_ec2\_security\_group
説明 |  ※空白でOK

![8_3c.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431142/727135e3-b4f3-3914-3352-5bd1f6d6dcbc.png)

作成後に次の図のようにルールが定まっているかどうかを確認して下さい。

![8_3d.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431142/e660a8b4-d980-e0bf-8d39-0512e4d4dd77.png)
![8_3e.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431142/e7a6d058-78cf-b6f0-4f32-95da42127e10.png)

### 8.4 ロードバランサーの設定

- 画面左のメニューバーの「ロードバランサー」を選択

- 「ロードバランサーの作成」ボタンをクリック

- 「HTTP, HTTPS」の方の「作成」ボタンをクリック

■ 手順 1: ロードバランサーの設定

- 【基本的な設定】

キー | 値
--- | ---
名前 | アプリ名-alb ※ ハイフンに変更

他はデフォルト

- 【リスナー】

「リスナーの追加」ボタンをクリックし，「HTTPS」を選択

- 【アベイラビリティゾーン】

キー | 値
--- | ---
VPC | アプリ名_vpc
アベイラビリティーゾーン | 「ap-northeast-1a」を選択し「アプリ名\_public\_1a\_subnet」を選択
アベイラビリティーゾーン | 「ap-northeast-1c」を選択し「アプリ名\_public\_1c\_subnet」を選択

「次の手順: セキュリティ設定の構成」ボタンをクリック

![8_4a.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431142/dfe000d6-2480-e1f4-31c0-ca0324661e87.png)

■ 手順 2: セキュリティ設定の構成

- 「証明書の名前」がアプリ用のドメインであることを確認し，「セキュリティグループの設定」をクリック

![8_4b.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431142/4ed9cda4-4bbe-bd55-a109-b8198c10749b.png)

■ 手順 3: セキュリティグループの設定

- 「アプリ名\_alb\_security\_group」を選択し，「次の手順: ルーティングの設定」ボタンをクリック

![8_4c.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431142/7e670112-80c4-1821-b0cb-1b57bb51a486.png)

■ 手順 4: ルーティングの設定

- ターゲットグループ

キー | 値
--- | ---
ターゲットグループ | 新しいターゲットグループ
名前 | アプリ名\-target\-group ※ ハイフンに変更
ターゲットの種類 | インスタンス ※デフォルト
プロトコル | HTTP ※自動設定
ポート | 80 ※自動設定

- ヘルスチェック

デフォルト設定でOK

「次の手順: ターゲットの登録」ボタンをクリック

![8_4d.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431142/fe631d18-118b-6f18-8a6f-a38cb371a1c9.png)

■ 手順 5: ターゲットの登録

- 「インスタンス」欄から、「アプリ名_instance」にチェックを入れた状態で「登録済みに追加」ボタンをクリック

![8_4e.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431142/39f9a26d-3d0f-698c-11f0-247a325cdd4d.png)

- 「次の手順: 確認」をクリック

- 「作成」ボタンをクリック

### 8.5 Route 53の設定を修正

ドメインを `EC2` から先ほど作成した `ALB` に割り当てるように設定を変更しましょう。

- `AWS` の画面左上の「サービス」を開き、検索欄に「route」と入力し、「Route 53」を選択

- 「ホストゾーン」をクリック

- アプリで使用するドメインをクリック

![8_5a.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431142/0aa6c839-c363-3cef-f5ea-885b1bafca30.png)

- 「タイプA」の「ドメイン名」のレコードをクリックし，右上に現れた「レコードを編集」ボタンをクリック

![9.41.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431142/e06c720d-b06d-afba-6909-4b1b3c8ee720.png)

- 「値」の近くにある「エイリアス」をオンにする

- 「トラフィックのルーティング先」の箇所を変更して下さい
  - 「Application Load Balancer と Classic Load Balancer へのエイリアス」を選択
  - 「アジアパシフィック (東京) [ap-northeast-1]」を選択
  - 「アプリ名-alb」を含むロードバランサーを選択

![9.48.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431142/b549e641-1b3e-748e-b1a5-c3579e716a36.png)

- 「保存」ボタンをクリック

### 8.6 セキュリティグループの修正

`ALB` 経由でアクセスされるように変更したため， `EC2` は `ALB` からのアクセスに限定すべきです。そのため， `EC2` 用のセキュリティグループを修正します。

- `AWS` の画面左上の「サービス」を開き、検索欄に「ec2」と入力し、「EC2」を選択

- 画面左のメニューバーの「セキュリティグループ」を選択

- 「アプリ名\_ec2\_security\_group」にチェックを入れ，「アクション」ボタンをクリックし，「インバウンドルールを編集」ボタンをクリック

![8_6a.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431142/db4ce5da-b485-64cf-ce2a-4ecedf160982.png)

- タイプが `HTTP` のものを全て削除し，「ルールを追加」をクリックし，以下を設定
  - `SSH` は削除しないこと

![8_6b.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431142/0cbdf1bc-75ea-32d6-c92d-954b888ce814.png)

キー | 値
--- | ---
タイプ | HTTP
ソース | カスタム: アプリ名\_alb\_security\_group
説明 |  ※空白でOK

![8_6c.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431142/62fe0e44-b7d2-6dad-e925-9a657593aca6.png)

- 「ルールを保存」ボタンをクリック

### 8.7 Nginx の設定ファイルを修正

`ALB` への接続に使用するプロトコルが `HTTPS` であることを識別できるよう，`Nginx` の設定ファイルを修正し，再起動しておきましょう。

（こちらを実行しないと，例えば POST リクエスト時にエラーが発生します）

```bash:サーバー環境のターミナル
sudo sed -i s/X-Forwarded-Proto\ \$scheme\;/X-Forwarded-Proto\ https\;/ /etc/nginx/conf.d/$APP_NAME.conf
sudo sed -i s/X-Forwarded-Proto\ http\;/X-Forwarded-Proto\ https\;/ /etc/nginx/conf.d/$APP_NAME.conf
sudo service nginx restart
```

【補足】最初の2行は， `/etc/nginx/conf.d/$APP_NAME.conf` 内の `X-Forwarded-Proto $scheme;` と `X-Forwarded-Proto http;` を両方 `X-Forwarded-Proto https;` に置換するコマンドです。

それでは， `HTTPS` でアクセスできるかを確認しましょう。まずはターミナルから以下を実行して下さい。

```zsh:ターミナル（ローカル側でもサーバー側でもOK）
curl -I https://ドメイン名
```

最初に `HTTP/2 200` もしくは `HTTP/2 302` が表示されれば正常です。次にブラウザから `https://ドメイン名` にアクセスし， `スーパーリロード` して下さい。（ショートカットキーは `command + shift + r`）

ブラウザのURLの左隣に「鍵マーク」が表示され，アプリが問題なく開けばOKです！

![8_7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431142/2b444b55-d17e-b4d3-2dd9-8e488c11f4db.png)

### 8.8 HTTPS にリダイレクト

【参考】 https://aws.amazon.com/jp/premiumsupport/knowledge-center/elb-redirect-http-to-https-using-alb/

最後に， `HTTP` でのアクセスを `HTTPS` にリダイレクトするように設定しましょう。

- `EC2`の画面左のメニューバーの「ロードバランサー」をクリック

- （「アプリ名-alb」を選択した状態で）「リスナー」タブをクリック

- `HTTP : 80` の方の 「ルールの表示/編集」をクリック

![8_8a.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431142/f1c8ea7a-eb86-e9d4-9b86-6b43c39118de.png)

- 上の「鉛筆」マークをクリックし，下に出現した「鉛筆」マークをクリック

![8_8b.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431142/d6ac47a1-75bf-0e2f-1905-675c117dd528.png)

- 「THEN」の項目の転送先にある「ゴミ箱」マークをクリックして削除

![8_8c.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431142/f33d4a66-3d08-d4dd-ba7b-46ea760bb497.png)

- 「アクションの追加」を選択し，「リダイレクト先」をクリック

- 「HTTPS」になっていることを確認し，ポートに `443` を入力

- 「チェックマーク」をクリック

- 右上の「更新」ボタンをクリック

![8_8d.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431142/89a73277-8026-a69c-84b9-ccfd28d48710.png)

これで `http` でアクセスした場合も `https` に自動変換されるようになりました。ターミナルから以下を実行してみましょう。

```zsh:ターミナル（ローカル側でもサーバー側でもOK）
curl -I http://ドメイン名
```

最初に `HTTP/1.1 301 Moved Permanently` が表示され，最後に `Location: https://アプリ名:443/` が表示されていればOKです。

ブラウザでも `http://ドメイン名` でアクセスしてみましょう。URLの左隣に鍵マークが付いていればOKです！

お疲れ様でした！

### 8.9 最後に

作業が終わりましたので，ローカル環境で定義したグローバル変数 `$APP_NAME` は消しておくこととしましょう。

```zsh:ローカル環境のターミナル
# zsh の場合
vi ~/.zshrc

# bash の場合
vi ~/.bash_profile
```

一番最後の行にある `export APP_NAME=アプリ名` を削除して下さい。

### 8.10 EC2のユーザーにパスワードを設定（任意）

実運用しないポートフォリオならスキップしても良いですが，セキュリティを高めるためEC2のユーザーにパスワードを設定し， `sudo` コマンド実行時にパスワードを求められるように設定することをお勧めします。

（作業を楽にするため，EC2のユーザーはパスワード無しで `sudo` コマンドを使用できる状態にしていました）

---

【注意】以下の操作はくれぐれも慎重に行って下さい。操作を間違えた場合，EC2の構築からやり直すこととなる可能性があります。セキュリティを高めるための操作ですが，個人のポートフォリオでは必須ではありませんので，自信がない場合は次の章に進んでもOKです。

---

```bash:サーバー環境のターミナル
sudo passwd `whoami`
設定したいEC2のパスワードを入力
EC2のパスワードを再入力
```

「EC2のパスワード」は必ずメモしておいて下さい。

```bash:サーバー環境のターミナル
sudo visudo
```

`Vim` で開かれたら，一番最後の行の `NOPASSWD: ` の箇所のみ削り，次の状態にして下さい。

```none:sudoers
ユーザー名 ALL=(ALL) ALL
```

【注意】`ユーザー名 ALL=(ALL) NOPASSWD: ALL` を「全て」削ってはいけません！編集を間違えると，二度と sudo コマンドを実行できなくなる恐れがありますので，慎重に行ってください。

これで `sudo` コマンドを実行した際に今後はパスワードを尋ねられるようになります。

以下を実行し，パスワードを求められるかどうか，パスワードを入力してコマンドを実行できるかどうかを確かめて下さい。

```bash:サーバー環境のターミナル
sudo ls
```

さて，このままでは，デプロイ実行時に sudo が実行できずエラーが出るようになります。その対策を行いましょう。

```rb:Gemfile
group :development do
  # 略
  # ***** sudo 実行時にパスワード入力できるようにするため以下を追加 *****
  gem 'sshkit-sudo'
  # ***** 以上を追加 *****
end
```

```zsh:ローカル環境のターミナル
bundle install
```

```rb:Capfile
# ***** 以下を追加 *****
require "sshkit/sudo"
# ***** 以上を追加 *****
```

```rb:config/deploy.rb
# ***** 以下を追加 *****
set :pty, true
# ***** 以上を追加 *****
```

これで完了です。

デプロイ時に EC2ユーザーのパスワードを求められた場合は，先程設定したパスワードを入力して対応するようにしてください。

## 9. デプロイ関連事項

この章は必要な場合のみご覧ください。

### 9.1 アプリ修正時の反映方法

以下のコマンドで「GitHub」の master ブランチをAWS側に反映させることができます。

```zsh:ローカル環境のターミナル
# Railsアプリのルートディレクトリに移動してから
bundle exec cap production deploy
```

【注意】 Heroku のデプロイで使用する `git push heroku master` は「ローカル」の master ブランチを反映させるコマンドです。 `bundle exec cap production deploy` コマンドは「ローカル」ではなく「GitHub」である点に注意しましょう。

### 9.2 master以外のブランチを反映させたい

```config/deploy.rb
set :branch, ENV['BRANCH'] || "master"
```

を追加すれば，例えば以下のコマンドで「GitHub」の `hoge` ブランチを反映できます。

```zsh:ローカル環境のターミナル
bundle exec cap production deploy BRANCH=hoge
```

例えば，現在のブランチをAWS側で動作確認したい場合は次の手順になります。

```zsh:ローカル環境のターミナル
# add, commit の実行後
git push origin HEAD
bundle exec cap production deploy BRANCH=HEAD
```

### 9.3 AWS側で Rails コマンドや rake タスクを実行する方法

サーバー側のアプリは `/var/www/$APP_NAME/current` に入っています。

まずはここまで移動し，必要に応じて `yarn install --check-files` を実行して下さい。

```bash:サーバー環境のターミナル
cd /var/www/$APP_NAME/current
yarn install --check-files
```

その上で，必要なコマンドを実行しましょう。コマンド例を紹介します。

- サーバー側で `rails db:seed` を実行したい場合

```bash:サーバー環境のターミナル(/var/www/$APP_NAME/current)
bin/rails db:seed RAILS_ENV=production
```

`bin/rails` は `bundle exec rails` でも問題ありませんが， `rails` ではダメです。また， `RAILS_ENV=production` が必要である点に注意して下さい。

- サーバー側で `rails db:migrate:reset` を実行したい場合

```bash:サーバー環境のターミナル(/var/www/$APP_NAME/current)
bin/rails db:migrate:reset RAILS_ENV=production DISABLE_DATABASE_ENVIRONMENT_CHECK=1
```

本番環境のデータベースを削除（リセットを含む）したい場合は， `DISABLE_DATABASE_ENVIRONMENT_CHECK=1` が必要です。

- サーバー側で `rails console` を実行したい場合

```bash:サーバー環境のターミナル(/var/www/$APP_NAME/current)
bin/rails c -e production
```

オプションが `RAILS_ENV=production` ではなく `-e production` の書き方になります。

- サーバー側で `rake` タスクを実行したい場合

```bash:サーバー環境のターミナル(/var/www/$APP_NAME/current)
bundle exec rake タスク名 RAILS_ENV=production
```

タスク名は `bundle exec rake -T` で確認できます。`bundle exec rake` は `bin/rails` でもOKですが `rake` ではダメです。

### 9.4 サーバー側で ログ を確認する方法

サーバー側の `ログ` は `/var/www/$APP_NAME/shared/log` に入っています。

```bash:サーバー環境のターミナル
cd /var/www/$APP_NAME/shared/log
ls
```

でログファイルの一覧を確認できます。

エラーが出た場合は，`nginx.error.log`, `puma_error.log`, `production.log` を確認しましょう。

```bash:サーバー環境のターミナル(/var/www/$APP_NAME/shared/log)
# ログを全て表示したい場合
cat nginx.error.log
# 最後の30行を表示したい場合
tail -n 30 nginx.error.log
# ログの追加分のみを自動表示したい場合（control + c で終了）
tail -f nginx.error.log
```

## 10. S3

【注意】10章, 11章は， `CarrierWave` や `ActiveStorage` などで画像の投稿機能を実装している場合のみ，実行して下さい。

現状でも画像の投稿は可能ですが， `AWS S3` を使用することで，Webサーバー（`EC2`）のストレージが画像で圧迫されるのを防いだり，負荷分散ができるなど複数のメリットがあります。

さらに， `CloudFront` を用いることで画像転送を高速化するところまでを解説します。

### 10.1 S3バケットの作成

- [(公式) Amazon S3](https://aws.amazon.com/jp/s3/)

`S3` は，クラウド型のオブジェクトストレージサービスです。画像に限らずいろいろなデータを保存することができ，簡単なWebサイトの公開にも使用できます。

セキュリティ・耐久性共に優れ，価格も安いのが特徴です。ポートフォリオの画像投稿機能に使用する程度であれば，大抵の場合は無料利用枠内でおさまるでしょう。

`S3` を利用するには，まず， `バケット` を作成する必要があります。

- 画面左上の「サービス」を開き、検索欄に「s3」と入力し、「S3」を選択

- 「バケットの作成」を選択

- 一般的な設定

タイトル | 内容
--- | ---
バケット名 | 任意 ※世界ですでに存在する名前は付けられません
リージョン | アジアパシフィック (東京) ap-northeast-1

【注】 バケット名とリージョン`ap-northeast-1`を忘れないようにメモしておいて下さい。

- ブロックパブリックアクセスのバケット設定

下の2つ（ACL以外）のみをチェックし，注意喚起にもチェック

![10_1a.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431142/a90ba825-2124-040c-7aa4-46ed33f29220.png)
![10_1b.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431142/d081329d-8871-127e-5a5d-c53f2a381adf.png)

「バケットを作成」をクリック

### 10.2 アプリ用のIAMユーザーを作成

次に，アプリ側から `S3` にアクセスするための `アクセスキー` などを入手しましょう。

- 画面左上の「サービス」を開き、検索欄に「iam」と入力し、「IAM」を選択

- 左のメニューから「ユーザー」を選択

- 青いボタン「ユーザーを追加」をクリック

タイトル | 内容
--- | ---
ユーザ名 | アプリ名_user
アクセスの種類 | 「プログラムによるアクセス」にチェック

![10_2a.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431142/f413e036-ef8a-9709-7a60-c5b56efe79f3.png)

- 「次のステップ:アクセス権限」をクリック

- 「既存のポリシーを直接アタッチ」ボタンをクリック

- `AmazonS3FullAccess` をチェックして，「次のステップ: タグ」ボタンをクリック
  - 「参考」のようにより権限を厳しくしたポリシーをアタッチするとより安全です

![10_2b.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431142/67c547be-ff45-de1b-1ba4-6d7586af508f.png)

- 「次のステップ: 確認」ボタンをクリック

- 「ユーザーの作成」をクリック

- 「.csvのダウンロード」ボタンをクリック

「ユーザー名」「アクセスキーID」「シークレットアクセスキー」をメモしておいて下さい。

- 「閉じる」ボタンをクリック

#### 参考: 権限の少ないポリシーを作成

`AmazonS3FullAccess` は `S3` の全ての操作ができる権限ですので，アプリに持たせる権限としては過剰すぎます。

最低限必要な権限をもつポリシーを作成し，`AmazonS3FullAccess` の代わりにこちらをIAMユーザーにアタッチしておくと，万一の場合の被害を軽減することができます。

[参考: CarrierWave](https://rubydoc.info/gems/carrierwave/frames#using-amazon-s3)

```json:IAMポリシー
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": [
                "s3:PutObject",
                "s3:GetObject",
                "s3:DeleteObject",
                "s3:PutObjectAcl",
                "s3:ListAllMyBuckets"
            ],
            "Resource": "*"
        }
    ]
}
```

![10_2c.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431142/11e1f019-bc69-ce83-ecbd-571a579058e6.png)
![10_2d.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431142/fdc6c231-fc2a-340e-e52a-acd49a9175be.png)

さらに安全を求めるならば，バケットまで制限することも可能ですが，ここでは省略します。

### 10.3 CarrierWaveの設定

※ 以下，画像投稿機能に `CarrierWave` を使用していることを前提とします

- [CarrierWave 公式ドキュメント](https://rubydoc.info/gems/carrierwave/frames#using-amazon-s3)

まず，Railsアプリに `fog-aws` を `Gemfile` に追加し，インストールしておきましょう。

```zsh:ローカル環境のターミナル
bundle add fog-aws
```

本番環境のみで `AWS S3` を使用する場合は次のように修正しましょう。

（開発環境でも使用したい場合は，条件分岐せず `storage :fog` のみにして下さい）

```app/uploaders/image_uploader.rb
# 「storage :file」を以下に置き換える
  if Rails.env.production?
    storage :fog
  else
    storage :file
  end
```

次に， `S3` の「アクセスキーID」などを読み込む設定を追加しましょう。

特に「シークレットアクセスキー」は，GitHubに公開してはならないので， `credentials.yml.enc` から読み込む形式とします。

「リージョン」と「バケット名」は公開しても問題ありませんので，直接記載することとします。

```zsh:ローカル環境のターミナル
touch config/initializers/carrier_wave.rb
```

（開発環境でもS3を使用したい場合は，最初の行 `if Rails.env.production?` と最後の行 `end` を削りましょう）

```config/initializers/carrier_wave.rb
if Rails.env.production?
  CarrierWave.configure do |config|
    config.fog_credentials = {
      provider: "AWS",
      aws_access_key_id: Rails.application.credentials.dig(:aws, :access_key_id),
      aws_secret_access_key: Rails.application.credentials.dig(:aws, :secret_access_key),
      region: "ap-northeast-1"
    }
    config.fog_directory = "S3のバケット名"
  end
end
```

- `credentials.yml.enc`を開くため，次のコマンドを実行

```zsh:ターミナル
EDITOR=vi rails credentials:edit
```

- アプリが `S3` にアクセスするために必要な情報を `credentials.yml.enc` に記載しましょう
  - `yaml`形式なので，インデント幅にはくれぐれも注意して下さい
  - 例えば，`access_key_id:`の後に「半角スペース1個」がないだけでエラーになります

```yml:config/credentials.yml.enc
db:
  password: RDSのパスワード
  hostname: RDSのエンドポイント
# 以下を追加
aws:
  access_key_id: IAMユーザーのアクセスキーID
  secret_access_key: IAMユーザーのシークレットアクセスキー
```

### 10.4. 動作確認

念のため以下を実行し，「アクセスキーID」などが取得できることを確認しておいた方がよいでしょう。

```zsh:ローカル環境のターミナル
rails c
# コンソール起動後
Rails.application.credentials.dig(:aws, :access_key_id)
Rails.application.credentials.dig(:aws, :secret_access_key)
# IAMユーザーのアクセスキーID, シークレットアクセスキーが表示されることを確認後
exit
```

コミット・プッシュ（必要があればプルリク・マージ）などを行い，GitHub の master ブランチに変更を反映した上で，`AWS` にデプロイを行いましょう。

```zsh:ローカル環境のターミナル
bundle exec cap production deploy
```

【補足】 `9.2` に記載した方法で，masterブランチにマージする前に確認するのが理想的です

これで本番環境では `S3` に画像を投稿し，読み込みができるようになりました。

ブラウザから `https://ドメイン名` にアクセスし，画像を投稿してみましょう。問題なく画像が投稿・表示できていればOKです。

念のため，AWSにログインし `S3` のバケットに画像が保存されているかどうかも確認しておくとよいでしょう。

バケットを選択し，ディレクトリを選択していき，「オブジェクト URL」をクリックして投稿した画像が表示されていればOKです。

## 11. CloudFront

- [(公式) Amazon CloudFront](https://aws.amazon.com/jp/cloudfront/)

最後に `CloudFront` を用いて画像の表示を高速化できるようにし，さらに画像のURLを独自ドメインに変更しましょう。

`CloudFront` も1年間は無料利用枠があり，料金も安いのであまり気にしなくてよいでしょう。

### 11.1 ACM

`CloudFront` で ACM 証明書を使用するには、「米国東部」リージョンで証明書をリクエストする必要があります。

- `AWS` の画面左上の「サービス」を開き、検索欄に「acm」と入力し、「Certificate Manager」を選択

- 【重要！】右上の「東京」を「米国東部 (バージニア北部)us-east-1」に変更

![11_1a.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431142/43207f3e-227e-9e23-6aca-b0e3e38f670b.png)

- 「証明書のプロビジョニング」の「今すぐ始める」ボタンをクリック

- 「パブリック証明書のリクエスト」を選択した状態で「証明書のリクエスト」ボタンをクリック

- `static.ドメイン名` を入力
  - `static` の箇所は任意ですが，変更する場合は以降も合わせて変更して下さい

![11_1b.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431142/cebd6204-2e46-7d36-2c2f-3f7f7762947c.png)

- 「次へ」ボタンをクリック

- 「DNS の検証」を選択した状態で「次へ」ボタンをクリック

タグ名 | 値
--- | ---
Name | アプリ名_cloudfront

![11_1c.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431142/4b7de402-3c94-0dd6-1e13-15b5a2b3123b.png)

- 「確認」ボタンをクリック

- 「確定とリクエスト」ボタンをクリック

- 「続行」ボタンをクリック

- DNS検証用の CNAME レコードを追加（8.2参照）

`11.3` の作業は，状況が「検証保留中」から「発行済み」に変わってから行う必要があるため，ブラウザのタブは残しておきましょう

### 11.2 CarrierWaveの設定

次に，Railsアプリ側のCarrierWaveの設定に追記しましょう。

```config/initializers/carrier_wave.rb
if Rails.env.production?
  CarrierWave.configure do |config|
    config.fog_credentials = {
      provider: "AWS",
      aws_access_key_id: Rails.application.credentials.dig(:aws, :access_key_id),
      aws_secret_access_key: Rails.application.credentials.dig(:aws, :secret_access_key),
      region: "ap-northeast-1"
    }
    config.fog_directory = "S3のバケット名"
    # ***** 以下を追加 *****
    config.asset_host = "https://static.ドメイン名"
    # ***** 以上を追加 *****
  end
end
```

コミット・プッシュ（必要があればプルリク・マージ）などを行い，GitHub の master ブランチに変更を反映した上で，`AWS` にデプロイを行いましょう。

```zsh:ローカル環境のターミナル
bundle exec cap production deploy
```

### 11.3 CloudFront

【注意】 `ACM` の状況が「検証保留中」から「発行済み」に変わってから行って下さい

- 画面左上の「サービス」を開き、検索欄に「cloudfront」と入力し、「CloudFront」を選択

- 「Create Distribution」ボタンをクリック

- 「Web」の方の「Get Started」を選択

【Origin Settings】

キー | 値
--- | ---
Origin Domain Name | S3のバケット名を選択
Restrict Bucket Access | Yes

![11_3a.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431142/b9eefed8-75f7-72a1-4f4e-83edfdc85bf0.png)

【Default Cache Behavior Settings】

キー | 値
--- | ---
Viewer Protocol Policy | Redirect HTTP to HTTPS

![11_3b.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431142/546be163-6c00-57b0-19ac-49a4a1706d27.png)

【Distribution Settings】

キー | 値
--- | ---
Alternate Domain Names | static.ドメイン名
SSL Certificate | Custom SSL Certificate をチェックし，自分のドメインを選択

![11_3c.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431142/1dfee92c-56a4-04de-763d-9c5c90538457.png)

他はデフォルト設定のまま，右下の「Create Distribution」ボタンをクリック

【注意】 続きの作業は「Status」が「Deployed」になってから行ってください。

### 11.4 Route 53

最後に `CloudFront` 用のAレコードを作成しましょう。

- `AWS` の画面左上の「サービス」を開き、検索欄に「route」と入力し、「Route 53」を選択

- 「ホストゾーン」をクリック

- アプリで使用するドメインをクリック

- 「レコードを作成」ボタンをクリック

- 「シンプルルーティング」にチェックを入れた状態で「次へ」ボタンをクリック

- 「シンプルなレコードを定義」ボタンをクリック

キー | 値
--- | ---
レコード名 | static
値/トラフィックのルーティング先 | CloudFront ディストリビューションへのエイリアス
 | 米国東部 (バージニア北部)
 | CloudFrontのドメイン名を選択
レコードタイプ | A

![11_4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431142/13f779aa-0d71-3652-6837-7493af932c02.png)

- 「シンプルなレコードを定義」ボタンをクリック

これで全ての設定が完了です。

ブラウザから `https://ドメイン名` にアクセスし，再度画像を投稿してみましょう。問題なく画像が投稿・表示できていればOKです。

念のため，AWSにログインし `S3` のバケットに画像が保存されているかどうかも確認しておくとよいでしょう。

「無事全てが完了した！!」という方は是非 <font color="red">**LGTM**</font> もお願いいたします！

## 12. 削除方法

`AWS` は有料ですので，アプリの公開が不要となったタイミングで削除することをお勧めします。

以下，削除の手順を解説しますが，特に有料となっている以下の削除を忘れないようにしましょう。

- RDSインスタンス【高額！】
- ALB（ロードバランサ）【高額！】
- EC2インスタンス【高額！】
- Elastic IP（EC2を削除すると課金対象）
- Route 53
- ACM
- S3（画像投稿機能を付けた場合）
- CloudFront（画像投稿機能を付けた場合）

### 12.1 Route 53 のホストゾーン削除

- Route 53 ダッシュボードに移動
  - （画面左上の「サービス」を開き、検索欄に「route」と入力し、「Route 53」を選択）

- 画面左のメニューバーの「ホストゾーン」をクリック

- アプリで使用したドメインをクリック

- タイプが `A` と `CNAME` のものにチェックを入れ，「削除」ボタンをクリックし，さらに「削除」ボタンをクリック

- 右上の「削除」ボタンをクリック

- 「削除」と入力し，「削除」ボタンをクリック

### 12.2 ALB の削除

- EC2 ダッシュボードに移動
  - （画面左上の「サービス」を開き、検索欄に「ec2」と入力し、「EC2」を選択）

- 画面左のメニューバーの「ロードバランサー」をクリック

- 「アクション」ボタンをクリックし，「削除」をクリック
  - 使用しているロードバランサーが表示されない場合は，右上のリージョンが「東京」になっているか確認

- 「削除」をクリック

### 12.3 CloudFront の削除

【備考】画像投稿機能を付けていない場合は，次に進んで下さい。

- CloudFront ダッシュボードに移動
  - （画面左上の「サービス」を開き、検索欄に「cloudfr」と入力し、「CloudFront」を選択）

- 使用している `Distribution` にチェックを入れて，「Disable」ボタンをクリック

- 「Yes, Disabled」ボタンをクリック

「Status」が「Disabled」になるまで待ちましょう

- 使用している `Distribution` にチェックを入れて，「Delete」ボタンをクリック

- 「Yes, delete」ボタンをクリック

- 「Close」ボタンをクリック

### 12.4 SSL証明書 の削除

- Certificate Manager ダッシュボードに移動
  - （画面左上の「サービス」を開き、検索欄に「acm」と入力し、「Certificate Manager」を選択）

- アプリで使用したドメインを選択し，「アクション」ボタンをクリックし，「削除」をクリック

- 「削除」ボタンをクリック

【備考】画像投稿機能を付けている場合は，「東京」リージョンだけでなく「バージニア北部」リージョンのACMも削除して下さい。

### 12.5 EC2 の削除

- EC2 ダッシュボードに移動
  - （画面左上の「サービス」を開き、検索欄に「ec2」と入力し、「EC2」を選択）

#### ターゲットグループの削除

- 画面左のメニューバーの「ターゲットグループ」をクリック

- アプリで使用していたものを選択した状態で「Action」のプルダウンの「Delete」をクリック

- 「Yes, delete」ボタンをクリック

#### EC2 インスタンスの削除

- 画面左のメニューバーの 「インスタンス」をクリック
- 削除したいインスタンスを選択した状態で「アクション」ボタンをクリックし，「インスタンスの状態」「インスタンスを終了」をクリック（「停止」ではない）
- 「終了」ボタンをクリック

#### Elastic IP の解放

- 画面左のメニューバーの `Elastic IP` をクリック
- 削除したい `Elastic IP` を選択した状態で「アクション」ボタンをクリックし，「Elastic IPアドレスの解放」をクリック
  - EC2終了後少し待たないと解放できません
- 削除したい `Elastic IP` が消えたことを確認

#### その他

- 「キーペア」も削除しましょう
- 「セキュリティグループ」は `VPC` 削除時に自動的に削除されます

### 12.6 RDS の削除

- RDS ダッシュボードに移動
  - （画面左上の「サービス」を開き、検索欄に「rds」と入力し、「RDS」を選択）

####s RDS インスタンスの削除

- 画面左のメニューバーの「データベース」をクリック
- 削除したい DB を選択し，「アクション」ボタンをクリックし，「削除」をクリック
- 「最終スナップショットを作成しますか?」のチェックを外し，「インスタンスの削除後、システムスナップショットとポイントインタイムの復元を含む自動バックアップが利用不可となることを了承しました。」にチェックを入れ，フィールドに「delete me」を入力して「削除」ボタンをクリック

#### その他

- 「サブネットグループ」を削除
  - RDSが削除されるまで削除できません
- 「パラメータグループ」は残してよいでしょう。

### 12.7 VPC の削除

- VPC ダッシュボードに移動
  - （画面左上の「サービス」を開き、検索欄に「vpc」と入力し、「VPC」を選択）

- 削除したい VPC を選択し，「アクション」ボタンをクリックし，「VPC を削除」をクリック

- フィールドに「削除」と記入して「削除」ボタンをクリック

サブネット，インターネットゲートウェイ，ルートテーブルも同時に削除されます。

### 12.8 S3/IAM の削除

【備考】画像投稿機能を付けていない場合は，次に進んで下さい。

#### S3 の削除

- S3 ダッシュボードに移動
  - （画面左上の「サービス」を開き、検索欄に「s3」と入力し、「S3」を選択）

- アプリで使用したバケットを選択し，「空にする」ボタンをクリック

- 「完全に削除」と入力し「空にする」ボタンをクリック

- 「終了」ボタンをクリック

- 「削除」ボタンをクリック

- 「バケット名」を入力し，「バケットを削除」ボタンをクリック

#### IAM の削除

- IAM ダッシュボードに移動
  - （画面左上の「サービス」を開き、検索欄に「iam」と入力し、「IAM」を選択）

- 画面左のメニューバーの「ユーザー」をクリック

- 「アプリ名_user」にチェックを入れ，「ユーザーの削除」ボタンをクリック
  - アプリと関係ないものを削除しないように注意！

- 「はい，削除します」ボタンをクリック

### 12.9 キーペアの削除

#### GitHub の公開鍵を削除

- ブラウザでGitHubにアクセス
- 右上のサムネイル画像をクリック
- 「Settings」をクリック
- 左メニューバーから「SSH and GPG keys」をクリック
- 「アプリ名_git_rsa/pub」の箇所で「Delete」ボタンをクリック
- 「I understand, please delete this SSH key」ボタンをクリック

#### ローカル環境のキーペアの削除

最後に，ローカル環境の秘密鍵と設定を削除しておきましょう。

```zsh:ローカル環境のターミナル
cd ~/.ssh
rm -f アプリ名.pem
vi config
# Host アプリ名 の設定を削除
```