このサイトを構成するnginxについてのメモ。
自分用であるが、誰かの役に立つかも知れないので公開しておく。
Windows版のnginxをインストールする
nginx.orgから安定バージョンである「Stable version」のZIPファイルをダウンロードした。
下の画像はバージョン1.22.1のもの。
展開したフォルダを任意の場所に配置すればインストールは完了。
今回はCドライブ直下に配置した。
ここまでは非常に簡単である。素晴らしい。
なぜWindows版のnginxを使用するのか?
我が家では、サーバ類は(可能なものは)原則としてDocker for windowsを用いて仮想化している。
nginxについても当初はDockerで構築したが、以下の問題を解決できなかったっため、止む無くWindowsに直接構築した。
- nginxのログを出力する際の
$remote_addr
が取得できず、同一の値になってしまう。
かなり調べたが、これはDocker for windowsの構造的な問題らしいので諦めた。
※Linuxであればnetwork_mode: host
を使用する事で解決できそうに見えたが、試していない。
なお、Docker for windowsで上記を指定するとエラーになるだけである。
だったらもうWindows上にnginxを置いてしまえ、という単純な理由である。
構成について
本サイトはCMSとしてWordPressを使用して構築しているが、以前はgrowiを使用していた。
growiは仕事で使用していた事もあり、慣れているので採用したが、本来はCMSとして使用するようなアプリケーションではないため、サイトをSSL化する際にバックエンドをWordPressに切り替えたという経緯がある。
WordPress/growiは直接公開せず、リバースプロキシとして間にnginxを挟んでいる。
これは、以下の理由からである。
- nginxを用いてアクセス制御を行いたい。
- アクセスログについてはnginxのものを参照したい。(前述の通り)
構成としては、雑だが以下の通りとなる。
- インターネット → ルータ → 母艦PC(Windows) → nginx → WordPress/growi
ルータのポート変換で、80番ポート・443番ポートへのアクセスを母艦PCへ飛ばしている。
母艦PCはWindowsのため、WindowsDefenderファイアウォールで80番・443番の穴を開けている。
nginxからWordPress/growiへのアクセス制御は、nginx.conf
によって行う。
nginx.conf
/conf/nginx.confの一部についてメモしておく。
ログ出力定義
httpブロックの内部。
# ログ出力フォーマットは標準から変更していない
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
log_format
ディレクティブによって、mainという名のログ出力を定義している。
この定義は後ほど、access_log
ディレクティブにして使用する。ここではフォーマットの定義のみ。
なお、上記の通り ‘ ‘ で囲った文字列が複数行に渡る場合は結合してくれるようだ。つまり2-4行目は1つの定義と解釈される。
コメントの通り、ログ出力フォーマットは標準の形から変更していない。
設定値の意味についてはここやここを参照。
$remote_addr
:接続元のIPアドレス。
前述の通り、敢えてWindows版のnginxを使用しているのはここから接続元のIPアドレスを取得したいがためである。$remote_user
:Basic認証されたユーザ名。本サイトではBasic認証は使用していないので常に空。$time_local
:サーバのローカル時刻。何もフォーマットを変更しないとこんな感じで出る。見辛い。
例:23/Sep/2022:23:07:21 +0900$request
:リクエスト。
例:GET /wizfo/2022-08-12/ HTTP/1.1$status
:HTTPステータスコード。コード値はWikipediaを参照。
大体は200か301、400・403・404ばかりになる。
ほかは後で。
ログの出し分け
# ログ出力出し分けのための定義
geo $logging_addr {
192.168.11.11 0; # 自身からのアクセスはログを出力しない
192.168.11.7 0; # 自宅LANからのアクセスはログを出力しない
include ng_addr_0.conf; # NGリストにあるアドレスはログを出力しない
default 1; # 基本はログを出力する
}
geo $ng_addr {
192.168.11.11 0; # 自身からのアクセスはログを出力しない
192.168.11.7 0; # 自宅LANからのアクセスはログを出力しない
include ng_addr_1.conf; # NGリストにあるアドレスのみ出力する
default 0; # 基本はログを出力しない
}
ログ出力自体の制御を行うため、geoモジュールを用いて$logging_addr
と$ng_addr
を定義している。
なお、geoモジュールについてはここを参考にした。大変助かった。
後述するが、ログファイルは正規のアクセスと攻撃を思われるアクセスの2つに分割して出力している。上記の定義はその出し分けのためである。
まず3,4行目及び、9,10行目について。192.168.11.11
と192.168.11.7
からのアクセスの場合は0を返してログに出力しないようにしている。
これはコメントの通り、おれ自身による自宅からのアクセスログは出力したくないがためである。WordPressで記事を書く度に、ドバドバと膨大なログが出力されるのは堪らない。
include
しているng_addr_0.confとng_addr_1.confには、ログファイルから判断し、サイトに対して攻撃を仕掛けていると思われるIPアドレスをベタで指定している。ng_addr_0.confの内容は具体的には以下のようなもの。
100.20.156.138 0;
100.26.109.68 0;
103.133.111.120 0;
...
両者のファイルは本質的には同じものであり、0を返すか1を返すかしている。
(Pythonで簡単なスクリプトを書いて、60秒ごとに両者の同期を取るようにしている。)
もっと良さそうな方法がありそうなものだが、力技で解決した。
ZeroSSLでのサーバ証明書発行
サーバ証明書はZeroSSLを用いて発行している。
リンクだけで済んでしまった。