sagara.inkITエンジニアのまとめノート

AWS EC2でNode.js(Express)+Nginxアプリケーションのホスティング環境をVPC上に構築する

AWSのEC2上でNode.jsフレームワークであるExpressで作成したアプリケーション(API)をホスティングする方法を書いていきます。 AWSの仮想ネットワークであるVPCのセッティング方法や、EC2の起動までの流れについても画像付きで丁寧に解説します。

AWSの仮想ネットワークの概要

Node.jsなどで作成したアプリケーションは、AWSの場合はVPCと呼ばれる仮想ネットワーク空間上に作成します。 そのため、EC2を立ち上げる前にまずはその配置場所にあたるVPCを作成することが必要です。

クラウドサービスを利用する場合、実物のサーバーを見ることはできないので、イメージがつきにくいと思います。 VPC関連の機能についてなるべく具体的な例を挙げて解説していきます。

VPCネットワーク関連の用語解説

VPC(Virtual Private Cloud)は、AWSのサービスを配置するためのネットワーク空間です。

現実世界で例えると、サーバーを置くための大きな部屋のイメージです。 サーバー(=EC2インスタンス)を使うために、それを配置するための部屋(=VPC)を定義してあげます。

VPCは、CIDR形式のプライベートIPアドレスで定義します。例えばIPv4で100.0.0.0/24とした場合、 100.0.0.1〜100.0.0.254の最大254個のIPアドレスをEC2インスタンスなどに割り当てることができます。

サブネット

VPCの中にはさらにサブネット空間を定義することができます。 サーバーを冗長化する場合など、用途によってサブネットを分けたりします。

現実世界に例えると、広い部屋(=VPC)の中に仕切り(=サブネット)を立てて、会議用スペースや休憩用スペースなど用途によって空間を分けるようなイメージです。

VPCで定義した空間よりも広いサブネットを定義することはできません。 例えばVPCが100.0.0.0/24の場合、100.0.0.0/26(100.0.0.1〜100.0.0.63)や100.0.0.0/27(100.0.0.1〜100.0.0.31)といった空間にしなければなりません。

ルートテーブル

VPCを作成すると、自動的にルートテーブルが作成されます。IPアドレスとVPCの対応づけがされています。 その他、インターネット空間への接続設定などもできます(後述)。

現実世界で例えると、部屋の使用ルールのようなものです。 プロジェクターを使いたくて会議室に来た人向けに、その使い方を提示する。 個別面談を行う場合に、鍵をかけるようにする。といった部屋に関わる取り決めを設定するイメージです。

ネットワークACL

VPCを作成すると、自動的にネットワークACLも設定されます。 ネットワークACL(Access Control List)は、VPCを出入りする通信を制御するためのものです。

そのVPCに入ってくる通信を制御するのがインバウンドルール、 そのVPCから出る通信を制御するのがアウトバウンドルールです。 通信プロトコル、ポート番号、送信元(インバウンドルール)、送信先(アウトバウンドルールの場合)などを条件として 通信を許可または遮断することができます。

現実世界に例えると、部屋に出入りするためのセキュリティーカードの仕組みのようなものです。入室や退室を許可された人(=通信)のみがその部屋(=VPC)を利用することができます。

セキュリティグループ

VPCを作成すると、自動的にセキュリティグループも設定されます。 ネットワークACLと似ていますが、こちらはEC2インスタンスにも設定できる通信制御機能です。 TCPやSSHなどのプロトコル、ポート番号ごとに通信の許可・遮断の設定をすることができます。

現実世界に例えると、レストランの食券のようなものです。レストラン(=EC2インスタンス)で利用可能な食券(=セキュリティグループ)を持っている人(=通信)だけがそのお店を利用できるようなイメージです。

インターネットゲートウェイ

VPCは、何もしなければ外に閉じた空間です。外部からアクセスすることはできません。インターネットゲートウェイは、その名の通り外部からVPC内へアクセスするための玄関口です。 VPCにインターネットゲートウェイをアタッチすることで、そのVPCは外部(例えばローカルPC)からアクセスできるようになります。

現実世界に例えると、家の玄関やビルのエントランスのようなものですね。これがあることでお客さんが入る(=外部からのアクセス)ことが可能になります。

VPCのセッティングをする

上記を踏まえて、まずはEC2インスタンスを配置するためのVPCのセッティングを行います。 ローカルからSSH接続したいので、インターネットゲートウェイをアタッチし、さらにSSHの22番ポートを通過できるようにします。

  • VPCとサブネットを作成
  • セキュリティグループを作成(SSH接続を許可する)
  • インターネットゲートウェイを作成(VPCにアタッチ)

VPCとサブネットを作成

まずはVPCとサブネットの作成を行います。VPCのアドレス空間をCIDR形式のIPアドレスで設定します。 画像では100.0.0.0/24(100.0.0.1〜100.0.0.254に割当て可能)としています。

fig11

VPCが作成できたら、続けてサブネットを作成します。先ほど設定したVPCのアドレス空間より狭い範囲に設定する必要があります。 画像では100.0.0.0/28(100.0.0.1〜100.0.0.14に割当て可能)としています。

fig12

セキュリティグループを作成(SSH接続を許可する)

VPCを作成すると自動でデフォルトのセキュリティグループが作成されます。 このデフォルトセキュリティグループを使うこともできますが、 個別のインスタンスごとに設定したい場合を考慮して、EC2インスタンス用のセキュリティグループを作成することもできます。

fig13

EC2にアタッチする予定のセキュリティグループのインバウンドにSSHのポート番号22を追加します。 インバウンドルールの「タイプ」を「SSH」、「ソース」に「0.0.0.0/0」を設定することで、 任意の端末からSSHで接続することができるようになります。

インターネットゲートウェイを作成(VPCにアタッチ)

VPCとインターネット間を繋ぐためのインターネットゲートウェイを作成します。

fig14

インターネットゲートウェイ(以下IGW)が作成できたら、VPCのルートテーブルにアタッチします。 なお、1つのインターネットゲートウェイは、複数のVPCにアタッチすることはできません。

インターネットゲートウェイ一覧からアタッチしたいIGWを選択し、右上「アクション」から「VPCにアタッチ」を選択します。

fig15

さらに、ルートテーブル一覧の「ルートを編集」から、IGWからの送信先として任意の場所へアクセスを許可します。
送信先に「0.0.0.0/0」、ターゲットに作成したIGWを設定します。

fig16

VPCの設定ができたので、この中にEC2インスタンスを作成します。

EC2インスタンスを起動する

OSの選択

OSは長期サポートされるAmazonLinux2を選択します。利用するコマンドだったりREHL、CentOSに近いですが別物のようです。

fig1

スペックの選択

EC2インスタンスのスペックを選択します。テストで作るならt2.microで十分です。AWSの1年間無料枠で試すならなおのこと無料枠対象のこちらを選択します。 ts.nanoもよさそうですが、筆者が試した時はNode.jsが重くて立ち上がらないことがありました。

fig2

インスタンスの詳細設定(VPCとサブネットの選択)

ネットワークのところで、あらかじめ作成したおいたVPCとサブネットを選択します。

また、ローカルからEC2に直接ログインするため、インスタンス起動時にIPが割り当てられる「自動割り当てパブリックIP」を「有効」にします。 最低限必要な設定は以上なので、他はデフォルトのままでも大丈夫です。

fig3

今回はEC2にパブリックIPを自動的に割り当てる設定としますが、ElasticIPと呼ばれる固定パブリックIPを別途発行し、そのIPをインスタンスに紐づけることも可能です。 また、パブリックIPを直接割り当てずに、VPC内に別途踏み台サーバーなどを置きそこからプライベートIPを利用して接続する方法もあります。

ストレージの追加

試しに作成する場合、特に追加の設定は不要です。

タグの追加

特に設定は不要です。

セキュリティグループの選択

VPCを作成すると自動で作成されたものでも構いませんし、個別に設定したい場合は別途作成したセキュリティグループを選択します。

fig6

確認

設定を確認し、問題なければ「起動」を選択します。

キーペアの設定またはダウンロード

ポップアップが表示され、EC2インスタンスに接続するためのキーペアの選択を聞かれます。 まだAWS用のキーペアを持っていない場合は、「新しいキーペアの作成」から作成しダウンロードします。 ここで作成したキーペアがダウンロードできるのは一度きりですので、無くさないように保管します。

fig8

インスタンス作成完了

fig9

インスタンスが作成されました。しばらくしてからダッシュボードを見るとステータスが「実行中」になります。

EC2インスタンスにSSH接続する

起動中のインスタンスを選択して右上の「接続」を選択すると、接続方法などが記載された画面が表示されます。

「EC2 Instance Connect」から、ブラウザ上でログインすることもできます。

fig17

ローカルPCからターミナルなどでログインする場合は「SSHクライアント」を参考に接続します。

console
ssh -i amazonaws-ssh-key.pem ec2-user@123.45.6.xxx

NginxとExpressの起動

Node.jsのインストール

AmazonLinuxでNode.jsを利用する場合、直接Node.jsをインストールする方法と、nvmでインストールする方法があります。

直接インストール

直接Node.jsをインストールする場合は、以下のコマンドからインストールできます。

console(ec2-user)
sudo yum install -y gcc-c++ make

curl -sL https://rpm.nodesource.com/setup_16.x | sudo -E bash - 

sudo yum install -y nodejs
How To Install Latest Nodejs on Amazon Linux

2022年2月現在のNode.js最新バージョンは17.xですが、互換性を考慮する場合は16.xの方が良さそうです。

nvmによるインストール

nvmを利用してNode.jsをインストールすると、バージョンの切替えを容易にすることができます。

console
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.34.0/install.sh | bash

. ~/.nvm/nvm.sh

nvm install 16
> Downloading and installing node v16.14.0...
> Downloading https://nodejs.org/dist/v16.14.0/node-v16.14.0-linux-x64.tar.xz...
> ####################################################################################### 100.0%
> Computing checksum with sha256sum
> Checksums matched!
> Now using node v16.14.0 (npm v8.3.1)
Setting Up Node.js on an Amazon EC2 Instance

Expressアプリケーションの起動

アプリケーションはnodeコマンドで実行すれば起動できますが、EC2インスタンスとの接続を切ると落ちてしまいます。

console(ec2-user)
node index.js

恒常的に起動し続けるために、npmのpm2パッケージをグローバルにインストールします。

console(ec2-user)
npm i -g pm2
pm2 start index.js

これで、EC2への接続を閉じてもアプリケーションを起動し続けることができます。

Nginxのインストールと起動

AmazonレポジトリにあるNginxを利用します。

console(ec2-user)
amazon-linux-extras list | grep nginx
amazon-linux-extras enable nginx1

nginxを有効化することで、yumコマンドを使ってインストールすることができるようになります。

console(ec2-user)
yum install -y nginx

Nginxはnginxコマンドで起動できます。

console(ec2-user)
sudo nginx //起動する
sudo nginx -s reload //再起動する 

psコマンドでプロセスを確認することで、nginxが起動していることを確認できます。

console(ec2-user)
ps aux | grep nginx

> root      3569  0.0  0.6  50460  6692 ?        Ss   01:48   0:00 nginx: master process nginx
> nginx     4937  0.0  0.6  50908  6252 ?        S    02:33   0:00 nginx: worker process
> ec2-user  5491  0.0  0.0 119432   984 pts/3    S+   03:27   0:00 grep --color=auto nginx

Expressホスティング

EC2のローカルホスト5555番ポートで起動しているNode.jsアプリケーションへの転送設定を行います。

/etc/nginx/nginx.conf
server {
    ...
    http {
      ...
      location / {
              proxy_pass http://localhost:5555;
      }
    }
  } 

Lets'EncryptでSSL/TLS対応(おまけ)

HTTPSでの接続に対応するためには、TLS証明書の発行が必要ですが、やや手間がかかります。 そこで、Let's EncryptでTLS証明書を発行します。無料ですが、有効期間は90日ですので定期的に更新する必要があるのですが、 certbotというツールを使うことで簡単に取得・更新ができます。

Amazon Linux 2 での Let's Encrypt と Certbot の使用

console(ec2-user)
sudo yum install -y certbot python2-certbot-apache
sudo certbot --nginx -d example.com

certbotを実行し、質問に答えていくと証明書の発行が完了し、自動的にnginx.confの設定が追加されます。

/etc/nginx/nginx.conf
server {
    ...
    listen 443 ssl; # managed by Certbot

    # RSA certificate
    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem; # managed by Certbot

    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
}

定期的に更新するために、クーロンを設定しておきましょう。

.crontab
59 23 1 */3 * /usr/bin/certbot renew --quiet

Using Free Let's Encrypt SSL/TLS Certificates with NGINX