Goatcounter on fly.io
Yet another container running on fly.io, this time a web analytics platform called goatcounter, backed by a LiteStream replication for disaster recovery.
This time I’ve setup a repository (inspired by fspoettel/linkding-on-fly) for setting this up, which was a lot of fun! I hope this might be useful for someone else.
I’ve been running goatcounter for my two blogs for a few months, and it’s been great on the free tier (1 shared CPU, 256 MB of RAM). Sure, my blog doesn’t receive a lot of visitors1 but if you need performance, you are probably not looking at the fly.io free tier :-)
Overview #
This setup works like this:
- Goatcounter runs as a FireCracker vm on fly.io, backed by a SQLite database2
- LiteStream wraps the goatcounter process3 and continuously reads and backs up the wal to a S3 compatible storage
If our flyio volume would die, or we would migrate to another VM
provider, we should be able to automatically restore our data to the
new host. I’ve tried to write entrypoint.sh
to do this
automatically, and through my happy testing this seems to work. :-)
Beyond that, I think I’ve outlined the procedure in the project readme, which I’ll just copy in below.
Prerequisites #
- A fly.io account
- An account with a S3 (compatible) storage provider, with a bucket already setup & credentials at hand (see this tutorial for Backblaze specific instructions)
- flyctl CLI installed
Usage #
Clone or fork this repository.
git clone https://github.com/oscarcarlsson/goatcounter-on-fly.git && cd goatcounter-on-fly
Run the command below and answer the questions - you don’t need Redis nor Postgres! This will generate a
fly.toml
but won’t try to launch anything yet. Make sure you change the name for the application as well.flyctl launch --no-deploy --memory 256 --name CHANGEME
If you want, you can always specify the region to launch the VM in. You can list all regions by running:
flyctl platform regions
Create a volume for the database, change to your preferred region:
flyctl volumes create goatcounter_data --region CHANGEME --size 1
Open
fly.toml
and add the following to the env section:[env] # Change these! GOATCOUNTER_DOMAIN = 'goatcounter.example.com' GOATCOUNTER_EMAIL = 'john.doe@example.com' # Change these for your S3 provider! LITESTREAM_REPLICA_ENDPOINT = '' LITESTREAM_REPLICA_BUCKET = '' # These can be blank GOATCOUNTER_SMTP = '' GOATCOUNTER_DEBUG = '' # Don't change these GOATCOUNTER_LISTEN = '0.0.0.0:8080' GOATCOUNTER_DB = '/data/goatcounter.sqlite3' LITESTREAM_REPLICA_PATH = 'goatcounter_replica.sqlite3'
Also make sure that the mount section looks something like this:
[[mounts]] source = 'goatcounter_data' destination = '/data' processes = ['app']
Nearly done! Now, create secrets for your secrets:
flyctl secrets set GOATCOUNTER_PASSWORD="changeme" LITESTREAM_ACCESS_KEY_ID="changeme" LITESTREAM_SECRET_ACCESS_KEY="changeme"
The secret called
GOATCOUNTER_PASSWORD
will be the initial password for theadmin
account.Now, try to deploy the application!
flyctl deploy && flyctl logs
If nothing goes wrong, visit your goatcounter instance and login using admin and the password you’ve set using the
GOATCOUNTER_PASSWORD
secret.
Hugo integration #
Exactly how you plug this into your theme will be left as an exercise for the reader, but what you need to do is include below in your header somehow:
<!-- Replace with your goatcounter DNS... -->
<script data-goatcounter="https://stats.monotux.tech/count" async src="//stats.monotux.tech/count.js"></script>
In my custom theme I have a configuration parameter called
customJS
, into which I’ve just added the above.
Conclusion #
Hopefully this might help someone else to setup a goatcounter instance on fly.io.
At least I know how few visitors I go get :-) ↩︎
This is persisted to a FlyIO volume, even though we in theory could skip this as the data is easy to automagically restore from backups! ↩︎
As described in the LiteStream documentation for running everything in one container ↩︎