GoAccess turns Apache and Nginx access logs into an interactive terminal dashboard or a standalone HTML report. It is useful for checking traffic, popular URLs, status codes, referrers, browsers, and client addresses without first shipping logs to another service. Because it reads the access log directly, the web server must already be logging requests in a format GoAccess understands.
Install GoAccess and verify it
On Debian or Ubuntu, install the distribution package:
sudo apt update
sudo apt install goaccess
On Fedora or a RHEL-compatible system with a repository that provides GoAccess, use:
sudo dnf install goaccess
macOS users can install it with brew install goaccess. Distribution packages may not contain the newest upstream release, but they are usually the simplest way to receive security and packaging updates.
Confirm that the command is available:
goaccess --version
Running goaccess without arguments also prints its basic usage and options.
Find the real access log
GoAccess analyzes access logs, not error logs. Common paths are:
- Apache on Debian/Ubuntu:
/var/log/apache2/access.log - Apache on RHEL-compatible systems:
/var/log/httpd/access_log - Nginx:
/var/log/nginx/access.log
Virtual hosts often use separate files, so check the CustomLog directive in Apache or access_log directive in Nginx rather than assuming the default. Use sudo ls -l on the path if your normal user cannot read it. Prefer read-only group access for a dedicated reporting user over running a long-lived dashboard as root.
Check for the COMBINED format
A typical Nginx combined or Apache LogFormat ... combined entry contains the client address, request time, request line, status, response size, referrer, and user agent:
192.0.2.10 - - [17/Oct/2026:10:15:30 +0000] "GET / HTTP/1.1" 200 1024 "-" "Mozilla/5.0"
The built-in COMBINED setting matches this layout. It is not a universal option: if an administrator adds a virtual-host name, changes field order, or removes fields, you must supply a custom format instead.
Monitor logs in the terminal
For Apache on Debian/Ubuntu, run:
sudo goaccess -f /var/log/apache2/access.log --log-format=COMBINED
For Nginx, change the path:
sudo goaccess -f /var/log/nginx/access.log --log-format=COMBINED
The -f option selects the input file. The terminal dashboard parses the existing entries and updates as new requests arrive. Scroll through the panels to inspect requested files, 404s, visitor hosts, operating systems, and browsers; press q to exit.
Treat visitor numbers as an approximation, not a count of people. Network address translation, shared connections, changing addresses, and bots all affect the result.
Create HTML reports
For a static report, use -o with an .html filename rather than relying on shell redirection:
sudo goaccess -f /var/log/nginx/access.log \
--log-format=COMBINED -o goaccess-report.html
Open the resulting file in a browser, or copy it to a suitably protected reporting directory. A static report does not refresh itself; rerun the command or schedule a carefully permissioned reporting job to update it.
GoAccess can also update HTML in real time:
sudo goaccess -f /var/log/nginx/access.log \
--log-format=COMBINED --real-time-html \
--addr=127.0.0.1 --port=7890 -o /srv/goaccess/report.html
This starts GoAccess's WebSocket service on loopback. Remote publication needs additional configuration: proxy both the report and WebSocket through an authenticated TLS endpoint and set --ws-url when the browser-facing address differs. Do not simply expose port 7890 to the internet.
Analyze multiple or rotated logs
To include yesterday's uncompressed rotation alongside the current Nginx log, pass both files, oldest first:
sudo goaccess /var/log/nginx/access.log.1 \
/var/log/nginx/access.log --log-format=COMBINED
This is helpful when an incident crosses midnight or a rotation boundary. Only combine logs that belong together; merging several virtual hosts makes their traffic look like one site. Check rotations for overlap or missing periods, and do not assume every .gz file can be read by your particular build.
Use a custom log format
For an Nginx-style combined layout, the long-form equivalent is:
sudo goaccess -f /var/log/nginx/access.log \
--log-format='%h %^[%d:%t %^] "%r" %s %b "%R" "%u"' \
--date-format='%d/%b/%Y' --time-format='%H:%M:%S'
Here %h is the client host, %r the request, %s the status, %b the response bytes, %R the referrer, and %u the user agent. %d and %t parse date and time, while %^ skips unneeded text. If your server adds $request_time or another field, account for it in the format string. Test against a small sample before processing years of logs.
Troubleshooting and common mistakes
- Permission denied: verify the path and grant read-only access; avoid making logs world-readable.
-
“Nothing valid to process” or zero parsed hits: the log, date, or time format probably does not match. Confirm you selected an access log, then test with
sudo tail -n 100 /var/log/nginx/access.log | goaccess - --log-format=COMBINED. - Unexpectedly large or small totals: check for overlapping rotations, missing logs, health checks, and bot traffic.
- A stale or disconnected HTML dashboard: static HTML never live-updates. For real-time HTML, check that GoAccess is still running and that the WebSocket is reachable through any proxy.
Protect reports containing visitor data
Access-log reports can reveal IP addresses, visited URLs, query strings, referrers, and user agents. Query strings may even contain reset tokens or other sensitive values. Treat the HTML as confidential operational data, not a public analytics page.
Keep reports out of an unauthenticated web root. Restrict file and directory permissions, require authentication and TLS when serving them, limit network access, and delete reports when they are no longer needed. Binding a real-time service to loopback and restricting direct access to its port prevents a protected web page from being undermined by an open backend.
Conclusion
GoAccess is a practical way to inspect web traffic directly on a server. Start with the correct access log and COMBINED format, move to custom parsing only when needed, and apply the same access controls to its reports that you would to the underlying logs.
Top comments (0)