こんにちは、GMOインターネット株式会社の斉藤です。
今回のnginxの小ネタのお話です。
目次
はじめに
nginxは非常に多く使われているWebサーバーの1つで、弊社のレンタルサーバやーVPSでも多く使われています。
私が関わっている案件で、「nginxのアクセスログから特定のクエリだけを除去したい」という要求がありました。クエリというのは、ここではURLに含まれるクエリ文字列のことです。
たとえば、このdeveloper.gmo.jpのサイトの右上にある検索フォームから「gmo」というワードで検索を行うと、URLは下記のようになります。
https://developers.gmo.jp/?s=gmo&action=Search
このs=golangの部分だけをアクセスログから除去したいと言う要求です。
平たく言うとユーザーが入力した検索文字列などをログに残したくないという話でした、実際には以下のような要件になります。
- nginxのアクセスログのURLクエリ文字列から特定のキーを除去したい
- HTTPリファラのURLも同様にしたい
- 一時的であれストレージに記録はしたくない(なので一度記録されたログファイルに置換をかけるのは避けたい)
- nginxだけで完結したい
- s=hogehogeのキーの部分は残し値の部分だけ除去したい
2番目を少し補足すると、アクセスログではHTTPリファラーにもURLが入ることもあります。典型的なのは下記のようなWebサイトのアセットへのアクセスログです。
XXX.XXX.XXX.XXX - - [04/May/2021:18:00:00 +0900] "GET /js/index.js HTTP/1.1" 200 37194 "https://developers.gmo.jp/?s=gmo&action=Search" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.93 Safari/537.36"
さて、通常こういった要件ではPOSTリクエストを使うのが一般的です。ただ、今回の案件は既存のシステムへの改修でしたので、リクエスト方法変更という大きな変更ができなかったのです。
前提
nginxのログ出力形式はngx_http_log_moduleのlog_formatディレクティブで設定できます。
出力自体はaccess_logディレクティブで行います。
log_formatのデフォルトは以下のようになっています。
log_format compression '$remote_addr - $remote_user [$time_local] '
'"$request" $status $bytes_sent '
'"$http_referer" "$http_user_agent" "$gzip_ratio"';
access_log /spool/logs/nginx-access.log compression buffer=32k;
変数が使えるのでこれで実現できそうです。$request と $http_referer ですね。これらの変数はnginxによってプリセットされるので、これを置換してURLクエリの該当部分を変更すれば良さそうです。そして、このlog_formatディレクティブはhttpコンテクストの中にしか書けません。access_logはhttp, server, locationの3つのコンテクストの中に書くことができます。
これを踏まえて、以下方針を決めました。
- $requestのURLクエリ文字列から特定のキー除外した変数$filtered_requestを用意
- $http_refererののURLクエリ文字列から特定のキー除外した変数$filtered_refererを用意
- 独自のlog_formatを定義
- access_logに上記log_formatを指定してログを出力する
設定方法
変数の用意
まず変数の用意です。
オリジナルの変数に対して正規表現置換を行って、URLクエリ文字列から特定キーを除去します。ただ、今回は完全に空文字にするのでは無く[FILTERED]という文字列に置き換えることにしました。この方が意図的に除去されたことがわかるので良いでしょう。
これはserverコンテクストの中で設定します。以下は例です。
server {
listen 443 ssl default_server;
(snip...)
set $filtered_request $request;
if ($filtered_request ~ (.*)q=[^&]*(.*)) {
set $filtered_request $1q=[FILTERED]$2;
}
set $filtered_referer $http_referer;
if ($filtered_referer ~ (.*)q=[^&]*(.*)) {
set $filtered_referer $1q=[FILTERED]$2;
}
これで$filtered_requestと$filtered_refererと言う2つの変数がセットされます。
log_formatの定義
次に、httpコンテクストの中でlog_formatを定義します。
http {
##
# Basic Settings
##
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
include /etc/nginx/mime.types;
default_type application/octet-stream;
(snip...)
log_format myformat '$http_cf_connecting_ip - $remote_addr - $remote_user [$time_local] '
'"$filtered_request" $status $body_bytes_sent '
'"$filtered_referer" "$http_user_agent"';
ここで$requestを$filtered_request、$http_refererを$filtered_refererにそれぞれ変更します。log_foramtの最初の引数は、このフォーマットの名前です。
access_logディレクティブの定義
最後にserverコンテクストに戻ってaccess_logディレクティブを定義します。access_logディレクティブは第二引数にログフォーマットの名前を渡すことができるので、ここに先ほど作成したフォーマットの名前を渡します。
access_log /dev/stdout myformat;
error_log /dev/stderr;
上で設定は完了です。nginxをリロードして設定を反映させましょう。すると、ログには以下のように記録されているはずです。
XXX.XXX.XXX.XXX - - [04/May/2021:18:00:00 +0900] "GET /?s=[FILTERED]&action=Search" 200 1335 "" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.93 Safari/537.36"
おわりに
今回は特定のURLパラメータをログに出力しない設定をしましたが、同様のやり方でログへの出力を柔軟に変更できるでしょう。何かのお役に立ったならうれしく思います。
それではまた次回お目にかかりましょう。
ブログの著者欄
採用情報
関連記事
KEYWORD
CATEGORY
-
技術情報(419)
-
イベント(156)
-
カルチャー(35)
-
デザイン(17)
TAG
- 5G
- Adam byGMO
- AI
- AWX
- BIT VALLEY
- blockchain
- ChatGPT
- cloudnative
- CloudStack
- CM
- CNDO
- CNDT
- CODEGYM Academy
- ConoHa
- CS
- CSS
- CTF
- DC
- Designship
- DevSecOpsThon
- Docker
- DTF
- GitLab
- GMO Developers Day
- GMO Developers Night
- GMO GPUクラウド
- GMO Hacking Night
- GMO kitaQ
- GMO SONIC
- GMOアドパートナーズ
- GMOアドマーケティング
- GMOイエラエ
- GMOグローバルサイン
- GMOデジキッズ
- GMOペイメントゲートウェイ
- GMOペパボ
- GMOリサーチ
- Go
- GTB
- Hardning
- Harvester
- HCI
- iOS
- IoT
- ISUCON
- JapanDrone
- Java
- JJUG
- K8s
- Kids VALLEY
- LLM
- MetaMask
- MySQL
- NFT
- NVIDIA
- OpenStack
- Perl
- PHP
- PHPcon
- PHPerKaigi
- QUIC
- Rancher
- RPA
- Ruby
- Selenium
- splunk
- SRE
- SSL
- Terraform
- TLS
- TypeScript
- UI/UX
- VLAN
- VS Code
- インターンシップ
- オブジェクト指向
- オンボーディング
- お名前.com
- カルチャー
- コンテナ
- スクラム
- スペシャリスト
- ソフトウェアテスト
- チームビルディング
- ドローン
- ネットワーク
- プログラミング教育
- ブロックチェーン
- ゆめみらいワーク
- リモートワーク
- 基礎
- 多拠点開発
- 大学授業
- 宮崎オフィス
- 応用
- 技育プロジェクト
- 新卒
- 暗号
- 機械学習
- 決済
PICKUP