AWStats+Nginx in Docker

Dockerコンテナにより稼働しているNginxウェブサーバにAWStatsを導入します。
Alpine-Linux版NginxコンテナにAWStatsをインストール、AWStats関連ディレクトリ及びファイルをdocker-composeファイルにより、NginxコンテナとPHP-FPMコンテナでシェアします。

awstats_ban_460x270

<参考>
https://wiki.archlinux.org/index.php/AWStats

docker-composeファイルのnginx, php-fpmのボリュームセクションに以下追加(一部抜粋)。

  # nginx https://hub.docker.com/_/nginx?tab=description
  nginx:
    container_name: nginx
    build: 
      context: ./docker_files
      dockerfile: nginx-alpine
      
    volumes:
      # awststs
      - awstats:/usr/lib/awstats
      - awstats_script:/etc/nginx
      - awstats_conf:/etc/awstats

  php-fpm:
    container_name: php-fpm
    image: PHP7.2-fpm    

      # awststs
      - awstats:/usr/lib/awstats
      - awstats_script:/etc/nginx
      - awstats_conf:/etc/awstats

上記nginxdockerfile nginx-alpineを別途用意します。

FROM nginx:alpine

# Set working directory
WORKDIR /var/www/html

RUN apk add --no-cache bash nano awstats
COPY awstats.www.yourdomain.com.conf /etc/awstats/
COPY cgi-bin.php /etc/nginx/

COPY awstats.www.yourdomain.com.conf /etc/awstats/
AWStatsによるドメインごとの設定ファイルを予め用意します。
(一度nginxコンテナにawstatsをインストール、その後/etc/awstatsディレクトリのデフォルト設定ファイルからドメインごとの設定ファイルをコピーして作成)

COPY cgi-bin.php /etc/nginx/
awstatsによるperlスクリプトを動作させるため、以下のphpスクリプトを作成します。

<?php
$descriptorspec = array(
   0 => array("pipe", "r"),  // stdin is a pipe that the child will read from
   1 => array("pipe", "w"),  // stdout is a pipe that the child will write to
   2 => array("pipe", "w")   // stderr is a file to write to
);
$newenv = $_SERVER;
$newenv["SCRIPT_FILENAME"] = $_SERVER["X_SCRIPT_FILENAME"];
$newenv["SCRIPT_NAME"] = $_SERVER["X_SCRIPT_NAME"];
if (is_executable($_SERVER["X_SCRIPT_FILENAME"])) {
   $process = proc_open($_SERVER["X_SCRIPT_FILENAME"], $descriptorspec, $pipes, NULL, $newenv);
   if (is_resource($process)) {
       fclose($pipes[0]);
       $head = fgets($pipes[1]);
       while (strcmp($head, "\n")) {
           header($head);
           $head = fgets($pipes[1]);
       }
       fpassthru($pipes[1]);
       fclose($pipes[1]);
       fclose($pipes[2]);
       $return_value = proc_close($process);
   } else {
       header("Status: 500 Internal Server Error");
       echo("Internal Server Error");
   }
} else {
   header("Status: 404 Page Not Found");
   echo("Page Not Found");
}
?> 

nginxコンテナにインストールされたAWStats関連ファイルをシェアするための共有ボリュームを作成 (awstats, awstats_script, awstats_conf)

$ dcoker volume create --name=VOLUME_NAME

docker-composeファイルに以下追加します(一部抜粋)。

volumes:
  awstats:
    external: true
  awstats_script:
    external: true
  awstats_conf:
    external: true

nginxの設定ファイルにawstatsを読み込むための記述を追加します。

location ^~ /icon {
   alias /usr/lib/awstats/icon/;
   access_log off;
}
location ^~ /awstatscss {
   alias /usr/lib/awstats/css/;
   access_log off;
}
location ^~ /awstatsclasses {
   alias /usr/lib/awstats/classes/;
   access_log off;
}
location ~ ^/cgi-bin/.*\.(cgi|pl|py|rb) {
   gzip off;
   fastcgi_pass  unix:/var/run/php-fpm/php-fpm.sock;
   fastcgi_index cgi-bin.php;
   fastcgi_param SCRIPT_FILENAME    /etc/nginx/cgi-bin.php;
   fastcgi_param SCRIPT_NAME        /cgi-bin/cgi-bin.php;
   fastcgi_param X_SCRIPT_FILENAME  /usr/lib/awstats$fastcgi_script_name;
   fastcgi_param X_SCRIPT_NAME      $fastcgi_script_name;
   fastcgi_param QUERY_STRING       $query_string;
   fastcgi_param REQUEST_METHOD     $request_method;
   fastcgi_param CONTENT_TYPE       $content_type;
   fastcgi_param CONTENT_LENGTH     $content_length;
   fastcgi_param GATEWAY_INTERFACE  CGI/1.1;
   fastcgi_param SERVER_SOFTWARE    nginx;
   fastcgi_param REQUEST_URI        $request_uri;
   fastcgi_param DOCUMENT_URI       $document_uri;
   fastcgi_param DOCUMENT_ROOT      $document_root;
   fastcgi_param SERVER_PROTOCOL    $server_protocol;
   fastcgi_param REMOTE_ADDR        $remote_addr;
   fastcgi_param REMOTE_PORT        $remote_port;
   fastcgi_param SERVER_ADDR        $server_addr;
   fastcgi_param SERVER_PORT        $server_port;
   fastcgi_param SERVER_NAME        $server_name;
   fastcgi_param REMOTE_USER        $remote_user;
}

nginxコンテナ内におけるログファイル /var/log/nginx/access.log 及び error.log は、ホストから $ docker logsコマンドで参照するためのものであり、通常のファイルではありません(STDOUT, STDERRへのリンク)。
このため、nginxの設定ファイル内で、serverセクション毎(ドメインネーム毎)にawstats用に別途ログファイルを指定する必要があります。

server {
    .......
    .......

    access_log  /var/log/nginx/domain001.access.log;
    error_log   /var/log/nginx/domain001.error.log error;
    .......

ホストのcrontabに自動アップデートコマンドを追加します。

$ sudo crontab -e

0 */3 * * *  docker exec nginx awstats.pl -config=yourdomain.ext -update > /dev/null

または、/usr/binディレクトリにアップデートスクリプトawstats_updateall.plが用意されているので、

$ sudo crontab -e

0 */3 * * *  docker exec nginx awstats_updateall.pl now > /dev/null

AWStats logfile analyzer 7.8 Documentation

その他ユーティリティについても下記参照して下さい。
Alpine Linuxでは、/usr/binディレクトリにインストールされます。

Awstatsにより作成されたデータは、デフォルトではawstats.plが格納されているディレクトリ (/usr/lib/awstats/cgi-bin) に作成されます。

Nginx+Basic Authentication

apache2-utilsのインストール(Alpine Linux)

# apk add apache2-utils

パスワードファイルの作成

$ sudo htpasswd -c /etc/apache2/.htpasswd user1

Nginx設定ファイルによるBasic認証の設定例

location /api {
    #...
    satisfy all;    

    deny  192.168.1.2;
    allow 192.168.1.1/24;
    allow 127.0.0.1;
    deny  all;

    auth_basic           "Administrator’s Area";
    auth_basic_user_file conf/htpasswd;
}

awstats 7.8 (build 20200416)アップデートエラー

以下Awstatsによるアクセスログファイルのロード時のエラー。ブラウザによる統計データの表示もブランクになる。

bash-5.0# awstats.pl -update -config=www.example.com
String found where operator expected at /usr/lib/awstats/cgi-bin/lib/mime.pm line 60, near "'ebook'"
	(Missing semicolon on previous line?)
syntax error at /usr/lib/awstats/cgi-bin/lib/mime.pm line 60, near "'ebook'"
Compilation failed in require at /usr/bin/awstats.pl line 2239.

原因は、上記メッセージにもあるようにmime.pm内の記述ミス。これを修正。

# nano /usr/lib/awstats/cgi-bin/lib/mime.pm

 'torrent',   'BitTorrent File',
 59 'gis',       'GIS File',  #--->ここにカンマ","を追加
 60 'ebook',     'Ebook File'

IPv6プラグイン

各ドメインの設定ファイル内で下記の箇所をアンコメントしてIPv6プラグインを有効にします。

# PLUGIN: IPv6
# PARAMETERS: None
# REQUIRED MODULES: Net::IP and Net::DNS
# DESCRIPTION: This plugin gives AWStats capability to make reverse DNS
# lookup on IPv6 addresses.
#
LoadPlugin="ipv6"

上記プラグインに必要なPerlモジュールをインストール

perl-net-ip(Alpine)
https://alpine.pkgs.org/3.17/alpine-main-x86_64/perl-net-ip-1.26-r4.apk.html

# apk add --upgrade perl-net-ip

perl-net-dns(Alpine)
https://alpine.pkgs.org/3.17/alpine-main-x86_64/perl-net-dns-1.35-r0.apk.html

# apk add --upgrade perl-net-dns