とーますメモ

Ruby on Rails / Goなどの学習メモ

【PHP-FPM】適切なプロセス設定について

色んなサイトを見て知ったことは、適切な設定を行うためにはまず以下のことを知る必要があるということ。

・使用可能なメモリ量
・PHPプロセスが確保している平均メモリ量

上記の内容を把握したのち、その内容をベースに以下の値を適切な値に設定する。

・pm.max_children
・pm.start_servers
・pm.min_spare_server
・pm.max_spare_server

ちなみに試した環境は2Gメモリ、1coreのUbuntu環境。
またphp-fpmのバージョンは7.2を利用。

1)使用可能なメモリ量の把握

単純に以下のコマンドを打ち

free -h

表示される「available」の箇所を見ればよい。
自分の場合、1.5Gと表示されていた。
※ free(239M) + buff/cache(1.4G) = 約1.5G

[参考]
Linuxのfreeコマンドの見方 – 日々、コレ勉強

使用可能メモリ量は1.5Gから、念の為10%(150MB)のバッファーを取って約1.35GBになったが
更に切りを良くするために最終的に1.3GBにする。

将来的に他のミドルウェアなどでメモリを消費する可能性がある場合は、予め大きなバッファを引いておく。

2)PHPプロセスが確保している平均メモリ量の把握

全てのfpmプロセスが確保したメモリ量は以下のコマンドで確認できる

$ ps -ylC php-fpm7.2 --sort:rss
||>

結果は以下
>||
S   UID   PID  PPID  C PRI  NI   RSS    SZ WCHAN  TTY          TIME CMD
S     0 16801     1  0  80   0 28804 115104 -     ?        00:00:00 php-fpm7.2
S    33 20281 16801  0  80   0 39456 117998 -     ?        00:00:00 php-fpm7.2
S    33 20284 16801  0  80   0 39548 117999 -     ?        00:00:00 php-fpm7.2
S    33 20285 16801  0  80   0 39568 117998 -     ?        00:00:00 php-fpm7.2
S    33 20242 16801  0  80   0 39620 118034 -     ?        00:00:01 php-fpm7.2
S    33 20277 16801  0  80   0 39632 117998 -     ?        00:00:00 php-fpm7.2
S    33 20141 16801  0  80   0 39720 118064 -     ?        00:00:01 php-fpm7.2
S    33 20139 16801  0  80   0 39728 118064 -     ?        00:00:01 php-fpm7.2
S    33 20120 16801  0  80   0 39908 118097 -     ?        00:00:02 php-fpm7.2
S    33 20117 16801  0  80   0 39936 118097 -     ?        00:00:02 php-fpm7.2
S    33 20114 16801  0  80   0 39952 118097 -     ?        00:00:02 php-fpm7.2
S    33 20118 16801  0  80   0 40032 118097 -     ?        00:00:02 php-fpm7.2
S    33 20278 16801  0  80   0 42800 118071 -     ?        00:00:00 php-fpm7.2
S    33 20140 16801  0  80   0 43020 118138 -     ?        00:00:01 php-fpm7.2

この平均を以下のコマンドで計算する

$ ps --no-headers -o "rss,cmd" -C php-fpm7.2 | awk '{ sum+=$1 } END { printf ("%d%s\n", sum/NR/1024,"M") }'

その結果プロセスの平均メモリ使用量が38MBとわかった。

[参考]
Adjusting child processes for PHP-FPM (Nginx) · GitHub

※ ちなみにPHPのmemory_limitを元に計算する方法もありかも。
これなら最大値で計算できる。
[参考]
[PHP] PHP-FPMのチューニングをするときに考えたことと行ったこと - Qiita

3)適切な設定値を計算

pm.max_childrenの値は上記で出した値を用いて、以下のように計算する。

pm.max_children = 使用可能メモリ量 / プロセスの平均メモリ使用量

pm.max_children = 1300MB / 38MB = 34.210526316 = 34

その他の項目は以下のサイトさんの指標に従うと・・・
Finding the correct pm.max_children settings for PHP-FPM - Chris Moore

pm.start_servers = [25% of max_children]
pm.min_spare_servers = [25% of max_children]
pm.max_spare_servers = [75% of max_children]

pm.start_servers = 34 × 0.25 = 8.5 = 8
pm.min_spare_servers = 34 × 0.25 = 8.5 = 8
pm.max_spare_servers = 34 × 0.75 = 25.5 = 25

結果以下の設定を行うに至った。
/etc/php/7.2/fpm/pool.d/www.conf

pm.max_children = 34
pm.start_servers = 8
pm.min_spare_servers = 8
pm.max_spare_servers = 25

※ちなみに以下の計算機も便利。
PHP-FPM Process Caluculator

4)ApacheBenchでどれぐらいまでのアクセスが許容可能かは把握

Macにはデフォルトで「ab」コマンドが入っているので試してみた。
thoames.hatenadiary.jp

例)100ユーザが同時に1リクエストを(合計100リクエスト)を行う負荷テスト

ab -n 100 -c 100 [テストするページのURL]

現在の環境に場合120以上のユーザが同時に1リクエストずつアクセスするとログにエラーが表示されたので、この辺がこのサーバのパフォーマンスということなのだろうか。

アクセスが増えてくるようならサーバ増強を行う必要があるだろう。

[その他参考]
nginxに変更したらメモリ不足なったので、php-fpmを設定を見直し | ex1-lab
[PHP] PHP-FPMのチューニングをするときに考えたことと行ったこと - Qiita

【ApacheBench】使い方メモ

テスト対象のサーバにもインストールできるが、
テスト時はテスト対象とは別のホストから負荷テストを行う。

abはApacheに同梱されてはいますが、性能テストを実行する際には、測定対象のサーバの外部にあるホストからリモートで実行します。ローカルから実行すると、ApacheBench自体の動作が、測定対象マシンのCPUやメモリの使用に影響するためです。

また、テスト対象のシステムに応じて、インターネット環境やLAN環境などを経由したリクエストを生成することで、より本番に近い形態でのネットワーク接続をシミュレートすることができるでしょう。

by 【初心者向け】ApacheBench入門 | Developers.IO

Ubuntuへのインストール

$ sudo apt-get install apache2-utils

基本的な使い方

nオプション: 生成するリクエスト数を指定します
cオプション: 並列実行する数(コネクション数)を指定します

例)10ユーザがそれぞれ10回リクエストした場合

$ ab -n 100 -c 10 http://example.com/

[結果の重要な項目]
Complete requests、Failed requests・・・完了したリクエストと失敗したリクエストの数
Requests per second・・・1秒間に処理したリクエスト数の平均値(ミリ秒)


[参考]
【初心者向け】ApacheBench入門 | Developers.IO
Apache Benchでサクッと性能テスト - Qiita

【Netdata】Ubuntu 18.04上にインストールした時のメモ

Netdata = リアルタイムリソース監視ツール

何が良いかって、リアルタイムの状況がわかるっていうことと
閾値や頻度を適宜設定できるアラート機能が便利。

Netdataの画面を開くとたくさんのセクションがあるが
大事なことはこのセクション毎の説明をしっかり読むこと。結構大事なことが書いてある。

インストール

お決まりのapt installでインストールできるようだったので
以下のページを参考に、インストールしたが、

https://www.howtoforge.com/tutorial/how-to-install-netdata-monitoring-tool-on-ubuntu/

プラグインファイルを編集するedit-configスクリプトが無く、web_logやfail2banなどのコレクター(?)が読み込まれていないようで
想定していた挙動と違う箇所が見受けられることから、最終的に公式と同じようにキックスタートでインストールする方法を使った。
Installation guide | Learn

$ bash <(curl -Ss https://my-netdata.io/kickstart.sh)

これだけで、netdataが起動し、「http://IPアドレス:19999」するだけで良い。

またデフォルトでいろんなコレクターなどの設定がされている。
元設定ファイルがある場所は「/usr/lib/netdata/conf.d」だが、このディレクトリ内のファイルは編集せずに、
「/etc/netdata」内に上書き用の同名ファイルを新規作成し、そこに上書きする。

例1)リソース状態が逼迫したときの通知を設定: health_alarm_notify.conf
cp /usr/lib/netdata/conf.d/health_alarm_notify.conf /etc/netdata/

例2)Fail2banの設定: fail2ban.conf
cp /usr/lib/netdata/conf.d/python.d/fail2ban.conf /etc/netdata/python.d/

※キックスタートスクリプト経由でインストールするとインストールパスが指定できないとのこと。
CentOS7 に netdata をインストールしてリアルタイムでリソース監視する - らくがきちょう

ちなみにアンインストールの方法は以下。
Uninstall Netdata | Learn

$ /usr/libexec/netdata/netdata-uninstaller.sh --yes

Webサーバが既に動作しているサーバにインストールする場合

また自分の場合、Webサービスが動作しているサーバにNetdataを設定したかったため、
そのためのvhost設定を以下のサイトを参考に設定した。
netdata/Running-behind-nginx.md at master · netdata/netdata · GitHub
mastodonが動いているサーバーにnetdataを相乗りさせた際のnginxの設定 - Qiita

ベーシック認証も。
Step 10. Set up a proxy | Learn


通知設定

デフォルトで以下のようなメール通知の設定がされている。

/usr/lib/netdata/conf.d/health_alarm_notify.conf

EMAIL_SENDER=""

# enable/disable sending emails
SEND_EMAIL="YES"

# if a role recipient is not configured, an email will be send to:
DEFAULT_RECIPIENT_EMAIL="root"

メールサーバが入っている場合は、root宛にメールが送られる。
自分の場合はメールサーバを運用せずに、Slackメッセージが送られれば十分のため
メール通知をOFFにし、SlackメッセージをONにする設定を行う。

Slackのincoming WebhookでURLを取得後、SLACK_WEBHOOK_URLにそのURLを設定し、
DEFAULT_RECIPIENT_SLACKにチャンネル名(#は省く)を設定すれば、そのチャンネル宛に通知が届くようになる。

例) netdataチャンネル宛に通知を行う設定
/etc/netdata/health_alarm_notify.conf

# [Email]
SEND_EMAIL='NO'

# [Slack]
SEND_SLACK='YES'
SLACK_WEBHOOK_URL='https://hooks.slack.com/services/xxxx......'
DEFAULT_RECIPIENT_SLACK='netdata'

設定を行った後は再起動。

$ sudo service netdata restart

また以下のコマンドを叩けばテスト通知も行える。

$ sudo su -s /bin/bash netdata
$ /usr/libexec/netdata/plugins.d/alarm-notify.sh test

これでテスト通知が届けば、設定が正しく行われている。

Slack | Learn
Setting up Netdata monitoring with Slack alarms – Arnold Galovics
Email notifications · Issue #3031 · netdata/netdata · GitHub

MySQLのリソース監視

まず、MySQLの監視設定については公式の以下のページを参考にした。
MySQL monitoring with Netdata | Learn

この監視設定を行うには、mysql上でnetdata用のユーザ作成が必須項目として挙げられている。
上記のリンクではパスワードなしのユーザを作成しているが、そもそもしっかりとセキュアな設定をしているMySQLでは
空のパスワードでのユーザ作成は許容されない。

なので以下のリンクやり方に従い、しっかりとしたパスワードでユーザを作成した後、
/etc/netdata/python.d/mysql.confに作成したユーザを設定する。
※ちなみにこのやり方は公式ドキュメントには書いてない!!!(#^ω^)
Integrate netdata monitor (on Linux server)

sql> GRANT USAGE ON *.* TO netdata@localhost IDENTIFIED BY '<password>';
sql> FLUSH PRIVILEGES;

/etc/netdata/python.d/mysql.conf

<任意の名前>:
    user: 'netdata'
    pass: '<password>'

設定後、netdataを再起動すれば「MySQL <任意の名前>」のセクションが表示される。

備考

・保存できるデータはデフォルトだと約2日分まで。

On a system that's collecting 2,000 metrics every second, the database engine's default configuration will store about two day's worth of metrics in RAM and on disk.

・Fail2banで読み込まれているfilterがsshdだけしか表示されないという現象が発生。
以下を参考にし、パーミッション関係かと思ったがそうではなかった。
Centos7 netdata only showing ssh bans and not other 13 filters. · Issue #6184 · netdata/netdata · GitHub

Fail2banプラグインをデバックモードで動かしてみると、jail.localのパースが失敗していた。

$ sudo /usr/libexec/netdata/plugins.d/python.d.plugin fail2ban debug trace

...
2020-04-30 13:03:20: python.d DEBUG: fail2ban[fail2ban] : /etc/fail2ban/jail.local parse failed
...

このプラグインのJailを読み取る正規表現を見てみると(true|false)とあり小文字のみの対応であったが、
自分はTrueまたはFalseと書いていた。それが原因だった。これをtrueとfalseにし、netdataを再起動したところ正常に他のJailsも読み込まれた。

RE_JAILS = re.compile(r'\[([a-zA-Z0-9_-]+)\][^\[\]]+?enabled\s+= (true|false)')

netdata/fail2ban.chart.py at master · netdata/netdata · GitHub

【fail2ban】WordPress用の独自フィルタ作成

以下のログに対応したものを作成する。

・wp-login.phpに対してPOSTをリクエストを送っているもの

※ 管理者のみがwp-login.phpするものなら良いが、不特定多数(woocommerceなど)が利用する場合は
wpのフィルター機能と連携して作成するのが良いと思う。
fail2banでWordPressを守る 2019年1月 - がとらぼ

フィルターの作成

$ vi /etc/fail2ban/filter.d/wordpress.local

failregexに、正規表現で検知したいログを記載します。 はIPアドレスに値します。

wordpress.local

[Definition]

# wp-login.phpの認証時に200番を返す場合は認証失敗を意味し、301番を返す場合は成功を意味する。
failregex = ^<HOST>.* "POST .*/wp-login.php([/\?#\\].*)? HTTP/.*" 200

ignoreregex =

フィルターの動作確認

以下のコマンドで対象ログの行が出ていれば成功

$ # fail2ban-regex access.logのパス /etc/fail2ban/filter.d/wplogin.local  --print-all-matched

監視設定

vi /etc/fail2ban/jail.conf に追記

[wordpress]
enabled = true
port = http,https
logpath = access.logのパス
maxretry = 5

再起動

$ systemctl restart fail2ban.service

【fail2ban】基本的な使い方

概要

Fail2banは、誤解を恐れずに言うと

1)様々な種類のログファイルを監視して、
2)特定のパターンにマッチしたログ情報(主にアクセス元IP)を元に
3)アクション(主にiptablesで接続拒否)を行う

ためのツール。

2)の特定のパターンにマッチさせる設定ファイルは「フィルター」と呼ばれ
デフォルトで入っているフィルターをそのまま使う、またはカスタマイズするか、
独自フィルターを作成することも可能

デフォルトで使用できるフィルターはsshdだけではなく
postfix, qmail, dovecot, proftpd, vsftpd, apache, PHP, phpmyadmin, nginx, mysql 等の有名所のログにも対応しているフィルターが入っている。

3)のアクション内容が定義された設定ファイルはiptablesだけではなく、sendmail, cloudflare, abuseipdb 等がある。
また独自アクションも作成可能。ちなみにアクションは複数設定が可能(例:攻撃元サイトをブロックし、sendmailで通知)

詳細は以下のサイトを参考にされたし。
不正アクセスからサーバを守るfail2ban。さくらのクラウド、VPSで使ってみよう! | さくらのナレッジ
第94回 サイトの防御とFail2ban[その1]:玩式草子─ソフトウェアとたわむれる日々|gihyo.jp … 技術評論社
fail2ban で対象 IP アドレスの第 2 オクテット(Class B)から遮断する - Qiita

※ [追記]
自分の勝手な勘違いだが、既に存在しているログファイルの行に対してもfail2banが対象になると思っていたが
それは勘違いで、fail2banがBanしてくれるログはあくまでも”監視中"のもののみのよう。

ログファイルの場所

/var/log/fail2ban.log

設定

主に以下の2つ。
1)/etc/fail2ban/fail2ban.conf・・・一般設定を行うファイル
2)/etc/fail2ban/jail.conf・・・どのログファイルを監視するかの設定を行うファイル。

ただし上記のファイルを直接触れるのは、fail2ban更新時に設定がすべて消えてしまうためご法度。
そのため、以下のファイルを別途新規に作る。

3)/etc/fail2ban/fail2ban.local
4)/etc/fail2ban/jail.local

3)と4)は1)と2)の内容を受け継ぎ、1)と2)の設定を上書きする。
そのため全部の設定を書く必要はなく、上書きしたい設定のみを書けば良い。

fail2ban.localの例

[Defination]
# change loglevel - CRITICAL, ERROR, WARNING, NOTICE, INFO, DEBUG
loglevel = INFO

# change log file location if required
logtarget = /var/log/fail2ban.log

# change pidfile location if required
pidfile = /var/run/fail2ban/fail2ban.pid

/etc/fail2ban/jail.localの例でsshdのみを設定

[DEFAULT]

# "bantime" is the number of seconds that a host is banned.
bantime = 15m

# A host is banned if it has generated "maxretry" during the last "findtime" seconds.
findtime  = 15m

# "maxretry" is the number of failures before a host get banned.
maxretry = 6

[ssh]
enabled = true
port = ssh
filter = sshd
logpath = /var/log/auth.log
maxretry = 4

現在の設定の確認コマンド

$ fail2ban-client status

特定のJailの確認コマンド

ex) sshd

$ fail2ban-client status sshd

独自フィルタと独自アクション

独自フィルタは「/etc/fail2ban/filter.d/」内に作成する。
拡張子は「.conf」か「.local」かを選べるがデフォルトのものと見分けるために「.local」で作成する方が良い。

独自アクション「/etc/fail2ban/action.d/」内に作成する。
独自フィルタと同じく、拡張子は「.local」を使用する。

詳細は別の記事で。


[参考]
How to use Fail2ban on Ubuntu 18.04 - LaymanClass
Using Fail2ban to Secure Your Server - A Tutorial | Linode

【Nginx】OCSP Staplingについて

Nginxのエラーログを見てたら「OCSP_basic_verify() failed・・・」というエラーが出ていたので調べてみた。

OCSP Staplingとは何か?の説明については以下のサイトの説明がわかりやすい。
OCSP Stapling
nginx で OCSP Stapling (RapidSSL) | | 1Q77
How To Configure OCSP Stapling on Apache and Nginx | DigitalOcean

要はSSLが失効しているかをチェックするためのプロトコルということ。

以下のコマンドを実行すれば設定の有無がわかる。

$ echo QUIT | openssl s_client -connect localhost:443 -status 2> /dev/null | head -n 20

「OCSP Response Status: successful」:設定されている
「OCSP response: no response sent」:設定されていない

または以下のサイトにアクセスして、確認する手もある。
その際には「Do not show the results on the boards」にチェックを念の為に入れておいたほうが良いだろう。
SSL Server Test (Powered by Qualys SSL Labs)

【fail2ban】Ubuntu 18.04上で単純なsshdフィルターのみ使用しているのに、IPがbanされない現象

結論から言うとbackendに、pollingを指定していたのが原因だった。
ちなみにFail2banのバージョンは「v0.10.2」

backend: 対象のログについての指定。 auto, pyinotify, gamin, systemd, pollingの5つから選択可能。 systemdを選択すると、systemdのjournalから情報を取得します。 autoはpyinotify, gamin, systemd, pollingの順番に情報を取得しますが、たまにgaminで失敗するそうです。 任意のログファイルを指定するのであれば、pollingを指定しておけば問題ないと思います。

by WordPressの不正ログインと不正中継メール送信をfail2banでbanしてみた - Qiita

どの記事をみて、pollingの設定をしていたのかは忘れたが、この値をautoにしたところ、ちゃんとIPをBanするようになった。

[追記]

systemdが選択されるとlogpathは無視してjournalmatchを使ってどのログファイルを監視するかを決める

↑ systemdを選択するときは注意が必要そう。。。。

[参考]
fail2banのbackend問題 – NorthPage