Setup GoAccess + Nginx + logrotate with Ansible

June 7, 2020

About setup

This is purely technical blog optimized for copy paste. I’m going to describe how to set up GoAccess, Nginx and logrotate using Ansible for Ubuntu/Debian OS.

GoAccess is awesome local replacement for Google Analytics. It’s simpler than Google Analytics or other similar software, but it’s enough for my need. Big pros - you don’t send the user data to Google.

Summary of the setup:

  • GoAccess generates single HTML page analytic based on Nginx logs;
  • Nginx stores access logs and serves GoAccess HTML with password protection;
  • logrotate rotates Nginx logs and removes the old one.

Nginx

Nginx by default writes access.log file in correct GoAccess format, so we only need to serve analytics under Auth Basic protection.

http {
  access_log /opt/optduty/logs/nginx-access.log;
  error_log /opt/optduty/logs/nginx-error.log;

  server {
    server_name  optduty.com;

    location =/weblogs.html {
      alias /opt/optduty/weblogs.html;
      auth_basic "closed site";
      auth_basic_user_file /etc/nginx/htpasswd;
    }
  }
}

Logrotate config

/opt/optduty/logs/*.log {
  daily
  missingok
  compress
  rotate 7

  postrotate
    invoke-rc.d nginx rotate >/dev/null 2>&1
  endscript
}

Logrotate config is basically copy paste from default Nginx config. I’m only tunned it to rotate daily in compressed format and to remove logs after 1 week.

After deploy I’d recommend to test logrotate with command logrotate -d path/to/config. Depending on your user/permission setup maybe you’ll need to change config a little bit.

Ansible

The final part is ansible config to set up everything. Ansible deploys Nginx+logrotate configs and run GoAccess periodically in cron. I’m using a few extra parameters in GoAccess: --exclude-ip to remove my IP address, --anonymize-ip and --geoip-database to have country stats.

---
- hosts: servers
  tasks:
    - name: Install a list of packages
      apt:
        pkg:
        - nginx
        - goaccess
        - python3-passlib

    - cron:
        name: "stats"
        minute: 0
        hour: "*"
        user: "root"
        job: "zcat /opt/optduty/logs/nginx-access.log.*.gz | goaccess -f - -f /opt/optduty/logs/nginx-access.log --log-format=COMBINED -o /opt/optduty/weblogs.html --exclude-ip 8.8.8.8 --anonymize-ip --geoip-database=/opt/optduty/GeoLite2-Country.mmdb"

    - htpasswd:
        path: /etc/nginx/htpasswd
        name: admin
        password: 'superPassword'
    - template:
        src: templates/nginx.conf
        dest: /etc/nginx/nginx.conf
        mode: '0666'
    - service:
        name: nginx
        enabled: yes
        state: restarted

    - template:
        src: templates/logrotate.conf
        dest: /etc/logrotate.d/optduty
    - copy:
        src: templates/GeoLite2-Country.mmdb
        dest: /opt/optduty/