logo TeddyDD

Self Hosted Analytics

On the one hand, I wouldn’t feel comfortable using Google Analytics (or any other evil corpo™ service) to track visitors of my website. On the other - I’m curious if anyone actually reads this stuff 🤣.

In best case scenario, one can simply parse server logs to get basic stats. Unfortunately, when hosting on Netlify this is not possible.

I have TinyKVM VPS that I use to host an IRC bouncer. It can handle additional task of collecting statistic from a small website.

I know two self-hosted Google Analytics alternatives:

While Plausible looks amazing, it seems it is more complicated to host and operate. GoatCounter is single binary, written in Go, and stores data in SQLite. Perfect for my use case.

My VPS runs Void Linux (I requested it when creating an account few years back and they immediately added the ISO to available options 😊).

Setup is pretty easy:

sudo xbps-install goatcounter

In /etc/sv/goatcounter/conf

OPTS="-db sqlite+/var/db/goatcounter/db.sqlite3?_busy_timeout=200&_journal_mode=wal&cache=shared"
OPTS="$OPTS  -listen :5000 -public-port 443 -tls none"

Then you have to initialize the database:

sudo -u _goatcounter goatcounter db create -createdb site \
	-user.email 'admin@domain.com' \
	-vhost domain.com \
	-db sqlite+/var/db/goatcounter/db.sqlite3

Now you can start the service

sudo ln -sf /etc/sv/goatcounter /var/service/

I use nginx as reverse proxy and Certbot to manage Let’s Encrypt certificates. GoatCounter has its own subdomain:

server {
    include mime.types;
    server_name analytics.domain.com;
    listen [::]:443 ssl; # managed by Certbot
    listen 443 ssl; # managed by Certbot

    ssl_certificate /etc/letsencrypt/live/analytics.domain.com/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/analytics.domain.com/privkey.pem; # managed by Certbot
    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot

    location / {
        proxy_set_header Host $http_host;
        proxy_set_header X-Forwarded-For $remote_addr;
        proxy_set_header X-Forwarded-Proto $scheme;

        proxy_http_version 1.1;
        add_header X-Clacks-Overhead "GNU Terry Pratchett";
        gzip on;
    location /loader {
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "Upgrade";
        proxy_set_header Host $host;

Integration with Hugo theme is done via calling partial template at the end of body of layouts/_default/baseof.html layout. Partial looks like this:

<script data-goatcounter="https://analytics.domain.com/count"
        async src="//analytics.domain.com/count.js"></script>
    <img src="https://analytics.domain.com/count?p={{ .RelPermalink }}">

Now I can see if anyone visits this website without feeding Google more data.

If you are curious what kind of data is collected then take a look at official GoatCounter’s live demo.

Cheers 🍺