GoAccess is an open-source, real-time web log analyzer that generates interactive HTML reports and live terminal dashboards directly from Nginx access logs. It requires no database, no JavaScript framework, and no persistent service — a single command can parse millions of log entries in seconds. On RHEL 8 the package is available from the EPEL repository, making installation straightforward. This tutorial covers installing GoAccess from EPEL, generating a static HTML report, enabling a live real-time dashboard served by Nginx itself, and proxying the WebSocket connection GoAccess uses for push updates.
Prerequisites
- RHEL 8 server with Nginx installed and generating access logs at
/var/log/nginx/access.log - EPEL 8 repository enabled (
dnf install -y epel-release) - Root or sudo access
- Firewalld active
- A domain name or server IP to access the report from a browser (optional)
Step 1 — Enable EPEL and Install GoAccess
GoAccess is not in the default RHEL 8 repositories. Enable EPEL 8 if you have not already done so, then install the package.
# Enable EPEL repository
sudo dnf install -y epel-release
# Install GoAccess
sudo dnf install -y goaccess
# Verify the installed version
goaccess --version
Step 2 — Generate a Static HTML Report
The simplest use case is generating a one-shot HTML report from an existing log file. The COMBINED log format matches Nginx’s default combined access log format, which includes method, URI, status code, bytes, referrer, and user agent.
# Generate a static HTML report from the default Nginx access log
sudo goaccess /var/log/nginx/access.log
--log-format=COMBINED
-o /tmp/report.html
--no-global-config
echo "Report generated at /tmp/report.html"
# Include all rotated logs in the report
sudo goaccess /var/log/nginx/access.log /var/log/nginx/access.log.*.gz
--log-format=COMBINED
-o /tmp/report-full.html
--no-global-config
# Check report file size
ls -lh /tmp/report.html /tmp/report-full.html
Step 3 — Serve the Report via Nginx
Move the generated report to the Nginx web root and add a location block that restricts access to trusted IP addresses, since the report may expose internal URL structures and traffic patterns.
# Create a dedicated directory for the report
sudo mkdir -p /var/www/html/stats
sudo chown nginx:nginx /var/www/html/stats
# Copy a generated report into it
sudo cp /tmp/report.html /var/www/html/stats/index.html
sudo chown nginx:nginx /var/www/html/stats/index.html
# Add a location block to your Nginx server block
# Edit /etc/nginx/conf.d/your-site.conf and add inside the server {} block:
cat <<'EOF'
location /stats/ {
alias /var/www/html/stats/;
index index.html;
auth_basic "Analytics";
auth_basic_user_file /etc/nginx/.htpasswd;
}
EOF
# Create a password-protected .htpasswd file (replace 'admin' with your username)
sudo dnf install -y httpd-tools
sudo htpasswd -c /etc/nginx/.htpasswd admin
sudo nginx -t && sudo systemctl reload nginx
Step 4 — Enable Real-Time HTML Dashboard
GoAccess can tail a log file continuously and push updates to an open browser via WebSocket. Run it as a background process and direct the output to the web-accessible directory. The default WebSocket port is 7890.
# Run GoAccess in real-time HTML mode (background)
sudo goaccess /var/log/nginx/access.log
--log-format=COMBINED
--real-time-html
-o /var/www/html/stats/realtime.html
--ws-url=wss://YOUR_DOMAIN/goaccess-ws
--port=7890
--daemonize
--pid-file=/var/run/goaccess.pid
--no-global-config
# Confirm the process is running
cat /var/run/goaccess.pid
ps aux | grep goaccess
# Allow WebSocket port through firewalld (only needed if directly exposed)
sudo firewall-cmd --permanent --add-port=7890/tcp
sudo firewall-cmd --reload
Step 5 — Proxy the WebSocket Connection Through Nginx
Rather than exposing port 7890 directly, proxy the WebSocket traffic through Nginx on the standard HTTPS port. Add the following location blocks inside your server block that handles the site.
# Add to your Nginx server block (/etc/nginx/conf.d/your-site.conf)
cat <<'EOF'
# Serve the real-time GoAccess dashboard
location /stats/realtime.html {
alias /var/www/html/stats/realtime.html;
auth_basic "Analytics";
auth_basic_user_file /etc/nginx/.htpasswd;
}
# Proxy GoAccess WebSocket connection
location /goaccess-ws {
proxy_pass http://127.0.0.1:7890;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
proxy_set_header Host $host;
proxy_read_timeout 86400s;
}
EOF
sudo nginx -t && sudo systemctl reload nginx
# Verify WebSocket port is listening locally
ss -tlnp | grep 7890
Step 6 — Automate Static Report Generation with Cron
Schedule a cron job to regenerate the static report daily so stakeholders always have an up-to-date snapshot without depending on the real-time daemon.
# Create a daily report generation script
sudo tee /usr/local/bin/goaccess-report.sh > /dev/null <<'EOF'
#!/bin/bash
set -e
LOGFILE=/var/log/nginx/access.log
OUTDIR=/var/www/html/stats
TMPFILE=$(mktemp /tmp/goaccess-report.XXXXXX.html)
goaccess "$LOGFILE"
--log-format=COMBINED
-o "$TMPFILE"
--no-global-config
mv "$TMPFILE" "$OUTDIR/index.html"
chown nginx:nginx "$OUTDIR/index.html"
EOF
sudo chmod +x /usr/local/bin/goaccess-report.sh
# Add a daily cron job for the root user
echo "0 3 * * * root /usr/local/bin/goaccess-report.sh" |
sudo tee /etc/cron.d/goaccess-report
# Test the script manually
sudo /usr/local/bin/goaccess-report.sh
ls -lh /var/www/html/stats/index.html
Conclusion
GoAccess is now installed on RHEL 8 and generating both static and real-time HTML reports from your Nginx access logs. The static report gives you historical traffic analysis with a single command, while the real-time dashboard streams live data to your browser via a WebSocket connection proxied securely through Nginx. Password-protecting the /stats/ location prevents unauthenticated access to potentially sensitive traffic data.
Next steps: How to Forward Nginx Logs to Elasticsearch with Filebeat on RHEL 8, How to Set Up Prometheus Nginx Exporter on RHEL 8, and How to Configure Log Aggregation with Loki and Grafana on RHEL 8.