GoAccess is a fast, open-source real-time web log analyzer that runs entirely in the terminal or generates self-contained HTML reports without requiring a separate database or web framework. On RHEL 9, it can parse Nginx access logs in seconds to surface the metrics that matter most — unique visitors, top requested URLs, HTTP response code distribution, geographic traffic breakdown, and bandwidth consumption. This tutorial walks through installing GoAccess from the EPEL repository, running it in interactive terminal mode, generating a static HTML report, enabling a real-time WebSocket dashboard, and processing compressed rotated log archives to build a historical view of your traffic.

Prerequisites

  • RHEL 9 server with Nginx installed and writing logs to /var/log/nginx/access.log
  • EPEL repository enabled (sudo dnf install -y epel-release)
  • A non-root user with sudo privileges
  • A web-accessible directory if you want to publish the HTML report (e.g., /var/www/html/)

Step 1 — Install GoAccess

Install GoAccess from the EPEL repository and confirm the installed version.

sudo dnf install -y epel-release
sudo dnf install -y goaccess

# Confirm installation
goaccess --version

# View the default GoAccess configuration file location
ls /etc/goaccess/goaccess.conf

Step 2 — Run GoAccess in Interactive Terminal Mode

Launch GoAccess against the live Nginx access log directly in your terminal using the combined log format. The interactive dashboard refreshes in real time as new requests arrive.

# Run GoAccess interactively — press F1 for help, q to quit
sudo goaccess /var/log/nginx/access.log 
  --log-format=COMBINED 
  --real-time-html=false

# If your Nginx log uses a custom format, specify it explicitly.
# For a log_format named 'main' containing:
#   $remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent
# use:
sudo goaccess /var/log/nginx/access.log 
  --log-format='%h - %e [%d:%t %^] "%r" %s %b' 
  --date-format='%d/%b/%Y' 
  --time-format='%H:%M:%S'

Step 3 — Generate a Static HTML Report

Generate a standalone HTML report file from the current access log. The output file is fully self-contained with embedded CSS and JavaScript — copy it anywhere and open it in a browser.

sudo goaccess /var/log/nginx/access.log 
  --log-format=COMBINED 
  -o /var/www/html/report.html

# Set appropriate permissions so the web server can read it
sudo chown nginx:nginx /var/www/html/report.html
sudo chmod 644 /var/www/html/report.html

# Verify the file was created and is non-empty
ls -lh /var/www/html/report.html

# Open in browser at: http://YOUR_SERVER_IP/report.html

Step 4 — Enable the Real-Time WebSocket Dashboard

GoAccess can serve a live-updating HTML dashboard over WebSocket. Use the --real-time-html flag along with --ws-url to specify the WebSocket address the browser will connect to.

sudo firewall-cmd --permanent --add-port=7890/tcp
sudo firewall-cmd --reload

# Start GoAccess in real-time mode (runs in the foreground; use screen or tmux for persistence)
sudo goaccess /var/log/nginx/access.log 
  --log-format=COMBINED 
  -o /var/www/html/live-report.html 
  --real-time-html 
  --ws-url=ws://YOUR_SERVER_IP:7890 
  --port=7890

# To run as a background process
sudo nohup goaccess /var/log/nginx/access.log 
  --log-format=COMBINED 
  -o /var/www/html/live-report.html 
  --real-time-html 
  --ws-url=ws://YOUR_SERVER_IP:7890 
  --port=7890 &> /var/log/goaccess.log &

# Open in browser at: http://YOUR_SERVER_IP/live-report.html
# The dashboard updates automatically as new log lines are written

Step 5 — Process Compressed Rotated Logs

Nginx rotates and compresses old log files with logrotate. Use zcat to decompress and pipe all archived logs together with the current log to produce a comprehensive historical report.

# List existing rotated Nginx logs
ls -lh /var/log/nginx/access.log*

# Decompress and concatenate all rotated logs plus the current log
zcat /var/log/nginx/access.log.*.gz | cat - /var/log/nginx/access.log 
  | sudo goaccess - 
    --log-format=COMBINED 
    -o /var/www/html/history-report.html

# If there are no .gz files yet (rotation not occurred), just use the current log
sudo goaccess /var/log/nginx/access.log 
  --log-format=COMBINED 
  -o /var/www/html/history-report.html

ls -lh /var/www/html/history-report.html

Step 6 — Automate Daily HTML Report Generation with Cron

Schedule a cron job to regenerate the HTML report daily so stakeholders always have an up-to-date view of the previous day’s traffic without manual intervention.

sudo tee /etc/cron.daily/goaccess-report > /dev/null </dev/null)
OUTPUT=/var/www/html/report.html

if [[ -n "$ROTATED" ]]; then
  zcat $ROTATED | cat - "$LOG" | goaccess - 
    --log-format=COMBINED 
    -o "$OUTPUT"
else
  goaccess "$LOG" 
    --log-format=COMBINED 
    -o "$OUTPUT"
fi

chown nginx:nginx "$OUTPUT"
chmod 644 "$OUTPUT"
EOF

sudo chmod +x /etc/cron.daily/goaccess-report

# Test the script runs without errors
sudo /etc/cron.daily/goaccess-report && echo "Report generated successfully"

Conclusion

GoAccess is now installed on RHEL 9 and configured to analyse Nginx access logs in three modes: interactive terminal for ad-hoc investigation, static HTML reports for sharing with non-technical stakeholders, and a live WebSocket dashboard for real-time traffic monitoring. The cron job ensures that the published HTML report is refreshed every night automatically. GoAccess parses the standard combined log format out of the box, but you can extend it to handle any custom Nginx log_format by adjusting the --log-format, --date-format, and --time-format flags to match your directive tokens.

Next steps: How to Set Up Nginx with ModSecurity WAF on RHEL 9, How to Forward Nginx Logs to Elasticsearch with Filebeat on RHEL 9, and How to Monitor Nginx Access Logs with Prometheus and Grafana on RHEL 9.