Self hosted webstats using goatcounter

Created: by Pradeep Gowda Updated: Nov 04, 2023 Tagged: self-hosting · webstats

I would like to understand how, and who is reading this website and its many pages; mostly to satisfy my own curiosity. But, I do not like to use Google Analytics or similar “free” services because I myself block trackers like that1. A self hosted webstats service keeps the stats on the same server2 as the page the visitor accessed in the first place3.

I have used goatcounter previously, but I used their hosted service. I stopped using them when I felt paying for webstats wasn’t something I cared for.

Recently I discovered that the source code behind the service is open-source - https://github.com/arp242/goatcounter, and I thank Martin Tournoij for open sourcing it. I hope to support the project via github sponsorship sometime.

Goatcounter checks many boxes for the software I want to run myself:

  • easy installation (a single binary)
  • small memory footprint (written using golang)
  • uses sqlite for data storage
  • well documented online and in the console (with -h option)
  • easy discoverability of features.

So, I went ahead and installed it on my server and configured it to serve the tracker as well as dashboard from https://gc.btbytes.com.

I automated the installation using Ansible. I proxied the instance behind my existing nginx webserver. I had to rerun certbot4 to add new letsencrypt provided SSL certificates for the gc.btbytes.com domain.

The actual command to run the server, as configured in the systemd file is as follows:

/usr/local/bin/goatcounter serve -automigrate -listen :5860 \
-tls none -db sqlite+/data/web/gc.btbytes.com/db/goatcounter.sqlite3
  • The automigrate is a nice option that applies migrations on server start - I think this will come in handy when I upgrade the server version and expect the db migrations to be applied automatically
  • setting tls to none allows me to use the nginx SSL termination
  • the db flag points to the sqlite db location.

Tracking visits to each page is easy as adding the following line to the sitebuild script:

<script data-goatcounter="https://gc.btbytes.com/count"
 async src="//gc.btbytes.com/count.js"></script>

  1. I understand if you want to block https://gc.btbytes.com/ youself :)↩︎

  2. It is so in this case and on this website.↩︎

  3. This is an attempt at understanding my website’s traffic while respecting visitor’s privacy.↩︎

  4. sudo certbot certonly --force-renew -d gc.btbytes.com↩︎