パッケージごとのnginxのsignatureについて

# 概要

nginxは1.9.11以降のバージョンから動的モジュールを使えるようになりました。ただし、外部モジュールのバイナリとnginxのバイナリのsignatureが同一でないと動かない[^1]という制約があり、それは現在まで続いています。

バージョン1.11.5から`./configure`時に`--with-compat`オプションがサポートされ、このオプションを有効にすればnginx公式で配布しているnginxを使う環境では困らなくなりました。ただし、公式以外のEPELやUbuntuの標準レポジトリなどが配布しているnginxバイナリでは必ずしもそうとも言えず、各自でバイナリや`nginx -V`を解析した上で、適切なconfigureオプションを選択し、ビルドする必要がある状況は続いています。

単純に考えて、**動的モジュールを使用する場合にはnginx公式のバイナリを使えよ（あるいは、自分でnginxごとビルドしよう）**、というのが最適解になるとは思うのですが、要件次第で他のバイナリを使う必要が出てくる場合があります。

ここでは、nginx公式以外のnginxバイナリのsignatureがどのようになっているのかをまとめると共に、簡単にはなりますが、どういったオプションを付ければ良いのかについても記してみたいと思います。

## 本記事を読む前に

本記事を書くにあたっては、ハートビーツさんのブログ記事が大変勉強になりました。あらかじめ読んでおくとスムーズだと思います。

- [nginx-1.9.11で動的モジュールをサポート - インフラエンジニアway - Powered by HEARTBEATS](https://heartbeats.jp/hbblog/2016/02/nginx-dynamic-modules.html)
- [nginxの動的モジュールの最新状況（2017年2月版） - インフラエンジニアway - Powered by HEARTBEATS](https://heartbeats.jp/hbblog/2017/02/nginx-dynamic-modules-201702.html)

# signatureの調べ方

上記ハートビーツさんの記事中にもありますが、以下のコマンドで調べることが可能です。

```bash
$ strings /usr/sbin/nginx | grep '^.,.,.,'
```

nginxのバイナリの場所は、環境によって異なる場合があります。特にOpenRestyなど、公式外のバイナリは異なる場合が多いでしょう（`/usr/local/openresty/nginx/sbin/nginx`とか）。

# 各バイナリのsignature一覧

- 本項の内容は、適宜追加・更新をする場合があります。

## Amazon Linux 2環境

| パッケージ（ファイル名・パッケージ名） | レポジトリ・配布元 | signature | 備考・説明 |
|-----------|-----------------------|-----------|----------|
| nginx-1.18.0-1.40.amzn1.x86_64.rpm | amzn-updates | 8,4,8,0010111111010111001110111111111110 | |

## Amazon Linux 2018環境（Amazon Linux 1 = CentOS 6互換)

| パッケージ（ファイル名・パッケージ名） | レポジトリ・配布元 | signature | 備考・説明 |
|-----------|-----------------------|-----------|----------|
| nginx-1.18.0-1.el6.ngx.x86_64.rpm | [nginx公式](https://nginx.org/) | 8,4,8,0011111111010011001111111111111111 | |

## CentOS Linux release 7.7.1908 (Core) 環境

| パッケージ（ファイル名・パッケージ名） | レポジトリ・配布元 | signature | 備考・説明 |
|-----------|-----------------------|-----------|----------|
| nginx-1.16.1-1.el7.ngx.x86_64.rpm | [nginx公式](https://nginx.org/) | 8,4,8,0011111111010111001111111111111111 | |
| nginx-1.16.1-1.el7.x86_64.rpm | [epel](https://fedoraproject.org/wiki/EPEL/ja) | 8,4,8,0010111111010111001110111111111110 | |
| openresty-1.15.8.2-6.el7.x86_64.rpm | [openresty](https://openresty.org/en/) | 8,4,8,0000111111010111001111111111111110 | |
| kong-2.0.1.el7.amd64.rpm | [kong](https://konghq.com/) | 8,4,8,0000111111010111001110111111110110 | Kongに含まれるnginxはOpenResty。バージョンも1.15.8.2。 |

## Ubuntu 18.04.4 LTS (Bionic Beaver) 環境

| パッケージ（ファイル名・パッケージ名） | レポジトリ・配布元 | signature | 備考・説明 |
|-----------|-----------------------|-----------|----------|
| 1.16.1-1~bionic   | [nginx公式](https://nginx.org/) | 8,4,8,0011111111010111001111111111111111 | |
| 1.14.0-0ubuntu1.7 | [ubuntu公式](https://ubuntu.com/) | 8,4,8,0000111111010111001111111111111110 | |

## Windows版

| パッケージ（ファイル名・パッケージ名） | レポジトリ・配布元 | signature | 備考・説明 |
|-----------|-----------------------|-----------|----------|
| nginx-1.16.1.zip   | [nginx公式](https://nginx.org/) | 4,4,4,0100000111010001000100111111111110 | |

## Mac OS版

| パッケージ（ファイル名・パッケージ名） | レポジトリ・配布元 | signature | 備考・説明 |
|-----------|-----------------------|-----------|----------|
| nginx: stable 1.19.2 (bottled), HEAD   | homebrew | 8,4,8,1011000111010111001101111111111111 | |

# 目的のsignatureに合わせるためのconfigureオプション

動的モジュールをビルドする手順は、nginxのソースのディレクトリで以下のコマンドを実施します。なお、この際、ビルドに必要なパッケージはインストールされているものとします。

```bash
$ ./configure --add-dynamic-module=<動的モジュールのソースのパスを指定>
$ make modules
```

この後、同じディレクトリ内の`objs`ディレクトリ以下に、`ngx_????.so`ファイルができるので、適当な場所に移動させてnginxに読み込ませることになります。

なにも考えない場合、configure実行時のオプションはOSの設定やインストールされているライブラリなどによって自動的に決定されます。nginxバイナリと動的モジュールのsignatureを合わせるというのは、この際のconfigureのオプションを調べたうえで合わせる必要があるわけです。

ちなみに、私の手元環境で、上記のコマンドでなにもオプションを付けずにビルドした場合、動的モジュールのsignatureは以下のようになりました。ちょっと長い文字列ですが、ページ内検索をかけてみても上記のどのsignatureとも異なることがわかります。この場合、上記のどのnginxバイナリと組み合わせても動作しない、なんとも無用な動的モジュールのバイナリができあがることになります。

```
8,4,8,0000111111010111001110101111000110
```

nginxに限らず、一般的にconfigureオプションは、`$ ./configure --help`コマンドである程度把握することが出来ます。ハートビーツさんのブログに記載の通り、signatureの数字の羅列はどういったオプションでビルドされたかのフラグになっており、どういったオプションが有効・無効かはここから把握することが可能です。

あとは、その設定状況に従ってconfigureオプションを指定しましょう。ただし、ここで直接指定しにくいオプションもあり、そう言った場合は`--with-cc-opt`で追加したりすることになります。

たとえば、`kong-2.0.1.el7.amd64.rpm`に含まれるnginxバイナリのsignatureに合わせるオプションは以下のようになります。

```bash
$ ./configure --add-dynamic-module=<動的モジュールのソースのパスを指定してね> \
  --with-http_realip_module \
  --with-http_ssl_module \
  --with-cc-opt='-DNGX_HTTP_HEADERS'
```

## もっと簡単な方法（2020-09-20追記）

nginxコマンド実行時に`-V`オプションを付けると、そのnginxがコンパイルされた時のオプションが表示されます。長くて右の方にはみ出てしまいますが、そのまま貼り付けてみましょう（MacでHomebrewによってインストールされたnginxで試しています）。

```bash
$ nginx -V
nginx version: nginx/1.19.2
built by clang 11.0.3 (clang-1103.0.32.62)
built with OpenSSL 1.1.1g  21 Apr 2020
TLS SNI support enabled
configure arguments: --prefix=/usr/local/Cellar/nginx/1.19.2 --sbin-path=/usr/local/Cellar/nginx/1.19.2/bin/nginx --with-cc-opt='-I/usr/local/opt/pcre/include -I/usr/local/opt/openssl@1.1/include' --with-ld-opt='-L/usr/local/opt/pcre/lib -L/usr/local/opt/openssl@1.1/lib' --conf-path=/usr/local/etc/nginx/nginx.conf --pid-path=/usr/local/var/run/nginx.pid --lock-path=/usr/local/var/run/nginx.lock --http-client-body-temp-path=/usr/local/var/run/nginx/client_body_temp --http-proxy-temp-path=/usr/local/var/run/nginx/proxy_temp --http-fastcgi-temp-path=/usr/local/var/run/nginx/fastcgi_temp --http-uwsgi-temp-path=/usr/local/var/run/nginx/uwsgi_temp --http-scgi-temp-path=/usr/local/var/run/nginx/scgi_temp --http-log-path=/usr/local/var/log/nginx/access.log --error-log-path=/usr/local/var/log/nginx/error.log --with-compat --with-debug --with-http_addition_module --with-http_auth_request_module --with-http_dav_module --with-http_degradation_module --with-http_flv_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_mp4_module --with-http_random_index_module --with-http_realip_module --with-http_secure_link_module --with-http_slice_module --with-http_ssl_module --with-http_stub_status_module --with-http_sub_module --with-http_v2_module --with-ipv6 --with-mail --with-mail_ssl_module --with-pcre --with-pcre-jit --with-stream --with-stream_realip_module --with-stream_ssl_module --with-stream_ssl_preread_module
```

`configure arguments: `より後ろをコピペして、`./configure`を実行すれば、ほぼ間違いなく合致する外部モジュールをコンパイルすることができるはずです。

シェルスクリプトで取得しようと思ったらこうなるでしょうか。`nginx -V`で表示される内容は、標準出力ではなく標準エラー出力に出力されるため、その点の考慮が必要です。

```bash
$ nginx -V 2>&1 > /dev/null | grep -E "^configure " | sed -E "s/^.+: //"
```

変数を使ったりすれば、こういう風にできますね。

```bash
$ NGINX_OPTION=$(nginx -V 2>&1 > /dev/null | grep -E "^configure " | sed -E "s/^.+: //")
$ ./configure --add-dynamic-module=<動的モジュールのソースのパスを指定してね> $NGINX_OPTION
```


あとは、`make modules`後、適切にファイルを配置して、nginxのコンフィグに追記、`sudo nginx -t`などで文法チェックを行った後、`sudo nginx -s reload`などで、再読込を実施すれば完了です。

[^1]: 設定読み込み時（`# nginx -s reload`など）にエラーが出て起動しなくなります。