Amazon Linuxで入手できるnginxをHTTP/2に対応させてみた

PPW_kiiroikabetonankinjyou_TP_V.jpg

このサイトはMovable Typeを用いて構築しているのですが、Amazon Web Services内のEC2環境に移行する予定です。このサイトでは、実験も兼ねてHTTP/2を有効にしているのですが、EC2で標準配布されているパッケージではHTTP/2に対応していないため、再度ビルドを行い、動かすことに成功した手順の記録。

HTTP/2に無理やり対応しなくてもよいのでは?

この記事を読まれている方は『面倒なことをせずにyumで取得したい』と思われているかもしれません。現状では、無理に対応する必要はないと私も考えています。

HTTP/2をサポートしたWebブラウザの普及に伴い、今日ではHTTP/2を利用しているWebサイトも増えている。たとえばGoogleやFacebookなどは全面的にHTTP/2を有効にしているほか、Twitterなども一部でHTTP/2を利用している。とはいえ、現時点ではHTTP/2の導入が必須、というわけではない。Webアプリケーションなど動的にコンテンツを生成するようなWebサイトでは、アプリケーション側での対応なども必要となるため、HTTP/2が導入しにくいケースもある。Linuxディストリビューションでのサポートもまだ十分でない。

HTTP/2を実際に使用するためのサーバー設定 - さくらのナレッジより

レンタルサーバーやホスティングサービスでは知っている方も多い、さくらインターネットが運営しているさくらのナレッジより引用しましたが、アプリケーション側での対応やLinuxディストリビューションでのサポートも十分ではないことから、対応させることは必要条件ではありません。

しかし、このサイトでは私自信の勉強や「最先端の技術で使えるのであれば使ってみたい」という好奇心もあり、有効にしています。

現状の問題点

今回、サーバーを変更するのには以下のような理由が挙げられます。

  1. サーバーのpingが落ちることが多い(監視サービスからサーバは落ちてないが、ダウンしていると通知が週に1〜2回、下手したら1日に1回来ることもあった)
  2. Movable Typeのデーモンがたまに再起動できなくなる(supervisordの設定などがうまくできていないか、スクリプトがうまく行っていない。プロセス自体は落ちていないので、supervisordの問題かも)
  3. EC2でReserved契約をしているのもかかわらず、放置している(色々あって腰が重たかった…)

3つ目の理由は私自信があと送りにしすぎ…ということもありますが、その他の理由はサーバーの乗り換えやMovable Typeの開発をしているSix Apartが提供しているMovable Type for AWS(AMI)を用いることで解決できると判断しました。

構築環境

今回の構築環境は以下のとおりです。

  • Movable Type for AWS(AMI)をベースに取得
    • OS: Amazon Linux
    • 基本的なソフトウェアはepelレポジトリとシステムに含まれているレポジトリから取得
    • Movable Typeに関してはSix Apartが提供しているレポジトリ
  • インスタンスタイプ: t2.micro

構築時の問題点

先に、私が普段行っている流れを示します。

  1. nginxの公式リポジトリからSRPMパッケージ(ソースコードを含んだパッケージ)を取得
  2. OpenSSLの最新バージョンをtar形式で取得
  3. OpenSSLのバージョンなどを記述したSPECファイル(パッケージを制作するための情報が記述されているファイル)を編集する
  4. 再度ビルド

当初は自前で…といいますか、調べていた時にnginx with OpenSSL 1.0.2 (ALPN) on CentOS 7と出会いまして、スクリプトで回していました。

しかし、このやり方ではMovable Typeパッケージにおいて、nginxのperl関連のモジュールを採用しているため、関連のパッケージがないと言われました。

そのため、Amazon Linuxが配布しているオリジナルのパッケージからソースコードを取得して実行することにしました。

実際にビルドしてみる

その前に、ビルドする環境を整えます。以下のサイトにざっくりと書いてありますが、色々とエラー吐き出されたので以下に示します。

参考: Amazon Linux でのソースの入手と再ビルド | dogmap.jp

rpmbuildをインストールする

パッケージを作成するために必要なrpmbuildをインストールします。

$ sudo yum -y install rpmdevtools
$ sudo adduser mockbuild
$ sudo su - mockbuild
$ mkdir $HOME/rpmbuild $HOME/rpmbuild/SOURCES $HOME/rpmbuild/SPECS $HOME/rpmbuild/BUILD $HOME/rpmbuild/SRPMS $HOME/rpmbuild/RPMS $HOME/rpmbuild/RPMS/x86_64
$ echo "%_topdir $HOME/rpmbuild" >> $HOME/.rpmmacros
$ echo "%debug_package %{nil}" >> $HOME/.rpmmacros

mockbuildというアカウントを追加していますが、パッケージ取得時にroot権限や標準のec2-user権限で実行した場合、「mockbuildユーザーとグループではないよ」という忠告が出たためです。

おそらく、Amazon側でパッケージを作成する時にmockbuildというユーザーとグループで行っているのでしょう。

その上で、 get_reference_sourceでパッケージを取得します。CentOSなどでは、yumdownloaderと呼ばれるものがあるなんて知らなかったです…(無知)

$ get_reference_source --package=nginx
$ rpm -ivh [File Path]

パッケージを取得すると、パッケージが保存された場所が表示されるので、それをコピーしておきます。コピーした保存場所は[File Path]になりますので、適宜読み替えてください。

次に、OpenSSLのパッケージを取得します。今回はシステムには手を加えず、nginx側のみで対応するため、rpmbuildフォルダ内にソースファイルを追加します。

$ cd ~/rpmbuild/SOURCE/
$ wget https://www.openssl.org/source/openssl-1.1.0f.tar.gz

その上で、SPECファイルを書き換えます。この記事では先述のスクリプトが非常に良くできているので、一部を変えた上で適応します。

cd ~/rpmbuild/SPECS/
sed -i "/Source12: .*/a Source20: https://www.openssl.org/source/openssl-1.1.0f.tar.gz" ./nginx.spec
sed -i "s|--with-http_ssl_module|--with-http_ssl_module --with-openssl=openssl-1.1.0f.tar.gz|g" ./nginx.spec
sed -i '/%setup -q/a tar zxf %{SOURCE20}' ./nginx.spec
sed -i '/.*Requires: openssl.*/d' ./nginx.spec
# hardening whatnots since 1.11.9
sed -i 's|%define WITH_LD_OPT .*|%define WITH_LD_OPT ""|g' ./nginx.spec
sed -i 's| -fPIC||g' ./nginx.spec

sedコマンドでファイルの場所とマッチしたところを置換しています。ちなみに、1行目と3行目は追加しているみたいです。

その後にrpmbuildするとパッケージが生成されます。

$ rpmbuild -ba nginx.spec

生成には時間がかかるため、その間にストレッチでもしておきましょう。

生成が終了すると、/home/mockbuild/rpmbuild/RPMS/x86_64/以下にrpmファイルが追加されています。

mockbuildユーザーからログアウトし、ec2-user内の適当なディレクトリにrpmファイルをコピーしてアプリケーションをインストールします。

Movable TypeのAMIを利用している場合はnginxが既にインストールしているため、一度アンインストールした後に再度インストールします。2017年6月21日現在では、データの削除などはありませんでした。

$ mkdir RPMS
$ sudo cp -r /home/mockbuild/rpmbuild/RPMS/x86_64 ./
$ sudo chown ec2-user:ec2-user -R ./x86_64
$ sudo yum remove nginx -y
$ cd x86_64
$ sudo yum install *
$ sudo yum install movabletype

nginxのインストールは終了しましたが、このままだと新しいバージョンが出るたびにyumでアップデートされてしまうため、レポジトリの情報が記述されているファイルに追記します。

以下のファイルを編集します。

$ sudo vi /etc/yum.repos.d/amzn-main.conf
# 最初のセクションの最終行に以下を追記
exclude=nginx*
$ sudo vi /etc/yum.repos.d/epel.conf
# 最初のセクションの最終行に以下を追記
exclude=nginx*

ファイルを保存したら作業は終了です。

あとがき

新しいバージョンが出るためにamzn-mainレポジトリも更新されると思いますので、そのあたりは各自で確認するなり、nginxのメーリングリストを購読して確認する必要があると思います。

また、Amazon Linuxは一定期間内で一度アップデートがあるため、そのあたりも常に追う必要があります。

今後、もしかしたらOpenSSLのバージョンなどがアップデートされると、この作業も必要ないかもしれません。