Apacheサーバーでnode.jsを動作させる(SSL対応)


私の話ですが「あるWebアプリケーションをApacheで稼働していてそのアプリケーションに対応したAPIを同じサーバー上にNode.jsで作りたい」ということがありました。
HTTPであればポートを指定したりリバースプロクシを設定したりすることで問題はないのですが、HTTPSの場合は通常ポート番号が443で固定です。HTTPSに限った話だとあまり記事がないと思い今回備忘録として残しておきます。

前提条件

・AWS EC2上でApacheが稼働中
・Apache / node.js / certbot(letsencrypt)がインストール済
・アプリのホスト名はexsample.comでAPIのホスト名はapi.example.comでDNS設定済
・HTTPSはec2のインスタンスで許可済

1.SSL対応
まずはexsample.comとapi.example.comのホストのバーチャルドメイン設定をします。

$ cd /etc/httpd/conf
$ vi httpd.conf
== (編集) ==
$ systemctl restart httpd

以下の記述を追加してください。その後にApacheを再起動します。

NameVirtualHost *:80
  <VirtualHost *:80>
    ServerAdmin [email protected]
    DocumentRoot /var/www/html/
    ServerName www.exsample.com
    ServerAlias exsample.com
  </VirtualHost>
  <VirtualHost *:80>
    ServerAdmin [email protected]
    DocumentRoot /var/www/html/
    ServerName api.exsample.com
    ServerAlias api.exsample.com
  </VirtualHost>

ブラウザでexsample.comとapi.exsample.comをアドレスバーに入れて確認します。(何もなければおそらくApacheのテストページが表示)アクセスできることが確認できたらSSL設定を行います。

$ certbot --apache -d exsample.com
$ certbot --apache -d api.exsample.com
$ systemctl restart httpd

いろいろな対話が発生しますがここでは省略します。ただし注意としてhttpsへの転送設定はceartbotのコマンドでは行わないでください。その方が確認するときに便利だからです。certbotについては詳しい記事がいろいろあります。時間があればリンクを貼っておきます。設定し終えたらhttps://付きで二つのホストのへアクセスをブラウザで確認しましょう。

2.Node.jsの起動
Node.jsを起動します。
https://qiita.com/someone-said-so/items/ed0aafee065efcbc3b57
にあるindex.jsを/home/ec2-user/api_sampleに作成します。

$ cd /home/ec2-user/api_sample
$ node index.js

これで3000番ポートでアクセスがあったときに{msg: 'hello express'}というjsonデータを返すAPIが稼働します。ひとまずhttp://api.exsample.com:3000でアクセスして確認しましょう。(1.でリダイレクトを指定しなかったのはこの確認をするため)

3.リバースプロクシの設定
準備が整ったので最終段階です。443番ポートでアクセスがあった場合のリバースプロクシを設定しましょう。

$ cd /etc/httpd/conf
$ vi httpd-le-ssl.conf
== (編集) ==
$ systemctl restart httpd

certbotでSSL設定をした場合、httpd-le-ssl.confというファイルが出来上がっているはずです。このファイルを編集します。###で囲まれている箇所を追記してください。Proxy関連の詳細設定が多いこと、パスをhttpで設定することがポイントです。(node.jsはhttpで待ち受けているため)

<IfModule mod_ssl.c>
  <VirtualHost *:443>
    ServerAdmin [email protected]
    DocumentRoot /var/www/html/
    ServerName www.exsample.com
    ServerAlias exsample.com
SSLCertificateFile /etc/letsencrypt/live/exsample.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/exsample.com/privkey.pem
Include /etc/letsencrypt/options-ssl-apache.conf
</VirtualHost>
</IfModule>
<IfModule mod_ssl.c>
<VirtualHost *:443>
    ServerAdmin [email protected]
    DocumentRoot /var/www/html/
    ServerName api.exsample.com
    ServerAlias api.exsample.com
SSLCertificateFile /etc/letsencrypt/live/api.exsample.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/api.exsample.com/privkey.pem
Include /etc/letsencrypt/options-ssl-apache.conf
    ###ここから追加###
    SSLEngine on
    SSLProxyVerify none
    SSLProxyCheckPeerCN off
    SSLProxyCheckPeerName off
    SSLProxyCheckPeerExpire off
    SSLProxyEngine on
    ProxyRequests off
    ProxyPass / http://api.exsample.com:3000/
    ProxyPassReverse / http://api.exsample.com:3000/
    ###ここまで###
</VirtualHost>
</IfModule>

これで設定は完了です。あとは
https://exsample.comでアクセスするとApacheのテストページ(そのまま)
https://api.exsample.comでアクセスするとjsonデータ
であることを確認します。

設定してみての感想ですが、リソースがあるなら別のサーバーを立てた方が手っ取り早いです。またEC2なら別のインスタンスでも追加すればよいでしょう。ですがリソースが限られている場合もありますし、DBがlocalhostからアクセスできた方がよいなどいろいろな制約があるかと思います。そのようなケースに役立ててもらえればと思います。