I have been trying to tune down the usage of Google services in my life in the last couple of months.

The monopoly google has regarding the global Internet is simply not healthy and we should be more aware of whom we gave our data. Over the years we very easily traded privacy for convenience without even noticing. At least I did.

So first I switched to protonmail, I started to keep more of my data locally / on my Synology NAS, I tend to use duckduckgo more often. Just add a little bit of diversity to keep things healthy. Unfortunately, I noticed by default I add Google Analytics to all my sites - even tho I have pihole setup locally. Oh, the irony. I talk about privacy and I give the data about my visitors to Google without hesitation. And don’t get me wrong - there is nothing wrong with analytics in general - I mean as an author/contributor you want to know how your content is performing. You have to measure it somehow.

So I started to look for an alternative. There is obviously matomo (former piwik). There is simple, but promising phantom analytics. After some more research, I finally stumbled upon countly.

Matomo seems like a beast that collects waaay too much information about visitors by default, phantom seems too limiting so I went with countly. For personal use it’s more than enough. For professional use? You will be missing some key features (eg. funnels) - which are accessible in enterprise edition tho. But the open-source version gives you a general overview about how your site is performing and which sections are most interesting for your readers.

So, let’s try to use traefik 2.0 to install our analytics then! We will use the suggested mongodb image for our database and configure routing rules for frontend and api based on provided nginx example.

Note: if you’re not familiar with new Traefik syntax checkout my previous blog post about spinning up Traefik 2.x in general.

Below is ansible snippet for creating our database container. For sake of simplicity we will spin single one and point frontend & api to it.

- name: Create a named volume
  docker_volume:
    name: countly

- name: Create countly db container
  docker_container:
    state: started
    name: countly-db
    restart_policy: always
    image: 'bitnami/mongodb:3.6.14'
    ports:
      # aadjust this to your needs, I personally bind port on a
      # private interface as db is kept on a different node
      - '27017:27017'
    env:
      MONGODB_USERNAME: username
      MONGODB_PASSWORD: password
      MONGODB_DATABASE: dbname
      MONGODB_ROOT_PASSWORD: rootpassword
    volumes:
      - 'countly:/bitnami'

Now let’s start with the API part.

- name: Create countly api container
  docker_container:
    name: countly-api
    image: countly/api:19.08.1
    state: started
    restart_policy: always
    expose:
      - 3001
    etc_hosts: >
      {
        "db-host": "{{ I keep mongodb container on a different host and I grab private ip of that host here }}"
      }
    env:
      # what is &w: https://docs.mongodb.com/manual/reference/write-concern/#wc-w
      # change DB-USER, DB-PASSWORD, DB-NAME, DB-PORT according to your mongo credentials
      COUNTLY_CONFIG_API_MONGODB: "mongodb://DB-USER:[email protected]:DB-PORT/DB-NAME?w=1"
      COUNTLY_CONFIG_FRONTEND_MONGODB: "mongodb://DB-HUSER:[email protected]:DB-PORT/DB-NAME?w=1"
    labels:
      traefik.enable: 'true'
      traefik.docker.network: 'traefik'
      traefik.http.routers.router-https-countly-api.rule: 'Host(`countly.mydomain`) && (PathPrefix(`/i/`, `/o/`) || Path(`/i`, `/o`))'
      traefik.http.routers.router-https-countly-api.entrypoints: 'websecure'
      # we set a higher priority here due to PathPrefix & Path matchers
      traefik.http.routers.router-https-countly-api.priority: '2'
      traefik.http.routers.router-https-countly-api.tls.certResolver: 'letsencrypt'
      traefik.http.services.balancer-countly-api.loadbalancer.server.port: '3001'
    networks:
      - name: traefik
    purge_networks: yes

And here goes our final frontend container.

- name: Create countly frontend container
  docker_container:
    name: countly-frontend
    image: countly/frontend:19.08.1
    state: started
    restart_policy: always
    expose:
      - 6001
    etc_hosts: >
      {
        "db-host": "{{ same here thing; change / remove this }}"
      }
    env:
      COUNTLY_CONFIG_API_MONGODB: "mongodb://DB-USER:[email protected]:DB-PORT/DB-NAME?w=1"
      COUNTLY_CONFIG_FRONTEND_MONGODB: "mongodb://DB-HUSER:[email protected]:DB-PORT/DB-NAME?w=1"
    labels:
      traefik.enable: 'true'
      traefik.docker.network: 'traefik'
      traefik.http.routers.router-http-countly-frontend.rule: 'Host(`countly.mydomain`)'
      traefik.http.routers.router-http-countly-frontend.entrypoints: 'web'
      traefik.http.routers.router-http-countly-frontend.middlewares: '[email protected]'
      traefik.http.routers.router-https-countly-frontend.rule: 'Host(`countly.mydomain`)'
      traefik.http.routers.router-https-countly-frontend.entrypoints: 'websecure'
      traefik.http.routers.router-https-countly-frontend.priority: '1'
      traefik.http.routers.router-https-countly-frontend.tls.certResolver: 'letsencrypt'
      # If you want to throw some basic auth for your front-end in the mix:
      # traefik.http.middlewares.countly-auth.basicauth.users: '/generate with htpasswd/'
      # traefik.http.routers.router-https-countly-frontend.middlewares: '[email protected]'
      traefik.http.services.balancer-countly-frontend.loadbalancer.server.port: '6001'
    networks:
      - name: traefik
    purge_networks: yes

And that’s it - once you visit countly.mydomain you should be prompted to create an admin account and add your first website.

Part of countly's dashboard. Data from one of my projects.