-- Leo's gemini proxy

-- Connecting to nox.im:1965...

-- Connected

-- Sending request

-- Meta line: 20 text/gemini; charset=utf-8

Static Site Generator for Web Analytics Dashboards


With Google Analytics, you allow Big Tech to monetize your visitors. Privacy and minimalism doesn't mix well with tracking, privacy intrusions and bloated Javascript clients. Server side analytics utilize only log files for basic insights into visitors and hits. GoAccess[1] is one such tool that does log file parsing and deals with the presentation of the data that we use in the following.


1: GoAccess


Unlike the name suggests, GoAccess isn't written in Go, but C. The tradeoff with log parsing is that we don’t get nearly as much information as Google Analytics-style system. There’s no screen sizes, no time-on-page metrics, etc, but it doesn't require any Javascript, no cookie or GDPR notice and is sufficient for most use cases.


GoAccess static HTML for nox.im[1]


1: GoAccess static HTML for nox.im


The setup consists of an OpenBSD httpd web server[1], a Tor Onion hidden service[2] and the Gemini protocol gmifs server[3], from previous articles. All of these produce logs which we can combine in a single, statically generated HTML dashboard that we serve publicly under `/stats/`. That's right, with everything else being open on this web log I do publish my web analytics with anonymized IPs, except for crawlers, publicly.


1: OpenBSD httpd web server

2: Tor Onion hidden service

3: Gemini protocol gmifs server


httpd logs


Ensure you have set the log style to combined, an extension to Common Log Format[1] with referrer and user-agent fields for our primary www server.


1: Common Log Format


server "nox.im" {
    ...
    log style combined

Log the hidden service access logs into a custom file, naturally we won't get IP address or referrers from Tor.


server "noximhkcqevri46e2kuthman5o6emplfcevppx3hvsvu55qcygj5elyd.onion" {
    ...
    log access onion.log

Gemini gmifs[1] logs are under `/var/www/logs/gemini/access.log`. We don't get http status codes but can ingest hits for Gemini. For this I now log with a `gemini.nox.im` prefix to get the hostname right.


1: gmifs


GoAccess


Install GoAccess


pkg_add goaccess

Edit `/etc/goaccess/goaccess.conf` for global configuration. The primary www web server has these settings:


# httpd(8) combined log format
date-format %d/%b/%Y
time-format %T %z
log-format %v %h %^ %^ [%d:%t] "%r" %s %b "%R" "%u"
# privacy for visitors identities
anonymize-ip true
# keep stats between runs
persist true
restore true
# ignore some panels I don't need
ignore-panel VISIT_TIMES
ignore-panel VIRTUAL_HOSTS
ignore-panel STATUS_CODES

I copy the file to `/etc/goaccess/goaccess.gmi.conf` and `/etc/goaccess/goaccess.onion.conf`.


For the hidden service I'm using the same combined log format above. For `gmifs@1.0.2` I'm using the common log format and exclude the status code:


# httpd(8) common log format
date-format %d/%b/%Y
time-format %T %z
log-format %v %h %^ %^ [%d:%t] "%r" %^ %b

All other options will be set with command line arguments.


Stats Database


We will keep all stats under `/var/db/goaccess/nox.im/`.


mkdir -p /var/db/goaccess/nox.im
chown daemon /var/db/goaccess/nox.im

Script and Periodic Updates


I copy the following script to `/usr/local/bin/goaccess-nox.im`. Note that I'm excluding the IP of the box that runs this blog as well as localhost for the hidden service hits. I'm also excluding my static exit IPs from my WireGuard VPN[1], not listed here.


1: WireGuard VPN


doas vi /usr/local/bin/goaccess-nox.im
doas chmod +x /usr/local/bin/goaccess-nox.im

#!/bin/sh

/usr/local/bin/goaccess $1 \
  -p $2 \
  -o /var/www/htdocs/nox.im/stats/index.html \
  --exclude-ip 127.0.0.1 \
  --exclude-ip 45.76.221.230 \
  --db-path=/var/db/goaccess/nox.im \
  --html-report-title="nox.im stats"

And run it with an `@hourly` cron for the www, the hidden service and the gemini server:


# vi /var/cron/tabs/root

0 * * * * /usr/local/bin/goaccess-nox.im /var/www/logs/access.log /etc/goaccess/goaccess.conf > /dev/null 2>&1
0 * * * * /usr/local/bin/goaccess-nox.im /var/www/logs/onion.log /etc/goaccess/goaccess.onion.conf > /dev/null 2>&1
0 * * * * /usr/local/bin/goaccess-nox.im /var/www/logs/gemini/access.log /etc/goaccess/goaccess.gmi.conf > /dev/null 2>&1

In order to ensure we generate the report before log rotations executes, prefix the entries in `/etc/newsyslog.conf`:


/var/www/logs/access.log			644  4     *    $W0   Z "/usr/local/bin/goaccess-nox.im /var/www/logs/access.log /etc/goaccess/goaccess.conf && pkill -USR1 -u root -U root -x httpd"
/var/www/logs/gemini/access.log		644  4     *    $W0   Z "/usr/local/bin/goaccess-nox.im /var/www/logs/gemini/access.log /etc/goaccess/goaccess.gmi.conf && pkill -USR1 -u root -U root -x gmifs"

Boom. We now get quite exhaustive web stats statically generated at `/stats/`.


-- Response ended

-- Page fetched on Sat Apr 27 21:42:57 2024