> ## Documentation Index
> Fetch the complete documentation index at: https://docs.controlplane.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Umami

> Deploy Umami on Control Plane using the Template Catalog. Privacy-first, cookieless web and product analytics — a self-hosted Google Analytics alternative — with a stateless multi-replica app tier and a single-instance or highly available PostgreSQL backing store. Covers the tracking script, database modes, scaling, and optional backups.

## Overview

Umami is a privacy-first, cookieless web and product analytics platform — a self-hosted, MIT-licensed alternative to Google Analytics. This template deploys the stateless Umami v3 app tier backed by PostgreSQL, serving both the analytics dashboard and the public tracking endpoint over HTTPS. You embed a small tracking script on your site; visitor events POST back to the same workload and are stored in PostgreSQL, with no cookies and no personal data collected.

### Architecture

* **Umami** — A stateless `standard` workload serving the dashboard, API, and tracking/collect endpoint on port `3000`. Runs a single replica by default; set `replicas` to `2` or more for an always-on tier with zero-downtime rolling restarts. All state lives in PostgreSQL, so replicas are independent — no clustering.
* **PostgreSQL (single-instance, default)** — The [postgres](/template-catalog/templates/postgres) template as a subchart: the backing store for all users, websites, sessions, and events.
* **PostgreSQL (HA, optional)** — The [postgres-highly-available](/template-catalog/templates/postgres-highly-available) template instead: 3× Patroni PostgreSQL with automatic failover and an HAProxy leader endpoint, for a durable production store.

### What Gets Created

* **Standard Umami Workload** — One or more stateless replicas serving the UI, API, and tracking endpoint on port `3000`.
* **Database Workloads** — Single mode: one stateful PostgreSQL workload. HA mode: a stateful Patroni PostgreSQL workload, a stateful etcd workload, and a standard HAProxy leader-routing workload.
* **Volume Sets** — The database subchart's persistent volumes (10 GiB by default; per replica in HA mode). Umami itself has none.
* **Secret, Identity & Policy** — A template-managed `appSecret` (dictionary secret) and a least-privilege policy granting the Umami identity `reveal` on exactly the app config secret and the active database credential secret.
* **Cron Backup Workload** *(optional)* — When database backups are enabled.

<Note>
  This template does not create a GVC. You must deploy it into an existing GVC.
</Note>

## Prerequisites

None for a default install. For optional database backups you need a bucket and access setup for one of the supported providers — see [Backing Up](#backing-up).

Install the template using your preferred method:

<CardGroup cols={2}>
  <Card title="UI" href="/template-catalog/install-manage/ui" icon="laptop">
    Browse, install, and manage templates visually
  </Card>

  <Card title="CLI" href="/template-catalog/install-manage/cli" icon="terminal">
    Manage templates from your terminal
  </Card>

  <Card title="Terraform" href="/template-catalog/install-manage/terraform" icon={<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 128 128"><g fill-rule="evenodd"><path d="M77.941 44.5v36.836L46.324 62.918V26.082zm0 0" fill="#5c4ee5"/><path d="M81.41 81.336l31.633-18.418V26.082L81.41 44.5zm0 0" fill="#4040b2"/><path d="M11.242 42.36L42.86 60.776V23.941L11.242 5.523zm0 0M77.941 85.375L46.324 66.957v36.82l31.617 18.418zm0 0" fill="#5c4ee5"/></g></svg>}>
    Declare templates in your Terraform configurations
  </Card>

  <Card
    title="Pulumi"
    href="/template-catalog/install-manage/pulumi"
    icon={<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" id="Pulumi-Icon--Streamline-Svg-Logos" height="24" width="24">
    <desc>
        Pulumi Icon Streamline Icon: https://streamlinehq.com
    </desc>
    <path fill="#f26e7e" d="M4.683025 13.3318c0.869125 -0.5018 0.870575 -2.1264 0.003225 -3.62865s-2.27504 -2.313275 -3.1441725 -1.811475C0.672945 8.3935 0.6715 10.0181 1.53885 11.52035c0.86735 1.502275 2.27505 2.313275 3.144175 1.81145Zm0.0052 3.2167c0.86735 1.502275 0.865925 3.126875 -0.003225 3.628675 -0.86915 0.5018 -2.2768275 -0.309225 -3.144175 -1.81145 -0.8673525 -1.50225 -0.8659075 -3.126875 0.003225 -3.628675 0.8691325 -0.5018 2.276825 0.309225 3.144175 1.81145Zm5.922875 3.4243c0.86735 1.50225 0.8659 3.126775 -0.003225 3.62875 -0.869125 0.501775 -2.27685 -0.309325 -3.1442 -1.81155 -0.867325 -1.50225 -0.865875 -3.12685 0.00325 -3.628675 0.869125 -0.5018 2.276825 0.309225 3.144175 1.811475Zm-0.001925 -6.845275c0.86735 1.50225 0.8659 3.12685 -0.003225 3.628675 -0.869125 0.5018 -2.276825 -0.309225 -3.144175 -1.811475 -0.86735 -1.50225 -0.8659 -3.12685 0.003225 -3.62865 0.869125 -0.501825 2.276825 0.3092 3.144175 1.81145Z" stroke-width="0.25"></path>
    <path fill="#8a3391" d="M22.45775 11.524125c0.86725 -1.502225 0.865925 -3.12685 -0.003225 -3.62865 -0.869125 -0.501825 -2.276825 0.3092 -3.144175 1.811475 -0.86735 1.50225 -0.8659 3.126825 0.003225 3.62865 0.869125 0.501825 2.276825 -0.3092 3.144175 -1.811475Zm0.000175 3.2151c0.869075 0.5018 0.870625 2.1264 0.003225 3.62865 -0.86735 1.50225 -2.27505 2.313275 -3.144175 1.81145 -0.869125 -0.5018 -0.870575 -2.126425 -0.003225 -3.62865 0.86735 -1.50225 2.27505 -2.313275 3.144175 -1.81145ZM16.536225 18.157875c0.86915 0.501825 0.8706 2.126425 0.00325 3.628675 -0.86735 1.502125 -2.275075 2.313225 -3.1442 1.81145 -0.869125 -0.50175 -0.870575 -2.126425 -0.003225 -3.62865 0.867375 -1.502275 2.27505 -2.3133 3.144175 -1.811475Zm-0.003325 -6.843775c0.869125 0.5018 0.870575 2.126425 0.003225 3.628675s-2.27505 2.313275 -3.1442 1.811475c-0.869125 -0.501825 -0.870575 -2.126425 -0.003225 -3.628675 0.86735 -1.502275 2.27505 -2.313275 3.1442 -1.811475Z" stroke-width="0.25"></path>
    <path fill="#f7bf2a" d="M15.138225 2.06721c0 1.003615 -1.40625 1.817215 -3.14095 1.817215 -1.7347 0 -3.14095 -0.8136 -3.14095 -1.817215C8.856325 1.06359 10.262575 0.25 11.997275 0.25c1.7347 0 3.14095 0.81359 3.14095 1.81721ZM9.2166 5.482375c0 1.003625 -1.40625 1.8172 -3.14095 1.8172 -1.7347 0 -3.14095 -0.813575 -3.14095 -1.8172s1.40625 -1.817225 3.14095 -1.817225c1.7347 0 3.14095 0.8136 3.14095 1.817225Zm8.71005 1.8172c1.7347 0 3.14095 -0.813575 3.14095 -1.8172s-1.40625 -1.817225 -3.14095 -1.817225c-1.7347 0 -3.14095 0.8136 -3.14095 1.817225s1.40625 1.8172 3.14095 1.8172Zm-2.788425 1.605625c0 1.003625 -1.40625 1.8172 -3.14095 1.8172 -1.7347 0 -3.14095 -0.813575 -3.14095 -1.8172 0 -1.0036 1.40625 -1.8172 3.14095 -1.8172 1.7347 0 3.14095 0.8136 3.14095 1.8172Z" stroke-width="0.25"></path>
    </svg>}
  >
    Declare templates in your Pulumi programs
  </Card>
</CardGroup>

## Choosing a Database Mode

Exactly one of the two backing stores must be enabled — the chart enforces this at render. Umami is wired to the active database automatically.

|                   | `postgres` (default)                   | `postgresHA`                                            |
| ----------------- | -------------------------------------- | ------------------------------------------------------- |
| What runs         | One single-replica PostgreSQL workload | 3× Patroni PostgreSQL, 3× etcd, HAProxy leader endpoint |
| Database failover | None                                   | Automatic (Patroni leader election)                     |
| Best for          | Development and lightweight installs   | Production                                              |

To switch to HA mode, set `postgres.enabled: false` and `postgresHA.enabled: true`.

## Configuration

Key configuration values (see the template's `values.yaml` for the complete set):

```yaml theme={null}
image: ghcr.io/umami-software/umami:3.2.0

replicas: 1 # 1 = proven single-instance; 2+ = always-on, zero-downtime restarts

resources: # per replica
  cpu: 500m
  memory: 512Mi
  minCpu: 100m
  minMemory: 256Mi

app:
  # Signs auth tokens; MUST be unique per install, identical across replicas,
  # and stable across restarts (changing it logs everyone out).
  appSecret: "change-me-KJ8xQ2mZraB7vN1pLwCf5tHgUeYd0sQ4" # override: openssl rand -base64 32
  disableTelemetry: true # opt out of Umami's anonymous usage telemetry

tracker:
  scriptName: ""      # custom tracker script path, e.g. "s.js" (dodges ad blockers); "" = default /script.js
  collectEndpoint: "" # custom collect API path, e.g. "/api/track"; "" = default /api/send

postgres: # default: single-instance PostgreSQL
  enabled: true
  image: postgres:18
  config:
    username: umami
    password: change-me-umami-db # change before installing
    database: umami
  volumeset:
    capacity: 10 # initial capacity in GiB (minimum is 10)
  backup:
    enabled: false # true = scheduled backups of the analytics DB to object storage
    schedule: "0 2 * * *" # daily at 2am UTC
    provider: aws # aws | gcp | minio
    aws:
      bucket: my-backup-bucket
      region: us-east-1
      cloudAccountName: my-backup-cloudaccount
      policyName: my-backup-policy
      prefix: umami/backups

postgresHA: # durable HA: 3-replica Patroni store with an HAProxy leader endpoint (disable postgres first)
  enabled: false
  postgres:
    username: umami
    password: change-me-umami-db # change before installing
    database: umami
  replicas: 3
  volumeset:
    capacity: 10 # initial capacity in GiB per replica (minimum is 10)
  backup:
    enabled: false # true = scheduled backups to object storage
    mode: logical # logical | wal-g
    provider: aws # aws | gcp | minio
    aws:
      bucket: my-backup-bucket
      region: us-east-1
      cloudAccountName: my-backup-cloudaccount
      policyName: my-backup-policy
      prefix: umami/backups

publicAccess:
  enabled: true # HTTPS dashboard + tracking endpoint via the canonical *.cpln.app endpoint

internalAccess:
  type: same-gvc # options: none, same-gvc, same-org, workload-list
  workloads: [] # only used with same-gvc / workload-list
```

### Application

* `image` — The Umami open-source container image.
* `replicas` — Number of stateless app-tier replicas. `1` is the proven single-instance shape; `2` or more gives an always-on tier where rolling restarts cycle one replica at a time with no downtime. Replicas are independent and share only the database and `app.appSecret`.
* `resources` — CPU and memory per replica.
* `app.appSecret` — Signs auth tokens and secures sessions. It **must** be unique per installation, identical across replicas, and stable across restarts — changing it logs every user out. Generate one with `openssl rand -base64 32` and set it before installing.
* `app.disableTelemetry` — When `true` (default), opts out of Umami's anonymous usage telemetry.

### Tracker

* `tracker.scriptName` — Serve the tracking script under a custom path (e.g. `s.js` → `/s.js`) instead of the default `/script.js`. Useful for reducing ad-blocker interception.
* `tracker.collectEndpoint` — Have the tracker POST events to a custom path (e.g. `/api/track`) instead of the default `/api/send`.

Both default to `""` (standard paths). Custom paths take effect once a replica has fully booted with the new setting; a mid-rollout replica still serves the old path until it cycles.

### Access

* `publicAccess.enabled` — Serve the dashboard and tracking endpoint on the canonical `*.cpln.app` HTTPS endpoint (default). **Keep this enabled for tracking to work** — browsers must reach `/script.js` and `/api/send`. Set to `false` for an internal-only instance (external requests are blocked at the edge; in-GVC callers still reach it per `internalAccess`), which stops all public data collection.
* `internalAccess.type` — Internal firewall scope of the Umami workload:

| Type            | Description                                                            |
| --------------- | ---------------------------------------------------------------------- |
| `none`          | No internal access.                                                    |
| `same-gvc`      | Allow access from all workloads in the same GVC (default).             |
| `same-org`      | Allow access from all workloads in the same organization.              |
| `workload-list` | Allow access only from workloads listed in `internalAccess.workloads`. |

### Backing Store

Enable exactly one of `postgres` (single-instance, default) or `postgresHA` (HA) — see [Choosing a Database Mode](#choosing-a-database-mode). In both modes, **change the database password before installing** (`postgres.config.password` / `postgresHA.postgres.password`).

## Connecting

| What                | Value                                                                                          |
| ------------------- | ---------------------------------------------------------------------------------------------- |
| Public URL          | `status.canonicalEndpoint` of `{release}-umami` (`cpln workload get {release}-umami -o yaml`)  |
| Dashboard / login   | `https://<canonical>.cpln.app/login`                                                           |
| Tracking script     | `https://<canonical>.cpln.app/script.js` (embed on your site)                                  |
| Collect endpoint    | `https://<canonical>.cpln.app/api/send` (where the tracker POSTs events)                       |
| Internal (same GVC) | `http://{release}-umami.{gvc}.cpln.local:3000`                                                 |
| Default admin       | `admin` / `umami` — hardcoded; change it immediately (see [Important Notes](#important-notes)) |

To start collecting data, log in, add a website in the dashboard, then paste the generated `<script>` tag — which loads the tracking script and POSTs to the collect endpoint — into your site's HTML.

## Backing Up

Database backups are optional and disabled by default. They cover the analytics database — the users, websites, sessions, and events that make up your Umami instance. Enable them with `postgres.backup.enabled` or `postgresHA.backup.enabled` (matching your database mode), and complete the storage setup for your provider **before** installing. The backup runs as a scheduled job in the backing PostgreSQL store, so this is the same setup as that template.

<Tabs>
  <Tab title="AWS S3">
    <Steps>
      <Step title="Create a bucket">
        Create an S3 bucket. Set `backup.aws.bucket` and `backup.aws.region` to match.
      </Step>

      <Step title="Set up a Cloud Account">
        If you do not have one, [create a Cloud Account](https://docs.controlplane.com/guides/create-cloud-account) for your AWS account. Set `backup.aws.cloudAccountName` to its name.
      </Step>

      <Step title="Create a bucket-scoped IAM policy">
        Create an AWS IAM policy that grants list/get/put/delete on your bucket (`arn:aws:s3:::YOUR_BUCKET` and `arn:aws:s3:::YOUR_BUCKET/*`), then set `backup.aws.policyName` to the policy's name. The backing template's README has the full JSON.
      </Step>
    </Steps>
  </Tab>

  <Tab title="Google Cloud Storage">
    <Steps>
      <Step title="Create a bucket">
        Create a GCS bucket. Set `backup.gcp.bucket` to its name.
      </Step>

      <Step title="Set up a Cloud Account">
        If you do not have one, [create a Cloud Account](https://docs.controlplane.com/guides/create-cloud-account) for your GCP project and grant its service account **Storage Object Admin** (`roles/storage.objectAdmin`) on the bucket. Set `backup.gcp.cloudAccountName` to its name.
      </Step>
    </Steps>
  </Tab>

  <Tab title="S3-compatible (MinIO)">
    <Steps>
      <Step title="Create a bucket">
        Create your bucket on the server. Set `backup.minio.bucket` to its name.
      </Step>

      <Step title="Set the endpoint and credentials">
        Set `backup.minio.endpoint` to the S3 API address including port, and `backup.minio.accessKey` / `backup.minio.secretKey` to credentials with access to the bucket. No Cloud Account is required — the keys authenticate directly.
      </Step>
    </Steps>
  </Tab>
</Tabs>

In HA mode, `postgresHA.backup.mode` selects `logical` (scheduled `pg_dump`) or `wal-g` (continuous WAL archiving). The full per-provider walkthrough, including the exact IAM JSON, lives in the backing [postgres](/template-catalog/templates/postgres) / [postgres-highly-available](/template-catalog/templates/postgres-highly-available) template README.

## Important Notes

* **Change the default admin password immediately after first login.** The bootstrap admin is a hardcoded `admin` / `umami`, seeded by the first database migration — there is no way to override it at install time. Change it in **Settings → Profile** right after installing.
* **Set your own `app.appSecret` before installing.** It signs auth tokens; changing it later logs every user out. Generate one with `openssl rand -base64 32`.
* **Keep `publicAccess` enabled for tracking to work** — browsers must reach the tracking script and collect endpoint. Disabling it silently stops all public data collection.
* **Ad blockers block the default `/script.js` and `/api/send`** — set `tracker.scriptName` / `tracker.collectEndpoint` to custom paths to reduce blocking.
* **`replicas` ≥ 2 is recommended for production** — replicas are independent and share the database and `appSecret`; rolling restarts cycle one at a time with no downtime.
* **Database volumes survive reinstalls under the same release name; uninstalling deletes them** — all analytics data is lost. Use `postgresHA` and/or enable backups for durable production data.

## External References

<CardGroup cols={2}>
  <Card title="Umami Documentation" icon="book" href="https://umami.is/docs">
    Official Umami documentation
  </Card>

  <Card title="Tracker Configuration" icon="gear" href="https://umami.is/docs/tracker-configuration">
    Configure the tracking script and its options
  </Card>

  <Card title="Collect API" icon="code" href="https://umami.is/docs/api/sending-stats">
    How events are sent to the collect endpoint
  </Card>

  <Card title="Environment Variables" icon="sliders" href="https://umami.is/docs/environment-variables">
    Umami environment variables reference
  </Card>

  <Card title="Umami Template" icon="github" href="https://github.com/controlplane-com/templates/tree/main/umami">
    View the source files, default values, and chart definition
  </Card>
</CardGroup>
