アクセス解析ツール GoAccess の導入

GoAccess Umami
データ源 Nginx/Apache等のアクセスログ Webサイトに埋め込んだトラッキングコード
解析対象 HTTPリクエストそのもの 訪問者・ページ閲覧・行動
JavaScript 不要 基本的に必要
サーバーへの直接アクセス 見える 基本的に見えない
Bot / Scanner 把握しやすい 基本的に除外・把握しにくい
404 / 5xx 非常に得意 限定的
静的ファイルへのアクセス 把握できる 通常は把握しない
ページ遷移・セッション 苦手 得意
ボタンクリック等 苦手 得意
UTM / コンバージョン 限定的 得意
Webサーバー負荷・異常監視 得意 苦手

htmlファイルの生成

GoAccessのDockerイメージを利用して、分析結果となるhtmlファイルを生成します。

docker-compose.yml

services:
  goaccess:
    image: allinurl/goaccess:latest
    container_name: goaccess
    volumes:
      - ../container_logs/nginx:/logs:ro
      - ./config:/etc/goaccess:ro
      - ./report:/report
      - ./scripts:/scripts:ro
      - ./geoip:/geoip:ro 
    restart: unless-stopped

config/goaccess.conf

time-format %T
date-format %d/%b/%Y
date-spec hr

log-format COMBINED
geoip-database /geoip/GeoLite2-City.mmdb
geoip-database /geoip/GeoLite2-ASN.mmdb

static-file jpg
static-file jpeg
static-file png
static-file gif
static-file svg
static-file ico
static-file webp
static-file avif
static-file css
static-file js
static-file map
static-file woff
static-file woff2
static-file ttf
static-file otf

exclude-ip 127.0.0.1
exclude-ip 172.16.0.0-172.31.255.255
exclude-ip 192.168.0.0-192.168.255.255
exclude-ip 10.0.0.0-10.255.255.255

注)オプション:tz Asia/Tokyo によるバグがあるため、UTCのまま運用するか、ホストとNginxのタイムゾーンをUTCからJPTへ変更して対応する必要あり。

ジオロケーションデータを以下のサイトから入手。

goaccess/geoipフォルダに入手した以下データをコピー

GeoLite2-ASN.mmdb
GeoLite2-City.mmdb

ホストと共有したNginxのログファイルからhtmlファイルを生成するスクリプト。

scripts/generate.sh

#!/bin/sh
set -eu

generate_report() {
    prefix="$1"
    output="$2"

    echo "Generating $output..."

    tmpdir="/tmp/goaccess-${prefix}"
    rm -rf "$tmpdir"
    mkdir -p "$tmpdir"

    # 現在のログ
    [ -f "/logs/${prefix}.access.log" ] &&
        cp "/logs/${prefix}.access.log" "$tmpdir/"

    # ローテーション済みログ
    for file in /logs/${prefix}.access.log.[0-9]*; do
        [ -f "$file" ] || continue

        case "$file" in
            *.gz)
                gzip -cd "$file" > "$tmpdir/$(basename "${file%.gz}")"
                ;;
            *)
                cp "$file" "$tmpdir/"
                ;;
        esac
    done

    files=$(find "$tmpdir" -type f -name "${prefix}.access.log*" -print | sort -V)

    if [ -z "$files" ]; then
        echo "No log files found for $prefix"
        return
    fi

    # shellcheck disable=SC2086
    goaccess $files \
        -p /etc/goaccess/goaccess.conf \
        -o "/report/${output}"

    rm -rf "$tmpdir"
}

generate_report "f9e" "f9e.html"
generate_report "f9e-forum" "f9e-forum.html"
generate_report "f9e-store" "f9e-store.html"

echo "Done."

htmlファイル生成

$ docker compose run --rm --entrypoint /bin/sh goaccess /scripts/generate.sh

ドメインを指定してウェブアクセス

Basic認証パスワード設定

$ docker run --rm httpd:alpine htpasswd -Bbn USER PASSWORD > htpasswd

nginx設定ファイル

nginx/goaccess.conf

server {
    listen 443 ssl;
    listen [::]:443 ssl;
    server_name goaccess.example.com;
    server_tokens off;
    http2 on;

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

    ssl_certificate     /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
    include /etc/letsencrypt/options-ssl-nginx.conf;
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;

    root /usr/share/nginx/html/goaccess;
    index f9e.html;

    location / {
        auth_basic "Restricted Stats";
        auth_basic_user_file /etc/nginx/.htpasswd;
        autoindex on;
    }
}

server {
    listen 80;
    listen [::]:80;
    server_name goaccess.example.com;
    return 301 https://$host$request_uri;
}

ログローテーション

logrotate設定ファイルの作成

/etc/logrotate.d/nginx

/home/takanobu/docker_server/container_logs/nginx/*.log {
  hourly
  missingok
  rotate 27
#  dateext
#  dateformat -%Y%m%d%H
  compress
  delaycompress
  notifempty
  sharedscripts
  postrotate
    cd /home/takanobu/docker_server \
      && docker compose kill -s USR1 nginx
  endscript
}

nginxのログを更新するためのlogrotateを1時間ごとに実行するタスクをcronジョブ(hourly)に登録。

注)デフォルトでログローテーションはdailyのcronジョブに所属。
ログローテーションの所属をhourlyに変更するのではなく、ログローテーション実行タスクをhourlyのcronジョブに登録。

$ sudo tee /etc/cron.hourly/logrotate-nginx <<'EOF'
#!/bin/sh
/usr/sbin/logrotate -s /var/lib/logrotate/status-nginx /etc/logrotate.d/nginx
EOF

実行権付与

$ sudo chmod +x /etc/cron.hourly/logrotate-nginx

GoAccessがhtmlを生成するcronジョブを登録(Ubuntuのデフォルトでhourlyのcronジョブは毎時17分に実行される:+5分後に設定。6時間に1回実行。)

22 0,6,12,18 * * * cd /xxxx/goaccess && /usr/bin/docker compose run --rm --entrypoint /bin/sh goaccess /scripts/generate.sh >> /xxxx/goaccess/cron.log 2>&1