AWS の EC2 を使った公サーバーで自作メール送信APIを使えるようにする

前回完成したGo言語とSendGridを使ったメール送信APIを、いよいよ本番環境の EC2 サーバーで実装します！

本APIの開発方法はこちらにまとめています↓↓↓

https://qiita.com/haruki-lo-shelon/items/3ed239d5479f84b10384

# EC2でサーバーを立てる

前回の時点でできたAPIでは、localhostでメール送信ができるところまでいきました。

このlocalhostの所を、世界中の人がアクセスできるサーバーにするためにサーバーを借りる必要があります。

お名前ドットコムなどでドメイン名を取得してレンタルサーバーを借りて…ってやっても良かったのですが、今回はAWSのEC2というサービスを使います。

EC2を使うメリットはいくつかありますが、少ない使用量であれば無料で使えるのがポイントでしょうか。そして使用量が一定ラインを越えたらその分だけ有料になります。詳しくはAWSのサイトをご覧ください。

EC2でのインスタンスやsshキーなどの作成方法はまた後日に記事にします。（一番大事かも…笑）

# EC2でGo言語の環境構築・準備

インスタンスやSSHキーができたらEC2でGo言語の環境構築をします。
ホームディレクトリ（カレントディレクトリ）直下の.sshディレクトリにSSHキー（tokumemo-key.pem）を入れておきます。

もうGo言語の環境構築は自分のパソコンにしたはずでは？と思うかもですが、イメージとしてはサーバーにもう一つのパソコンがあって、そのパソコンでプログラムを実行させる必要があるのです。

つまり、前作ったコードをEC2環境でもう一度書かないといけないんです！…というのはめんどくさいので、便利なコマンドを使ってファイルをローカル環境からEC2環境にコピーできます。詳しくは後程。

## EC2環境(Amazon Linux)に入る

まず、作成したSSHキーのアクセス権をユーザーの読み取りと実行のみを許可しておきます。

SSHキーのプロパティを開いて以下のように設定します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2388259/78a5b029-598f-914b-6827-47acc3ad0e76.png)

それができたらEC2環境にコマンドプロンプトから入ります。
.sshの親ディレクトリで次のコマンドを実行します。
~~~
ssh -i .ssh/tokumemo-key.pem ec2-user@xxx.xxx.xxx.xxx
~~~
xxx.xxx.xxx.xxxにはインスタンスのパブリックIPアドレスを入れます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2388259/50916ba8-5361-4cd3-edb3-367ceb3c7e8f.png)
上のような表示が出たらOKです。

ここからはAmazonLinux環境ですので、Linuxのコマンドを使用していくことになります。

## EC2にGoをダウンロード

以下のコマンドをEC2環境のAmazon Linuxで打ち込みます。
~~~
wget https://dl.google.com/go/go1.17.8.linux-amd64.tar.gz
~~~
Goの公式サイトで最新のバージョンを確認して、上記の1.17.8の部分を書き換えて実行してください。

## ダウンロードしたパッケージを解凍

Goのパッケージをダウンロードできたら続けて以下のコマンドを実行します。
~~~
sudo tar -C /usr/local -xzf go1.13.5.linux-amd64.tar.gz
~~~

## パスを通す

自分のパソコンにGOPATHを設定したように、EC2環境でもGOPATHを設定します。

設定する場所は「.bash_profile」というファイルです。このファイルを編集します。
~~~
vi .bash_profile
~~~
ファイルを開けたら、キーボードの「i」を押して入力モードにします。

そしてファイルの最後に次の2行を追加します。
~~~:.bash_profile
export GOPATH="$HOME/go"
export PATH=$PATH:$GOPATH/bin
~~~

編集が終わったらEscで入力モードからコマンドモードに切り替え、「:wq」と入力してEnterを押します。

これでファイルの保存が終わりました。続けて
~~~
source .profile
~~~
を実行してください。これで変更したファイルを読み込みます。
~~~
go version
~~~
最後にこれを実行して「go version go1.17.8 linux/amd64」と出たらインストール完了です。

## EC2にプログラムファイルをコピー

ではここから以前作成したAPIのプログラムファイルをPCのローカル環境からEC2環境にコピーして持ってきます。

以下のコマンドで一旦EC2環境から抜けます。
~~~
exit
~~~
EC2へのファイルのコピペはscpコマンドを使います。
~~~
scp -r -i .ssh/tokumemo-key.pem go_sendmail ec2-user@xxx.xxx.xxx.xxx:/home/ec2-user/
~~~
使い方は以下のようになっています。-rオプションを使うとディレクトリを送信することができるようになります。
~~~
scp -r -i sshキーのファイルパス 転送したいファイルもしくはディレクトリ ec2-user@xxx.xxx.xxx.xxx:/home/ec2-user/転送先のパス
~~~

## ファイルの所有者を変更

プログラムファイルを手に入れたので早速APIを実行したいところですが、ファイルの所有者を変更しないとGo言語が実行できないようです。

ここでは、先ほどインストールしたGoのパッケージの所有者がrootユーザーになっているようなのでec2-userに所有権を移してあげます。

とりあえずまたssh -i .ssh/tokumemo-key.pem ec2-user@xxx.xxx.xxx.xxxでEC2に接続します。

ls -lでファイルやディレクトリの所有者を確認してみます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2388259/42e9c27c-fdbc-54aa-b1fe-fae46eb046c1.png)

上のようにgoディレクトリの赤丸で囲った部分がrootになっている場合は所有者を変更する必要があります。ここがユーザー名（ここではデフォルトのec2-user）になっている場合は変更する必要はありません。

変更する場合、まずrootユーザーとしてログインします。ファイルの所有者を変更できるのはrootユーザーのみだからです。
~~~
sudo su -
~~~
これで、コマンド入力スペースの左側の今までec2-userだったのがrootに変わったことが確認出来たらOKです。

続けてファイルの所有者を変更します。
~~~
chown -R ec2-user go
~~~
ファイルの所有者を変更するにはchownコマンドを使用します。-Rオプションでディレクトリの所有者も変更できるようになります。使い方は以下の通りです。
~~~
chown -R 所有させたいユーザー ファイル名
~~~

変更できたらもう一度ls -lで確認してみましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2388259/c4efc888-28b4-36de-e6e2-0af0d0f29fb4.png)

所有者がec2-userになっていますね！

最後にrootユーザーからログアウトしてec2-userに戻っておきましょう。
~~~
exit
~~~

# ポート番号設定・解放

API通信に利用するポート番号はどうやら1024以上でないとPermission deniedになるらしいので、新たにポート番号を解放してあげる必要があります。

## プログラムコードを編集してポート番号を設定

一つだけプログラムコードを変更しないといけない箇所があります。main.goファイルのサーバーを立てる関数の引数です。

まずAPIプログラムのディレクトリに入ります。
~~~
cd go_sendmail
~~~
main.goを編集します。
~~~
vi main.go
~~~
~~~go:main.go
package main

import (
	"go_sendmail/handler"
	"log"
	"net/http"

	"github.com/ant0ine/go-json-rest/rest"
)

func main() {
	//REST APIでpost処理を実現
	api := rest.NewApi()
	api.Use(rest.DefaultDevStack...)
	router, err := rest.MakeRouter(
		rest.Post("/post", handler.PostEmail),
	)
	if err != nil {
		log.Fatal(err)
	}
	api.SetApp(router)
	log.Fatal(http.ListenAndServe(":12345", api.MakeHandler()))
}
~~~

変更するのは22行目のみです。上のコードは変更後のものです。前回は:80だったのが:12345になっています。

ここはポート番号を入れるところなんですが、ポート番号は1024以上でないとPermission deniedになるっぽいので、ポート番号はテキトー12345にしました。それに合わせてEC2のセキュリティグループからインバウンドルールを追加します。

ポート番号を解放

EC2→セキュリティグループ→インバウンドルールを編集の順に押します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2388259/9a1eafd2-0aab-e267-1227-b720303af591.png)

ルールを追加します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2388259/bdf5afd8-3a83-6b49-9655-0add38ad7558.png)

手書きで汚くて申し訳ないですが、プログラムに設定したものと同じポート番号を追加します。

# 実行

いよいよ実行に移ります。ローカルのテスト環境とほとんど同じ手順です。

## Goパッケージをダウンロード

EC2環境でec2-userとしてログインしている状態かつカレントディレクトリがgo_sendmailの状態で、まず作成したメール送信APIで使うGoのパッケージをダウンロードします。

以下のコマンドを一つずつ実行します。
~~~
go get "github.com/sendgrid/sendgrid-go"
go get "github.com/sendgrid/sendgrid-go/helpers/mail"
go get "github.com/joho/godotenv"
go get "github.com/ant0ine/go-json-rest/rest"
~~~

一応modファイルの生成も試しておきましょう。「go.modファイルは既に存在します」的なことを言われてもそのままで大丈夫です。
~~~
go mod init go_sendmail
~~~

## メール送信

続けてサーバーを立てます。
~~~
go run main.go
~~~
ここでコマンドプロンプトを新しくもう一つ開いて、またssh -i .ssh/tokumemo-key.pem ec2-user@xxx.xxx.xxx.xxxでEC2に接続してから
~~~
curl -i -H "Content-Type: application/json" -d "{\"Name\":\"taro\",\"Subject\":\"test\",\"Text\":\"hello\",\"Email\":\"example@email.com\"}" http://xxx.xxx.xxx.xxx:12345/post
~~~
を実行しましょう。xxx.xxx.xxx.xxxには同じようにインスタンスのパブリックIPv4アドレスを入れます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2388259/dae96193-2356-6ada-ac3d-dcdb4e0883f7.png)
これで.encファイルで指定した宛先にメールが届いていたら成功です！