お名前ドットコムVPSへ移行への道9-設定ファイルを見てみる

※ 当サイトではアフィリエイト広告を利用しています。リンクは広告リンクも含みます。

この記事は約21分で読めます。
広告

お名前.com VPS でDockerを使用しmodsecurity-crs:nginx、WordPress、Djangoを動かしている。
ネットで調べると自分の環境と違ったり、断片的な情報を間違って理解することが多いので
改めて整理したほうがいいと思い。
Docker+modsecurity+Nginxの設定を個人的メモとしてまとました。
私が誤解していることもあると思いますのでご了承ください。

環境
パソコン Windows11
VPS OS Ubuntu 20.04.3 LTS、 
Docker image: owasp/modsecurity-crs:nginx

広告

Nginxの設定を見る

コンテナ(私の一連のお名前.comVpsシリーズの記事の場合waf-nginx)の中に入って
catで中身を確認して、解説はGeminiに聞いた。

nginx.conf

cat /etc/nginx/nginx.conf

load_module modules/ngx_http_modsecurity_module.so;

worker_processes auto;
pid /tmp/nginx.pid;

events {
    worker_connections 1024;
}

http {
    include /etc/nginx/mime.types;
    default_type application/octet-stream;
    keepalive_timeout 60s;
    sendfile on;

    resolver 127.0.0.11 valid=5s;
    include /etc/nginx/conf.d/*.conf;
}

1. モジュールロード

load_module modules/ngx_http_modsecurity_module.so;

この行は、Nginxにngx_http_modsecurity_module.soという動的モジュールを読み込むように指示します。このモジュールは、Webアプリケーションファイアウォール(WAF)であるModSecurityとの統合を提供し、Webサーバーをさまざまな攻撃から保護するのに役立ちます。

このモジュールは通常、Nginxインストールパスのmodulesディレクトリにあります(例:一部のシステムでは/etc/nginx/modules)。

2. ワーカプロセス

worker_processes auto;

この行は、Nginxが生成するワーカプロセスの数を設定します。ワーカプロセスは、受信したHTTPリクエストと接続を処理します。

値をautoに設定すると、Nginxはシステムのハードウェアリソース(通常はCPUコアの数)に基づいて、最適なワーカプロセスの数を自動的に決定します。

3. PIDファイル

pid /tmp/nginx.pid;

この行は、NginxがプロセスID(PID)ファイルを書き込む場所を指定します。PIDファイルには、Nginxマスタープロセスのユニーク識別子が含まれます。このファイルは、システムツールやスクリプトによってNginxを管理するために使用されることがよくあります。

この場合、PIDファイルは/tmp/nginx.pidに書き込まれます。

4. イベント

events {
  worker_connections 1024;
}

このブロックは、Nginxがネットワークイベント(受信接続とデータ)を処理する方法に関する設定を定義します。

このブロック内には1行あります。

worker_connections 1024;

この行は、各ワーカプロセスが処理できる同時接続の最大数を設定します。これを1024に設定すると、各ワーカーは最大1024の同時接続を処理できます。

5. HTTP

http {
  include /etc/nginx/mime.types;
  default_type application/octet-stream;
  keepalive_timeout 60s;
  sendfile on;
  resolver 127.0.0.11 valid=5s;
  include /etc/nginx/conf.d/*.conf;
}

このブロックは、NginxのHTTPサーバー機能に特化した設定を含みます。

  • include /etc/nginx/mime.types; – MIME(Multipurpose Internet Mail Extensions)タイプを定義するファイルをインクルードします。MIMEタイプはファイル拡張子をコンテンツタイプにマッピングし、ブラウザがWebコンテンツを正しくレンダリングするのに役立ちます。
  • default_type application/octet-stream; – 特定のタイプが定義されていないファイルのデフォルトMIMEタイプを設定します。application/octet-streamは、バイナリデータを示す汎用タイプです。
  • keepalive_timeout 60s; – Nginxがアイドル接続を開いたままにする時間を定義します。この設定により、同じクライアントからの後続のリクエストは60秒以内に既存の接続を再利用でき、パフォーマンスが向上します。
  • sendfile on; – Nginxがオペレーティングシステムのファイル転送メカニズムを活用して、ディスクからクライアントにファイルを効率的に転送できるようにする技術を有効にします。
  • resolver 127.0.0.11 valid=5s; – Nginxがホスト名を解決するために使用するDNSリゾルバーを定義します。ここでは127.0.0.11 (典型的な設定ではない可能性があります)に設定され、5秒の検証タイムアウトを指定します。
  • include /etc/nginx/conf.d/*.conf;/etc/nginx/conf.dディレクトリにある.conf拡張子を持つすべての設定ファイルをインクルードします。これらのファイルには、Nginxが特定のドメインやURL
プロセスとはプログラムで書いたコードが実際に仕事をしている実態という認識で私はいます。
ワーカプロセスを、このお名前.comVPSシリーズの最終形態で実際に動いているときに確認した。
ワーカプロセスの数(多分、子プロセスの数)はworker_processes auto;の設定で
CPUコアの数(2個)と同じになっているのかも。
NginxはWAFの入っているコンテナとWordPressの前のコンテナで2つ使っている。
なので2つの親プロセスと、それぞれに子プロセスが2つある。
systemctl status
   CGroup: /
           ├─379 bpfilter_umh
           ├─docker 
      略
           │ ├─7***Djangoのコンテナのプロセス***9 
           │ │ ├─1777778 bash
           │ │ ├─1777777 python manage.py runserver 0.0.0.0:8006
      略
           │ ├─15***WAFの入ってるNginxのコンテナ***82 
           │ │ ├─1777775 nginx: master process nginx -g daemon off;
           │ │ ├─1777755 nginx: worker process
           │ │ └─1777756 nginx: worker process
     略
           │ ├─51***WordPressのコンテナ***45 
           │ │ ├─1777732 php-fpm: master process (/usr/local/etc/php-fpm.conf)
           │ │ ├─1777709 php-fpm: pool www
           │ │ ├─1777756 php-fpm: pool www
           │ │ └─1777796 php-fpm: pool www
      略
           │ └─08***WordPressの前のNginxのコンテナ***61 
           │   ├─1777720 nginx: master process nginx -g daemon off;
           │   ├─1777701 nginx: worker process
           │   └─1777702 nginx: worker process
     
この各子プロセスが最大1024までのクライアントからのリクエストを
うまくあしらって後段のDjangoのプロセス
(python manage.py runserver 0.0.0.0:800*)とやりとりし
最後はクライアントにレスポンスを送っていると思われる。
ここのしくみはよくわかっていないので知りたいところです。
この辺を調べるとコネクションというキーワードがよく出てくるが、
worckerプロセス絡めた仕組みが知りたいです。
ソケットというのもよく見る。ソケットについては、
後でじっくり読ませていただきたいので見つけたものを貼っておきます。 
 https://envader.plus/article/27
 https://zenn.dev/ganariya/articles/socket-slide-illustration-go-implement
 https://qiita.com/Michinosuke/items/0778a5344bdf81488114
 https://qiita.com/lymansouka2017/items/2d2e78a37b9f1f8fb3a0
 https://qiita.com/MoriokaReimen/items/5c4256ef620499a88bb3
 https://www.youtube.com/watch?v=xbAFhCxgEQI
 ファイルディスクリプタとソケットの関連がわかる
 https://xtech.nikkei.com/it/article/COLUMN/20071031/285990/?rt=nocnt
この辺、いろんな話に脱線してしまって的が定まらないが、
いろいろ見ていくと的が絞れて来る。一つの情報源で決めつけるとなかなか解決しない。
特に最近は生成AIの答えは特に注意が必要だと思っています。

WAFのプロセスがコンテナの中に見当たらない。
モジュールという形で取り込まれているので、
多分、Nginxのワーカーの中に拡張機能みたいな形で入っていると推測する。

WordpressのほうはWordPressの処理の本体のphp-fpmのプロセスも
Nginxのプロセス同様に複数見られた。

1Gのメモリでいっぱい、いろんなことするのが目的で、
アクセス数も少ないので、この辺を調整してメモリ使用量を減らせる可能性もあるが
現段階ではデフォルトのままにした。

Nginxのworckerの話は、

Nginxのアーキテクチャを理解する - Qiita
Nginxのアーキテクチャについて調べてたことをまとめた。用語のおさらいプロセス(Process)プログラムの実行単位であり、CPU時間単位で割り振られる。状態(ステート)があり、現在処理中…
が参考になります。

こちら↓でもいろいろ実験しました。

よく使うところがincludeされている/etc/nginx/conf.d/*.confだと思われる。

cd /etc/nginx/conf.d/
ls
default.conf      default.conf.bak  jikken1.conf      logging.conf      modsecurity.conf

default.conf.bakはバックアップ、jikken1.confは自分で書いた設定なので
他の3つを見ていく。
目次へ

modsecurity.conf

cat modsecurity.conf

modsecurity on;
modsecurity_rules_file /etc/modsecurity.d/setup.conf;

modsecurity on;はmodsecurityをon/offできそうだが、
ここで変更して、この設定を反映させるのが大変で断念した。
dockerでupやrestartをするとデフォルト値で上書きされてしまってうまくいかなかった。
コンテナの中に入ってNginx単独で設定を更新させる方法だとうまくいくかもしれません。
systemctlを使う方法は私が使っているコンテナはalpineなので
確かデフォルトで入ってなかったような気がしたので断念しました。

docker-compose.ymlのenvironment:でOFFさせることもできるが。
offするのはWordPressを使うときが多かったのでルール追加でoffせずに使うことができた。

modsecurity_rules_file /etc/modsecurity.d/setup.conf;
はmodsecurityのルールを設定していると思われる。
cat /etc/modsecurity.d/setup.conf
# Note: the plugin rules will be uncommented when the container starts,
# depending on whether the respective files exist. This works around
# the issue that ModSecurity doesn't support optional includes on NGiNX.

# Allow custom rules to be specified in:
# /opt/modsecurity/rules/{before,after}-crs/*.conf

Include /etc/modsecurity.d/modsecurity.conf
Include /etc/modsecurity.d/modsecurity-override.conf

Include /etc/modsecurity.d/owasp-crs/crs-setup.conf

Include /etc/modsecurity.d/owasp-crs/plugins/*-config.conf
Include /etc/modsecurity.d/owasp-crs/plugins/*-before.conf

Include /etc/modsecurity.d/owasp-crs/rules/*.conf

Include /etc/modsecurity.d/owasp-crs/plugins/*-after.conf
こちらもこのファイルを変更したり、*.confをincludeさせて設定しようとしたが
dockerでupやrestartをすると上書きされてしまってうまくいかなかった。
なのでルール追加でやろうと思います。
目次へ

default.conf

cat default.conf

# Nginx configuration for both HTTP and SSL

server_tokens off;

map $http_upgrade $connection_upgrade {
    default upgrade;
    '' close;
}

server {
    listen 8080 default_server;

    server_name localhost;
略}

server {
    listen 8443 ssl;

    server_name localhost;
略}

後半はデバッグ用(ポート8080、8443)の設定のようなので省略。
1. Server Tokensの無効化

server_tokens off;

この行は、Nginxサーバーが送信するHTTPヘッダーからServerX-Powered-Byトークンを削除します。これらのトークンは、サーバーのバージョンやソフトウェアスタックに関する情報を公開します。攻撃者はこの情報を利用して、サーバーの脆弱性を特定し、攻撃を仕掛ける可能性があります。

2. HTTP Upgradeヘッダーの処理

map $http_upgrade $connection_upgrade {
  default upgrade;
  '' close;
}

このブロックは、Upgrade HTTPヘッダーに基づいて、接続を維持するか閉じるかを制御します。

  • default upgrade; – Upgradeヘッダーが存在する場合は、接続を維持します。
  • '' close; – Upgradeヘッダーが存在しない場合は、接続を閉じます。

この設定は、WebSocketsなどの新しいプロトコルをサポートする一方で、不要な接続を閉じ、リソースを節約するのに役立ちます。

目次へ

logging conf

cat logging.conf

# The "combined" log format is predefined
log_format main '$realip_remote_addr - $remote_user [$time_local] "$request" '
                '$status $body_bytes_sent "$http_referer" '
                '"$http_user_agent" "$http_x_forwarded_for"';

access_log /var/log/nginx/access.log main;
access_log /dev/null combined;

error_log /var/log/nginx/error.log warn;

1. ログフォーマットの定義

log_format main '$realip_remote_addr - $remote_user [$time_local] "$request" '
                 '$status $body_bytes_sent "$http_referer" '
                 '"$http_user_agent" "$http_x_forwarded_for"';
  • この行は、”main”という名前のログフォーマットを定義します。
  • このフォーマットは、各ログエントリに以下の情報を含みます:
    • $realip_remote_addr: クライアントのIPアドレス
    • $remote_user: リクエストを行ったユーザー名(認証されている場合)
    • $time_local: ローカル時間形式でのアクセス時間
    • $request: リクエストされたURLとHTTPメソッド
    • $status: HTTPステータスコード
    • $body_bytes_sent: クライアントに送信されたレスポンスボディのサイズ
    • $http_referer: リクエスト元ページのURL
    • $http_user_agent: クライアントのユーザーエージェント
    • $http_x_forwarded_for: クライアントのIPアドレス(プロキシ経由の場合)

2. アクセスログの設定

access_log /var/log/nginx/access.log main;
access_log /dev/null combined;
  • 最初の行は、/var/log/nginx/access.logファイルにアクセスログを記録し、そのログフォーマットを “main” に設定します。
  • 2行目は、デフォルトの “combined” ログフォーマットでのログ記録を無効化します (nullデバイスに送信)。

3. エラーログの設定

error_log /var/log/nginx/error.log warn;
  • この行は、/var/log/nginx/error.logファイルにエラーログを記録し、ログレベルを “warn” に設定します。このログレベルでは、警告レベル以上のエラーが記録されます。
access.logをホスト(SSH接続の場合Vsコードの左のツリー)にコピーし中身を見た。
sudo docker cp コンテナID:/var/log/nginx/access.log ./
ダウンロードしてサイズを見たら36kb

NGINX Access Logs and Error Logsにlogの使い方が書いてありそう。
ここ↓は分かりやすい。"combined" ログフォーマットについても書かれている。
 https://beyondjapan.com/blog/2024/02/nginx-access-log/
NGINX Access Logs and Error Logsを見ると
各serverのlocationにaccess_logやerror_logを記述するように書かれている。
デフォルトのままだとクライアントのアクセスログが何も入ってないので
locationに書くとクライアントのアクセスログが書かれるのかもしれない。
erroe.logも見ているものと違った。

しかし、
sudo docker logs コンテナID -f 2>/dev/null
で表示されるログやエラーと内容が全然違う。
また、docker logsで表示されるものは、どこからきているのか。
この辺は次項。
目次へ

Docker logs

どうやらdocker logsは上のNginxのログとは別物のようです。
参考:https://www.kagoya.jp/howto/cloud/container/dockerlog/
Dockerでは各コンテナのログが、
以下の場所にJSON形式※で保存されているようなので実際に見ました。
/var/lib/docker/containers/コンテナID/コンテナID-json.log

rootユーザーでないと見れないのでrootにして。
cd /var/lib/docker/containers
lsで見るとコンテナIDが64桁だった。
123456789012*************************************************099
これは
IMAGE ID … イメージが持つ固有のイメージ ID(64桁)
ショート ID (12桁)があるみたい。(64桁の最初の12桁と同じだった。)
docker psで表示されるのは12桁のほうみたいです。例123456789012

cd 123456789012*************************************************099
lsすると確かに
123456789012*************************************************099-json.log
がありました。
tail 123456789012*************************************************099-json.log
で最後の数行の中身を表示してみて、その中の1個がこれです。
私がログはどこにあるのだろうと探していたのはこれでした。
{"log":"123.456.7.89 - - [22/Mar/2024:14:11:38 +0900] \"GET / HTTP/1.0\" 200 274263 \"-\" \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36\" \"-\"\n","stream":"stdout","time":"2024-03-22T05:11:38.995785392Z"}

ファイルサイズを確認すると
du -ch ファイル名 | grep total$ | cut -f 1
9.0Mでした。
var/lib/dockerに移動して
du -ah containersを実行すると各コンテナの使用しているサイズが分かります。
コンテナIDがついているから、コンテナを削除すればlogも削除されると思います。

試しにwaf-nginxの-json.logをrmで消してみた。
どこかにアクセスして
sudo docker logs waf-nginx -f 2>/dev/nullをしても何も表示されない。
sudo docker logs waf-nginx -f 1>/dev/nullでは

error from daemon in stream: Error grabbing logs: open /var/lib/docker/containers/123456789012*************************************************099/123456789012*************************************************099-json.log: no such file or directory

touch 123456789012*************************************************099-json.log
で空のファイルを作った。
パーミッションを確認すると
-rw-r--r--
元からあるほかのファイルは
-rw-r-----
chmod 640 123*-json.logで同じにしておいた。
そのまま、アクセスしたりしてログに記録されるかみたがダメだった。
結局コンテナを削除してsudo docker compose up -dしたら復活した。

以下はファイルのサイズを0にできたが、上と同じでlogは増えない。
sudo truncate -s 0 /var/lib/docker/containers/xxxxx/yyyyy-json.log
参考:https://qiita.com/TachiTech/items/ae4f5da70cadc392516e

しかしsudo docker restart コンテナ名でリスタートしたらlogがでるようになった。
多分、ファイルを消すほうもrestartすればいいかも。

またログのフォーマットを変更したかったが分からなかった。
長くて見にくい場合はログの表示形式を変更すると見やすくなる。
方法→https://kikuichige.com/24890/#toc5
目次へ

所感

ログがどうなっているのか疑問だったがDocker独自のログがあることが分かってすっきりした。
設定を反映させたはずなのに反映されてないときは
書く場所が違うか、
docker compose upやrestartなどによるデフォルトで上書きされている場合が多いようです。
今回、まとめたことで、このように原因が少しわかった。
生成AI(Gemini)を使って解説文を書いたが、役に立つときもあれば
全く的外れな場合もあり、回答を信じて突き進むと、えらい遠回りになることを改めて認識した。
目次へ
イチゲをOFUSEで応援する(御質問でもOKです)Vプリカでのお支払いがおすすめです。
MENTAやってます(ichige)

コメント

タイトルとURLをコピーしました