solar/umami-operations-guide.md

9.7 KiB
Raw Permalink Blame History

Umami Analytics Operations & Integration Guide

This document explains how we run our selfhosted Umami analytics at https://analytics.degelas.be, how to integrate new sites/domains, and how to define custom events, goals, and reports. It is written so another server/agent can reproduce the setup.


1. Architecture overview

  • Umami app: Docker container umami, image ghcr.io/umami-software/umami:postgresql-latest.
  • Database: Docker container umami-db, image postgres:16-alpine.
  • Reverse proxy: Existing Nginx proxy stack in fullstack_degelas (container degelas_nginx).
  • Public URL: https://analytics.degelas.be (served by degelas_nginx, proxied to umami by container name).
  • TLS: Single Lets Encrypt certificate for degelas.be that now includes:
    • degelas.be, www.degelas.be, glenn.degelas.be, maite.degelas.be, analytics.degelas.be.

All analytics script tags on our sites point to https://analytics.degelas.be/script.js.


2. Umami stack (docker-compose)

Location: solar_trading_engine/umami-docker-compose.yml

Key points:

  • Creates umami-db (Postgres) and umami (Umami server).
  • Uses an .env file (umami.env) for DB credentials and secrets.
  • Attaches umami to both:
    • A private network umami-net (for DB),
    • The shared external network fullstack_degelas_proxy so Nginx can reach it by container name umami.

To (re)start the stack on a server:

cd /root/solar_trading_engine
docker compose --env-file umami.env -f umami-docker-compose.yml up -d

Check containers:

docker compose -f umami-docker-compose.yml ps

3. Environment configuration (umami.env)

Location: solar_trading_engine/umami.env (not committed; umami.env.example is the template).

Required values:

  • UMAMI_DB_NAME, UMAMI_DB_USER, UMAMI_DB_PASSWORD
    • Strong password; used by umami-db and umami.
  • UMAMI_APP_SECRET
    • Random secret, generated with:
    • openssl rand -hex 32
  • UMAMI_WEBSITE_URL
    • Canonical analytics URL, e.g. https://analytics.degelas.be.

On a new server:

  1. Copy umami.env.exampleumami.env.
  2. Fill in strong values for the password and secret.
  3. Set UMAMI_WEBSITE_URL to the correct domain.

4. Nginx proxy integration (analytics.degelas.be)

The global proxy stack lives in fullstack_degelas/ with docker-compose.yml and Nginx config under nginx/.

4.1 Networks

  • fullstack_degelas creates an external Docker network fullstack_degelas_proxy.
  • Our degelas (solar trading) stack and maite stack join this network.
  • umami also joins this network to allow:
    • degelas_nginxproxy_pass http://umami:3000;

4.2 Nginx vhost for analytics

Location: fullstack_degelas/nginx/conf.d/analytics.degelas.be.conf

Behavior:

  • Listens on 80/443 for analytics.degelas.be.
  • Serves ACME challenges via /var/www/certbot.
  • Redirects HTTP → HTTPS.
  • On HTTPS, proxies to http://umami:3000 using the shared Docker network.

After changing Nginx configuration:

cd /root/fullstack_degelas
docker compose up -d          # ensure nginx + certbot are running
docker compose exec nginx nginx -s reload

5. Certificates (Lets Encrypt)

The fullstack_degelas stack runs a certbot container that:

  • Stores certs under /etc/letsencrypt.
  • Uses the webroot /var/www/certbot for HTTP-01 challenges.
  • Has a single certificate degelas.be that includes:
    • degelas.be, www.degelas.be, glenn.degelas.be, maite.degelas.be, analytics.degelas.be.

To inspect certificates:

cd /root/fullstack_degelas
docker compose exec certbot certbot certificates

To add an extra domain (e.g. analytics.degelas.be) without changing others:

docker compose exec certbot certbot certonly \
  --webroot -w /var/www/certbot \
  --expand \
  -d degelas.be \
  -d www.degelas.be \
  -d glenn.degelas.be \
  -d maite.degelas.be \
  -d analytics.degelas.be

Then reload Nginx:

docker compose exec nginx nginx -s reload

If you reproduce this on another server, adjust the -d list to match the domains you want on the shared cert.


6. Frontend integration (tracking script)

For degelas.be we inject the Umami script in solar_trading_engine/frontend/index.html:

<script
  async
  src="https://analytics.degelas.be/script.js"
  data-website-id="c7ba71c0-4bac-48d3-a8e3-7fdc92a6e4ba"
  data-domains="degelas.be"
></script>

Key fields:

  • src: always points to the Umami instance, https://analytics.degelas.be/script.js.
  • data-website-id: UUID for the specific website in Umami (per-site).
  • data-domains: comma-separated list of hostnames this Umami site should accept, e.g. degelas.be or degelas.be,www.degelas.be.

For new domains:

  1. In Umami, create a new website for that domain.
  2. Copy its Website ID.
  3. On that domains frontend, add a script tag pointing to https://analytics.degelas.be/script.js with the new website ID and correct data-domains.

Example for example.com:

<script
  async
  src="https://analytics.degelas.be/script.js"
  data-website-id="NEW-WEBSITE-ID-FROM-UMAMI"
  data-domains="example.com"
></script>

You can also use one website ID for multiple domains by listing them all in data-domains and in the Umami UI.


7. Custom events from the frontend

We added a small helper in solar_trading_engine/frontend/src/umami.ts:

  • It exposes a safe trackEvent function that calls window.umami.track(...) when available.
  • It fails silently if Umami is disabled or not loaded, so analytics never breaks the app.

Usage in React code:

import { trackEvent as trackUmamiEvent } from './umami'

// Example: when user runs a trading simulation
trackUmamiEvent('trading_sim_run', {
  country: 'BE',
  plan: 'battery',
})

// Example: when user visits a special page (in addition to normal pageview)
trackUmamiEvent('view_log_page', { section: 'activity' })

Notes:

  • The event name is the first argument (string).
  • The optional second argument is a keyvalue object (string/number/boolean) and appears in Umami as event properties.

8. Goals in Umami

Goals are configured in the Umami UI, not in code.

For each website:

  1. Open Umami → Settings → Websites → [website] → Goals.
  2. Click Add goal and choose:
    • Event goal: triggered by a custom event name, e.g. signup_completed, trading_sim_run.
    • Pageview goal: triggered when a specific URL or path is viewed, e.g. /contact/success.
  3. Save.

From that point:

  • Every time code calls trackUmamiEvent('signup_completed', {...}), the corresponding goal increments.
  • For pageview goals, any visit to the configured path increments the goal.

9. Reports & dashboards

Umamis built-in UI allows:

  • Filtering by date range, country, referrer, event name, etc.
  • Viewing:
    • Pages: top URLs and their metrics.
    • Events: your custom events and their counts.
    • Goals: conversion counts and rates.

Workflow for useful reports:

  1. Decide on key events/goals, e.g.:
    • signup_started, signup_completed
    • trading_sim_run
    • battery_config_saved
  2. Implement them in code using trackUmamiEvent.
  3. Define goals in Umami based on those events or URLs.
  4. In the Events/Goals views, filter by:
    • Country (e.g. Belgium vs. others),
    • Referrer (e.g. google, maite.degelas.be),
    • Device, etc.
  5. Use Umamis “save view” or dashboard features (depending on version) to keep common filters.

10. Geo stats (country/region/city)

We keep GeoIP lookups local to preserve privacy and avoid external dependencies.

On the server (see umami-geoip.md for more detail):

  1. Download a local GeoIP database (e.g. MaxMind GeoLite2-City).
  2. Mount it into the Umami container (e.g. /geoip/GeoLite2-City.mmdb).
  3. Configure Umami (via environment or config, depending on version) to use that file.

Once enabled, Umamis UI shows breakdowns by:

  • Country, and optionally region/city, in the standard views.

Umami can send:

  • User invites,
  • Password reset emails,
  • (Depending on version) scheduled reports.

Configuration is described in umami-smtp-and-testing.md. In summary:

  1. Choose an SMTP provider (Postmark, Mailgun, SES, etc.).
  2. Add SMTP environment variables to umami.env, for example:
    • UMAMI_SMTP_HOST, UMAMI_SMTP_PORT, UMAMI_SMTP_USERNAME, UMAMI_SMTP_PASSWORD, UMAMI_EMAIL_FROM.
  3. Wire them into the umami service in umami-docker-compose.yml.
  4. Restart the umami container.
  5. Test:
    • Invite a test user,
    • Trigger password reset,
    • Check inbox + spam + email headers for SPF/DKIM/DMARC.

12. Adding a new domain/site checklist

Assuming another server or site wants to use the existing Umami instance:

  1. DNS: point the new sites domain to its own web server as usual (no change needed for analytics).

  2. Ensure the new site is allowed:

    • In Umami, either:
      • Create a new website with that domain, or
      • Add the domain to an existing sites allowed domains.
  3. Script tag:

    • Add a script tag to the new sites HTML:
    <script
      async
      src="https://analytics.degelas.be/script.js"
      data-website-id="WEBSITE_ID_FOR_THIS_SITE"
      data-domains="new-domain.com"
    ></script>
    
  4. Custom events (optional):

    • Implement window.umami.track(...) or use a helper similar to frontend/src/umami.ts to send custom events.
  5. Goals & reports:

    • Define goals in the Umami UI for this site.
    • Build and save reports as needed.

No changes are required to the Umami server stack for additional sites; it is multi-tenant by design as long as each site has a Website ID and uses the correct script tag.