Five-Minute Traffic Reports
There’s a traffic analytics dashboard for this server that has zero runtime overhead. No JavaScript tracking pixels, no database, no always-on daemon. It’s a static HTML file that gets regenerated every five minutes by a cron job.
How it works
- A cron job runs every 5 minutes
- The script copies Traefik’s access log out of the proxy container
- GoAccess processes the log and generates a self-contained HTML report
- The report is served as a static file through nginx
That’s it. The report shows visitors, requests, referrers, 404s, response codes, bandwidth — all the standard web analytics, rendered as an interactive HTML page with client-side sorting and filtering. No server-side processing at view time.
The incremental trick
GoAccess supports persistent databases for incremental processing. Instead of re-parsing the entire access log on every run, it stores state between runs and only processes new entries. This makes the 5-minute cron job fast even as the log grows.
The database files live in a dedicated directory and are persisted/restored on each run. First run processes everything; subsequent runs process only what’s new since the last run.
Why not a real analytics platform?
Because this server doesn’t need one. The sites served here are small business sites, documentation wikis, and application backends. The questions we need answered are simple: “Is anyone hitting the site?” “Are there unusual 404 patterns?” “Is a bot hammering us?”
GoAccess answers all of those from access logs that already exist. Adding Plausible, Umami, or Matomo would mean another container, another database, another piece of software to update — all to answer questions that a log parser handles perfectly.
The log format detail
Traefik writes access logs in Combined Log Format (CLF) with some extra fields. GoAccess needs to be told the exact format to parse correctly. Getting the format string wrong produces a report full of “(null)” entries and phantom visitors.
The format string is configured once and never touched again. But that initial configuration is a 15-minute exercise in counting fields and matching delimiters. There’s no “auto-detect” that works reliably across different reverse proxy log formats.
The serving trick
The generated index.html is mounted read-only into the admin panel’s nginx container. A location alias maps /admin/traffic/ to the report file. No PHP, no proxy, no dynamic content — nginx serves a static HTML file that happens to contain interactive JavaScript charts.
Total ongoing cost: one cron job, ~2 seconds of CPU every 5 minutes, and a 2MB HTML file. For a complete traffic dashboard, that’s hard to beat.