nginxのエラーページの設定方法

デフォルトのnginxの設定のままだとエラーページにnginxのバージョンが表示されてしまいます。

セキュリティを考えると良くないので表示されないようにします。設定は簡単で、nginx.confに「server_tokens off;」と記載するだけです。nginx.confは /etc/nginx 配下にあります。


user  nginx;
worker_processes  1;
 :
 :
http {
 :
  server_tokens off;
 :
}

nginxを再起動して同じエラーページを表示してみると、バージョンが表示されなくなります。

とは言ってもWEBサーバーにnginxを使っていることはバレてしまいます。ユーザーがサイト内の存在しないURLにアクセスすることでサーバーからのエラー情報を取得しようとする場合に備え、専用のエラーページを表示させるようにしておこうと思います。

初期設定のnginxではdefault.confの「error_page 404 /404.html;」の記載がコメントアウトされていますので、このコメントアウトを外して専用のエラーページ(40x.html)表示に変えます。default.confは /etc/nginx/conf.d 配下にあります。


server {
 :
  error_page  400 403 404  /40x.html;
  location = /40x.html {
      root   /usr/share/nginx/html;
  }
 :
 :
}

初期設定だとHTTPのステータスコード404しか記載がありませんので400と403も独自に追加しました。意味は以下です。

400(Bad Request)・・不正なリクエスト
403(Forbidden)・・禁止されているリクエスト
404(Not Found)・・リソースが見つからない

default.confへの記載が終わったら40x.htmlを新規作成して配置します。40x.htmlには以下を記載します。


<!DOCTYPE HTML>
<html><head>
<title>404 Not Found</title>
</head><body>
<h1>Not Found</h1>
<p>The requested URL was not found on this server.</p>
</body></html>

HTTPステータス400、403も404エラーとして表示させています。この辺は好みによってエラー文言を変えてください。この40x.htmlを /usr/share/nginx/html 配下に配置します。このディレクトリはroot権限がないと書き込みできないです。

nginxを再起動して(存在しないhtmlファイルを指定するなどして)エラーページを表示してみます。

という画面が表示されるかと思いましたが、

となりました。実はコレ、、Apacheのエラー画面のHTMLソースをコピってきたもので、キャッシュが残っていたのかフォントがApacheのままになってしまいました。Apacheで動いているように見せかけて、実はnginxで動いているという・・これはこれでそのままとします。

ちなみに /usr/share/nginx/html 配下には50x.htmlというのが格納されています。これはHTTPステータスが500、502、503、504のときに表示されるものです(default.confに記載されています)。50x.htmlにはnginxの記載がありますのでnginxという文言を隠すのであれば50x.htmlも書き換えたほうが良いでしょう。

少し別の話題になりますが、nginxではエラーページ表示の代わりにレスポンスを返さない、という設定ができます。HTTP標準にはないnginx独自のステータスコード444を指定することで、レスポンスヘッダを返さずに接続を強制的に終了するようです。


server {
    listen       80;
    server_name  dummy;
    root         /var/www/html/dummy;

    location / {
        return 444;
    }
  :
  :
}

この設定をしたnginxにアクセスすると、ブラウザではこのように表示されます。FireFoxの例です。

エラーページとステータスコード444をうまく使い分けると良さそうです。

新規ログファイルは初日にlogrotateされない?

CentOSのnginxをいじっていてログファイルの名前を変えたらローテートされていないことに気づきました。CentOSのログのローテートのイメージです。

初め
access.log
error.log

翌日
access.log
access.log-20210102
error.log
error.log-20210102

翌々日
access.log
access.log-20210102.gz
access.log-20210103
error.log
error.log-20210102.gz
error.log-20210103

dailyでローテートするようにしているのですが翌日に確認するとローテートされていません。。logrotateのコンフィグファイルの設定です。


/var/log/nginx/*.log {
        daily
        missingok
        rotate 5
        compress
        delaycompress
        notifempty
        create 640 nginx adm
        sharedscripts
        postrotate
                if [ -f /var/run/nginx.pid ]; then
                        kill -USR1 `cat /var/run/nginx.pid`
                fi
        endscript
}

error.logがもともとあったファイルでdumy_access.logとdumy_error.logが新しく作成されたログファイルです。以下に今回起きた状況を書くと、、

初め
dumy_access.log
dumy_error.log
error.log
error.log-20210103

翌日
dumy_access.log
dumy_error.log
error.log
error.log-20210103.gz
error.log-20210104

error.logはちゃんとローテートされているのですが、新規ログファイルのdumy_access.logとdumy_error.logがローテートされていないです。dumy_access.logとdumy_error.logがログファイルとして認識されていないんじゃないか?と思い調べてみたところ、原因は別にありました。

logrotateはcronでlogrotateコマンドを実行しているので /etc/cron.daily 配下のlogrotateシェルを見てみます。


#!/bin/sh

/usr/sbin/logrotate -s /var/lib/logrotate/logrotate.status /etc/logrotate.conf
EXITVALUE=$?
if [ $EXITVALUE != 0 ]; then
    /usr/bin/logger -t logrotate "ALERT exited abnormally with [$EXITVALUE]"
fi
exit 0

logrotateコマンドのパラメータにlogrotate.statusファイルとlogrotate.confファイルを与えています。このうち、logrotate.statusには前回ログローテートを行った時刻を記載しているとのこと。logrotate.statusを見てみました。


# grep nginx /var/lib/logrotate/logrotate.status
"/var/log/nginx/error.log" 2021-1-4-3:44:1
"/var/log/nginx/dumy_error.log" 2021-1-4-3:0:0
"/var/log/nginx/dumy_access.log" 2021-1-4-3:0:0

dumy_error.logとdumy_access.logの記載があるのでログファイルとしては認識してるようです。ではなぜローテートされなかったかというと、新規ログファイルの場合はlogrotate.statusに何も記載がないわけで、初回処理時に新規ログファイルの情報をlogrotate.statusに書き込むようです。初回の処理としてはそれで終わりです。次回(翌日)のlogrotateが動くときにlogrotate.statusに記載のある時刻を元に1日後(daily)、1週間後(weekly)、1ヶ月後(monthly)のローテートを行うようです。なので、明日、もう一度ローテートがされているか確認することにしました。

[広告]

で、、翌日。。

ちゃんとローテートされてました。こんな感じです。

dumy_access.log
dumy_access.log-20210105
dumy_error.log
dumy_error.log-20210105
error.log
error.log-20210103.gz
error.log-20210104.gz
error.log-20210105

logrotate.statusも更新されていました。ということで、logrotateは初日はローテートをしないということを知りました。

ちなみにですが、logrotateのコンフィグファイルでdaily指定しているものが毎日ローテートされているか見てみると、そうでないものがありました。これはログファイルがゼロバイトのためのようです。ゼロバイトのログファイルもローテート対象にするにはコンフィグファイルにifemptyの指定をすればローテート対象になるようです。

なお、ubuntuの場合はlogrotate.statusではなくstatusという名前のファイルです。参考までにubuntuのlogrotateシェルを載せておきます。


#!/bin/sh

# Clean non existent log file entries from status file
cd /var/lib/logrotate
test -e status || touch status
head -1 status > status.clean
sed 's/"//g' status | while read logfile date
do
    [ -e "$logfile" ] && echo "\"$logfile\" $date"
done >> status.clean
mv status.clean status

test -x /usr/sbin/logrotate || exit 0
/usr/sbin/logrotate /etc/logrotate.conf

CentOSとはちょっと違うのですね。。