+++ date = '2025-10-06T01:00:51+02:00' title = 'Goaccess install on NixOs' tags = [ "nixos","statistics" ] +++ When you self-host, there comes a moment when curiosity takes over. Who visits my site? At what time? Which pages actually get attention? And, sooner or later, the big question: Is anyone, anywhere, really reading what I write? You could go for Google Analytics or Matomo — but that comes with its own baggage: - Questionable privacy practices, - Third-party scripts injected into your site, - Extra weight on every page, - And a dependency on services I don’t want. GoAccess, on the other hand, takes the minimalist route. No scripts, no tracking, no cookie banner — it reads directly from the web server logs (in my case, Caddy) and generates a clear, efficient report. That’s the kind of philosophy I like: - Privacy-friendly — nothing leaves my server, no profiling. - Simple — I don’t touch my site, I just process the logs. - Fast — one command and I instantly see who visited and how. - Self-hosting friendly — no database, no bloated setup. In short, GoAccess fits perfectly with what I look for in my homelab: → Getting visibility into my services without turning it into a Rube Goldberg machine. ⸻ Minimal setup on NixOS GoAccess is available directly from the official repository. I just added the package and a small systemd service to generate a static report every hour: ``` {pkgs, ...}: { environment.systemPackages = with pkgs; [ goaccess ]; # Service for generation the GoAccess static report systemd.services.goaccess-report = { description = "Generate GoAccess HTML report"; serviceConfig = { ExecStart = "${pkgs.goaccess}/bin/goaccess /var/log/caddy/access-levr.porzh.me.log --log-format=CADDY -o /var/www/goaccess/index.html"; }; }; # Timer to regénérate the report every hour systemd.timers.goaccess-report = { description = "Hourly GoAccess report generation"; wantedBy = ["timers.target"]; timerConfig = { OnCalendar = "hourly"; Persistent = true; }; }; services.caddy = { virtualHosts = { "koum.porzh.me" = { extraConfig = '' root * /var/www/goaccess file_server browse try_files {path} {path}/ /index.html ''; }; }; }; } ``` What’s next? In the second part, I’ll go a bit further: - filtering out local network IPs, - generating daily, weekly, and monthly reports, - and explaining why I chose not to use the “live” mode. Because yes — even analytics deserve a bit of restraint.