A privacy respecting approach

Umami Infrastructure

Umami is the tool I’m using for collecting and viewing the user analytics. My needs are simple—I just want to know how popular I am.

Some prior infrastructure that is already setup is Kubernetes, Flux, Nginx Ingress, Certificates, and Hugo. I’ll get to posts describing the full setup at some time. In my git repo I have the following files for Umami

1
2
3
4
.
├── kustomization.yaml
├── umami-secrets.yaml
└── umami.yaml

The file kustomization.yaml is simple and is just a reference to the other two. umami-secrets.yaml is an opaque secret encrypted using sops. Unencrypted it has the following contents.

1
2
3
4
5
6
7
8
apiVersion: v1
kind: Secret
metadata:
    name: umami
    namespace: public
type: Opaque
stringData:
    DB_CONNECTION_STRING: postgres://umami:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx@postgresql.data.svc.cluster.local:5432/umami?sslmode=disable

Note that I manually created the postgres user and database with values that match the connection string above.

umami.yaml has the following contents

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
---
apiVersion: helm.toolkit.fluxcd.io/v2beta1
kind: HelmRelease
metadata:
  name: &app umami
  namespace: public

spec:
  interval: 15m
  chart:
    spec:
      chart: umami
      version: 1.20.1
      interval: 15m
      sourceRef:
        kind: HelmRepository
        name: christianknell
        namespace: flux-system

  values:
    umami:
      removeDisableLoginEnv: true
      trackerScriptName: analytics
      hostname: &host analytics.${SECRET_DOMAIN2}

    database:
      existingSecret: *app
      databaseUrlKey: DB_CONNECTION_STRING

    postgresql:
      enabled: false

    ingress:
      enabled: true
      hosts:
        - host: *host
          paths:
            - path: /
              pathType: Prefix

      tls:
        - secretName: wildcard2-cert-tls
          hosts:
            - *host

Values for trackerScriptName and hostname will need to be changed to dodge ad blockers. Use the data only for good, not evil.

Shoutout to christianknell for the helm chart.

Umami Setup

Navigate to the URL defined in the above ingress definition. Default username is admin and the default password is umami. Change these ASAP.

Go to the settings and add a website:

Hugo add website screenshot

Once that is done, click on the code button to get the data you need for the next part.

Analytics in Hugo

How to do this will depend on the theme. I’m using the PaperMod theme and here’s how I did the next part.

First, I created a partial file. Hugo will look in this directory and overwrite the contents of your theme with what is in here. PaperMod has extend_head.html for custom header resources like this.

1
2
3
layouts
└── partials
    └── extend_head.html

Contents of extend_head.html are

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
{{ if and .Site.GoogleAnalytics (not .Site.IsServer) }}
{{ template "_internal/google_analytics.html" . }}
{{ else if and .Site.Params.umami.enabled (not .Site.IsServer) }}
<script
  async
  defer
  data-website-id="{{ .Site.Params.umami.websiteId }}"
  src="{{ .Site.Params.umami.jsLocation }}"
></script>
{{ end }}

The parameters referenced there are defined in Config.toml

1
2
3
4
[params.umami]
enabled = true
websiteId = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
jsLocation = "https://analytics.telnetlocal.host/analytics.js"

This data comes from the Umami settings for the website. And, now after visiting the website I go back to umami and see it working:

Umami

Conclusion

Not very popular.