From 3c37fa72931b15236aadbea869894290a4070cc3 Mon Sep 17 00:00:00 2001 From: Jake Howard Date: Wed, 5 Aug 2020 17:14:30 +0100 Subject: [PATCH] Add post about self-hosting plausible --- content/posts/self-hosting-plausible/index.md | 91 ++++++++++++++++++ .../plausible-login.png | Bin 0 -> 27435 bytes 2 files changed, 91 insertions(+) create mode 100644 content/posts/self-hosting-plausible/index.md create mode 100644 content/posts/self-hosting-plausible/plausible-login.png diff --git a/content/posts/self-hosting-plausible/index.md b/content/posts/self-hosting-plausible/index.md new file mode 100644 index 0000000..4632b42 --- /dev/null +++ b/content/posts/self-hosting-plausible/index.md @@ -0,0 +1,91 @@ +--- +title: Self hosting Plausible +date: 2020-08-05 +image: resource:plausible-login.png +subtitle: Simple and privacy-friendly alternative to Google Analytics +--- + +I only recently talked about using [GoAccess]({{< relref "goaccess-analytics" >}}) as an analytics tool. Over the last couple months, I've been more interested in how many hits this website actually gets. GoAccess was a really simple solution which worked on log files and only captured the bits of information I really cared about: Page views. + +After hearing about it on [Changelog](https://changelog.com/podcast/396), I looked into [Plausible](https://plausible.io/). It's much more powerful than GoAccess, and is actually designed for analytics. And because it's working in the browser, I don't have to ignore all the static paths to stop them showing up in the analytics. + +## Why Plausible + +Google Analytics is the current go-to solution for analytics, but it's a non-starter for me due to privacy concerns. The fewer sites collecting information for Google, the better! Plausible positions itself directly as a GDPR-compliant, privacy-driven analytics platform. + +Plausible is pretty new to the scene, But what it's achieved in that time is quite remarkable. There's now a functional, simple analytics platform, which collects only the data needed, and isn't tied to a huge company like Google. + +[Plausible vs Google Analytics](https://plausible.io/vs-google-analytics) + +Plausible's primary offering is a hosted version, but in the last few weeks the option to self-host has been available. The hosted option is rock-solid, running on [renewable energy](https://plausible.io/blog/made-in-eu), and definitely recommended if you don't want to faff for yourself. Using the hosted version also financially supports the project, and ensures it stays around. + +## Installation + +The current options are to compile and run the Elixir application yourself, or use [Docker](https://hub.docker.com/r/plausible/analytics). My servers already run Docker, so that was a simple decision! In the Plausible repository, there's a `docker-compose.yml` - Don't use it. It's intended more as a reference to what's needed for setup rather than to be used directly. However, from this we can see we need a couple containers: + +- [Plausible](https://hub.docker.com/r/plausible/analytics) itself, obviously +- [PostgreSQL](https://hub.docker.com/_/postgres), for the application database +- [Clickhouse](https://hub.docker.com/r/yandex/clickhouse-server), for the analytics database + + +{{}} +A cautionary tale for installing Clickhouse. I'd intended to run it on a reasonably old machine (Intel Atom N2800), and due to a requirement on a specific instruction set ([SSE4](https://en.wikipedia.org/wiki/SSE4)), it wouldn't start. Chances are this won't affect you if you're running a server even remotely modern, but something to note. +{{}} + +### Setup and configuration + +Fortunately, configuring Plausible is actually really simple and the settings are pretty obvious. There's a [hosting README](https://github.com/plausible/analytics/blob/master/HOSTING.md) in the repository which should definitely be read. Here's what I have set up for Plausible: + +```yaml +environment: + - SECRET_KEY_BASE={{ secret_key }} + - SIGNING_SALT={{ signing_salt }} + - DATABASE_URL=postgres://plausible:plausible@db:5432/plausible + - DISABLE_REGISTRATION=true + - DISABLE_SUBSCRIPTION=true + - CLICKHOUSE_DATABASE_HOST=clickhouse + - CLICKHOUSE_DATABASE_NAME=plausible + - DATABASE_POOL_SIZE=20 + - CLICKHOUSE_DATABASE_POOLSIZE=20 + - HOST={{ plausible_host }} + - SCHEME=https +``` + +`$DISABLE_REGISTRATION` and `$DISABLE_SUBSCRIPTION` are both pretty handy. These prevent other users from signing up to your instance, and stop showing anything to do with subscriptions. For now, the self hosted Plausible comes with a 100-year subscription for admin users, which is very gracious. + +`$SECRET_KEY_BASE` and `$SIGNING_SALT` should be kept private at all costs. There's little documentation on what these should be or how to generate them, but according to Phoenix `$SECRET_KEY_BASE` should be at least 64 bytes. `$SIGNING_SALT` just needs to be something reasonably complex, but I used 16 bytes for ease. I used `openssl rand -hex ` to securely generate these keys. + +Here's my full [`docker-compose.yml`](https://github.com/RealOrangeOne/infrastructure/blob/master/ansible/roles/plausible/files/docker-compose.yml) for reference. + +### Migration and admin setup + +This is the point we diverge pretty hard from what's defined in both the `docker-compose.yml` and `HOSTING.md` from Plausible. The instructions there note a `setup` container, which is used to initialize Plausible, but then shouldn't be run afterwards. Personally I don't like this pattern, I'd rather the compose file contain exactly what's needed to run the application, no more no less. Instead, we need to set up the databases manually: + +1. Start up everything except Plausible itself (`docker-compose up -d db clickhouse`) +2. Enter the Plausible container (`docker-compose run plausible sh`) +3. Run migrations (`/entrypoint.sh db migrate`) +4. Define your user credentials as environment variables: + - `$ADMIN_USER_NAME` + - `$ADMIN_USER_EMAIL` + - `$ADMIN_USER_PWD` +5. Create your admin user (`/entrypoint.sh db init-admin`) + +These steps only need to be done once, during application setup. After this, the command must be changed to automatically run migrations on start up. This ensures the database schema and running application are always in sync, and are updated with the container. This can be done by changing the `docker-compose.yml` [like so](https://github.com/RealOrangeOne/infrastructure/commit/384a07b513e42942625df07184ae502957d41013). + +Once the migrations have run, stop all the containers (`docker-compose down`), and start the all up as normal (`docker-compose up -d`). + +At this point, Plausible should be accessible (however that's configured). + +![Plausible login screen](plausible-login.png) + +## Installing into website + +Now that Plausible is up and running. + +The next steps are actually setting it up on your website, by far the easiest step! Plausible has some great documentation on both [creating a site](https://docs.plausible.io/add-website) and [adding the tracker script to your website](https://docs.plausible.io/plausible-script), so there's no point duplicating that here. + +Here's how I [added Plausible to this site](https://github.com/RealOrangeOne/theorangeone.net/commit/f87466090e70b819370ef57aa4fd5cd1acefb95a), and then [promptly fixed](https://github.com/RealOrangeOne/theorangeone.net/commit/3ce9f709fbbdb1e986f5ef3c5cadb6ea8cc76002). + +## Success + +If all's gone according to plan you should now see page hits being tracked by Plausible, running on your own server. Amazing! diff --git a/content/posts/self-hosting-plausible/plausible-login.png b/content/posts/self-hosting-plausible/plausible-login.png new file mode 100644 index 0000000000000000000000000000000000000000..503d679650d5641f9dbe93d5d094d43d5d577264 GIT binary patch literal 27435 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
ou~2 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