Skip to main content

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 a bundled PostgreSQL store, serving the analytics dashboard and the tracking endpoint on the same port. You embed a small tracking script on your site; visitor events are posted back to the same workload and stored in PostgreSQL, with no cookies and no personal data collected. The install starts private: Umami seeds a hardcoded admin / umami account that no setting can override, so publicAccess.enabled defaults to false and you publish the install only after changing that password. Tracking collects nothing until you do — follow First Run.
This template deploys into an existing GVC that you already have — it does not create or manage a GVC. Every workload below runs in each location of that GVC.

What Gets Created

Umami itself has no volume set — every user, website, session and event lives in PostgreSQL. The app secret and the database credentials secret are prerequisite secrets you create yourself; the chart references them by name and never creates, modifies or deletes them.

Prerequisites

Two secrets must exist before you install: an opaque secret for the app secret and a dictionary secret for the database credentials. They hold credentials, so they are prerequisite secrets rather than values — a value would sit in plaintext in the Helm release for the life of the install. Secrets are org-level, so no --gvc flag is involved.
1

Create the app secret

The app secret signs Umami’s auth tokens and sessions — anyone holding it can forge a login — so it is never a Helm value and never lands in the release. Generate a random value and store it as the secret’s payload:
Keep it for the life of the install: changing it logs every user out. Set app.appSecretName to this name.
2

Create the database credentials secret

The bundled PostgreSQL initializes with these values and Umami connects with them, in both database modes:
Set its name in the key of the store you use: postgres.config.credentialsSecretName (single-instance, the default) or postgresHA.config.credentialsSecretName (HA). Umami builds its connection URL from the three keys, so keep them URL-safe (letters, digits, -, _). PostgreSQL reads the secret only when its data is first initialized — see Rotating the Database Password.
A missing app secret or database credentials secret wedges the install rather than failing it. cpln helm install reports success and every resource is created, but the Umami container never starts — so cpln logs returns zero lines. The only place the missing secret is named is status.versions[].message:
The message reads The secret <name> no longer exists. Workload updates are paused until the secret is added or the reference to the secret removed. It is get-deployments — plain cpln workload get has no versions key. Create the missing secret and the deployment recovers on its own within several minutes, or run cpln workload force-redeployment RELEASE_NAME-umami --gvc GVC_NAME to skip the wait.
Optional, for two-factor authentication (app.twoFactorKeySecretName, opaque): a 64-character hex key that encrypts users’ TOTP secrets. Without it, two-factor setup in Settings reports that 2FA is not configured:
Keep it for the life of the install. Changing or removing it locks every enrolled user, admin included, out of their account until the same key is restored. Optional database backups need a bucket and access setup on AWS S3, Google Cloud Storage or an S3-compatible server, and S3-compatible servers additionally need a dictionary secret with the bucket keys — see Backing Up.

Installation

Once both secrets exist, install the template into your GVC, naming them:
Keep these settings in a values file (--values) rather than --set, because every later upgrade must pass them again. If you run more than one release of this template in the same org, create a separate database credentials secret for each — see Backing Store.

UI

Browse, install, and manage templates visually

CLI

Manage templates from your terminal

Terraform

Declare templates in your Terraform configurations

Pulumi

Declare templates in your Pulumi programs

Configuration

Application

Replicas are independent — they share only the database and the app secret, so a session opened against one replica is honored by the others.

Tracker

Custom paths are aliases, not replacements: the default /script.js and /api/send keep working. They help because your site loads a path ad blockers do not recognise. The custom collect path is baked into the script Umami serves, so the snippet you embed picks it up automatically.

Backing Store

Enable exactly one of the two stores — the chart refuses to render with both or neither. Umami is wired to whichever is active.

Choosing a Database Mode

To use HA mode on a new install, set postgres.enabled: false and postgresHA.enabled: true. The credentials come from your prerequisite database credentials secret in both modes, named by postgresHA.config.credentialsSecretName in HA mode. Switching an existing release between modes does not move data — the other store starts empty. Secret names are org-wide, so if you run more than one release of this template in the same org, create a separate database credentials secret for each and point each release’s postgres.config.credentialsSecretName (or postgresHA.config.credentialsSecretName in HA mode) at its own. Database backups are configured under postgres.backup / postgresHA.backup — see Backing Up.

Access

Tracking collects nothing while publicAccess.enabled is false — browsers on the sites you track must reach the tracking script and the collect endpoint. Turn it on once the admin password is changed. An access change takes a few minutes to take effect, so re-test rather than trusting the first response.

Connecting

CANONICAL_ENDPOINT is the host of status.canonicalEndpoint. Open a tunnel to the dashboard from your machine — this works whether or not public access is on:
Then confirm the app answers with curl -sS http://localhost:3000/api/heartbeat. The heartbeat does not touch the database, so a 200 there proves only that the app tier is up; loading the dashboard is the check that the database is reachable too.

First Run

Umami’s bootstrap admin is a hardcoded admin / umami, seeded by its first database migration and published in Umami’s own documentation. The install therefore starts private, and you publish it once the password is changed.
1

Install with public access off

Install as shown in Installation, leaving publicAccess.enabled at its default false. Wait until the workload reports ready:
2

Open the dashboard through a tunnel

cpln port-forward is a top-level command, not a subcommand of cpln workload. Open http://localhost:3000/login in a browser and sign in as admin / umami.
3

Change the admin password

In the dashboard, open Settings → Profile and change the password. From then on the old password is rejected.
4

Publish the dashboard and tracking endpoint

Upgrade the release with publicAccess.enabled=true, passing the same app secret and database credentials secret names you installed with (or the same values file):
Upgrading through the marketplace UI is the alternative. Allow a few minutes for public access to take effect, then read the endpoint with cpln workload get RELEASE_NAME-umami --gvc GVC_NAME -o yaml.
5

Add your website and embed the tracker

In the dashboard, add a website, then paste the generated <script> tag into the HTML of your site. It loads the tracking script from the public address and posts events to the collect endpoint.
The publishing upgrade is the first upgrade after the install, and it can restart the bundled database even though no database value changed. Expect Umami to be briefly unreachable while the database comes back; this is not a failed upgrade — do not roll back. Confirm recovery by loading the dashboard rather than by /api/heartbeat, which answers even while the database is down.

Operations

Backing Up

Database backups are optional and disabled by default. They cover everything that makes up your Umami instance — users, websites, sessions and events. They are a pass-through to the bundled database template, which runs the backup as a scheduled job; enable them on whichever store is active and complete the storage setup for your provider before installing or upgrading with them on. Single-instance mode:
HA mode — the same providers, plus a choice of backup mode:
1

Create a bucket

Create an S3 bucket. Set backup.aws.bucket and backup.aws.region on the active store to match.
2

Set up a cloud account

If you do not have one, create a cloud account for your AWS account. Set backup.aws.cloudAccountName to its name.
3

Create a bucket-scoped IAM policy

Create an AWS IAM policy scoped to your bucket, then set backup.aws.policyName to its name:

Restoring a Backup

No restore path has been rehearsed against this template. A restore goes into the database, not into Umami, and follows the bundled database template — rehearse it against a scratch release before you depend on it. Restoring from a volume set snapshot is likewise unverified here.
Use the procedure on the postgres page in single-instance mode, or the postgres-highly-available page in HA mode, with these Umami-specific values:
  • The database workload is RELEASE_NAME-postgres (single-instance) or RELEASE_NAME-postgres-ha-proxy (HA mode — always go through the leader endpoint).
  • The username, password and database name are the keys of the credentials secret: cpln secret reveal DB_CREDENTIALS_SECRET_NAME -o yaml.
  • The Umami container has neither psql nor a cloud CLI, so run the restore from a client that can reach both the bucket and the database — your own machine with a cpln port-forward to the database workload open, for example.
  • Restore into an empty database and keep Umami from writing until the replay has finished; replaying into a database Umami has already migrated collides with the existing schema.
The restored data carries its own users, so after a restore you sign in with the passwords stored in the backup, not admin / umami.

Upgrading From 1.0.0

Version 1.0.0 did not compact the etcd cluster inside the bundled highly available database, so etcd’s backend grows with time alone and goes read-only once it reaches its quota — taking PostgreSQL failover with it. Only installs running the HA database are affected (postgresHA.enabled). Upgrading to 1.0.1 or later turns compaction on: that stops further growth but cannot shrink a backend that has already grown, and a cluster that has already raised a NOSPACE alarm needs operator recovery rather than an upgrade. See etcd History Compaction.

Upgrading From 1.0.1

Version 1.1.0 is a security release that renames three values. Carrying a 1.0.1 values file forward fails at render with a message naming the replacement, so nothing silently reverts to a default: publicAccess.enabled also changed its default to false. An upgrade that does not set it explicitly makes the install private and stops data collection — pass publicAccess.enabled=true once the admin password is changed.

Upgrading From 1.1.0

Version 1.2.0 moved the single-instance database credentials. Carrying the old keys forward fails at render: Put the values your single-instance database was initialized with into the database credentials secret under Prerequisites, set postgres.config.credentialsSecretName to its name, and remove the three keys. The error message comes from the bundled database (config.username was REMOVED in postgres 3.4.0). The MinIO keys are a prerequisite secret too: create it as shown in Backing Up.

Upgrading From 1.2.0

Version 1.3.0 removed the HA database credentials block. Carrying the old block forward fails at render with the postgres block was REMOVED in 2.5.0. Put the username, password and database values that sat in a postgres block under postgresHA unchanged into the database credentials secret under Prerequisites — the HA database was initialized with them — set postgresHA.config.credentialsSecretName to its name, and delete the block. Take a backup before upgrading. Single-instance installs need no action.

Upgrading From 1.3.0

Version 1.3.1 moved the HA database’s MinIO backup keys into a prerequisite secret. With HA-mode MinIO backups on, the old accessKey and secretKey values under postgresHA.backup.minio now fail at render: create a dictionary secret holding accessKey and secretKey as shown in Backing Up and set postgresHA.backup.minio.credentialsSecretName to its name. No other install needs action.

Upgrading From 1.3.1

Version 1.4.0 removed postgres.credentials: the database credentials are now a prerequisite secret, the same one the database templates require on their own. Carrying the old key forward fails the render. 1.3.x created the database secret itself, so this upgrade deletes it. Before upgrading, create a secret under a new name holding the values your database was initialized with — not new ones, or Umami loses its database connection. OLD_SECRET_NAME is the credentialsSecretName of the mode you use (default my-umami-db-credentials):
Then upgrade with postgres.config.credentialsSecretName (single-instance mode) or postgresHA.config.credentialsSecretName (HA mode) set to that name, and postgres.credentials removed. Your current values are also in postgres.credentials of the 1.3.x release. The upgrade restarts the bundled PostgreSQL too (it now reads the new secret), so Umami briefly loses its database and reconnects by itself. The new version of a workload can also wait for several minutes, with get-deployments reporting that it is not allowed to reveal the secret, while access to the new secret propagates; the previous version keeps serving meanwhile, and it clears by itself.

Upgrading From 1.4.0

The image moves from Umami 3.2.0 to 3.4.1, which fixes Critical vulnerabilities in its bundled Next.js. The chart refuses any ghcr.io/umami-software/umami tag below 3.4.1, so if your values pin image, set it to ghcr.io/umami-software/umami:3.4.1 or remove it. Umami migrates its database on first start (two-factor, session linking, annotations, API keys). Rolling back to 1.4.0 afterwards is not supported, so take a backup first if you need a way back. Two-factor authentication (new in Umami 3.3) needs the optional key secret described under Prerequisites. If you add it in the same upgrade, the new version can wait several minutes with is not allowed to reveal the secret in get-deployments while the new grant propagates; the previous version keeps serving. In HA mode (postgresHA) the database moves to controlplanecorporation/patroni-postgres:0.8, which carries pgvector 0.8.7. The database members restart and nothing limits that rollout, so expect a brief interruption of writes while the leader changes; Umami itself restarts as on any upgrade, and with a single Umami replica (the default) that is the longer interruption, because the old replica stops before the new one serves. Upgrade in a quiet window. Umami does not use the vector extension; if you created it yourself in a database, run this there after the upgrade. If your values set postgresHA.image, set it to the 0.8 tag: tags 0.1 to 0.7 are refused at render.

Rotating the Database Password

PostgreSQL keeps the password it was initialized with, and a running workload keeps the values it started with, so a rotation takes three steps in order (single-instance; in HA mode follow Rotating the Database Password in HA Mode instead):
  1. Change it in the database: ALTER ROLE DB_USERNAME PASSWORD 'NEW_PASSWORD'; (connected as that user, from inside the GVC).
  2. Update the secret: cpln secret edit SECRET_NAME.
  3. Right away, redeploy Umami with cpln workload force-redeployment RELEASE_NAME-umami --gvc GVC_NAME, and wait until get-deployments shows a higher version number, alone and ready (right after the command the status may not show the restart yet, and ready: true alone can still describe the old replica). Do not redeploy the database: PostgreSQL reads the secret only when it is first initialized, so restarting it only adds downtime.
Umami keeps serving on the database connections it already has open, so logins fail only briefly while its replica is swapped. Do step 3 right away: if those connections drop before Umami restarts, it cannot open new ones.

Rotating the Database Password in HA Mode

The HA database (postgresHA) needs its own order. The replication role repl shares the password, and a member that restarts with the old password can be promoted to leader, which splits the cluster. Move the leader to member -0 first, so it restarts last, after every other member already has the new password. pgx runs a command in one member (LOCATION is your GVC’s location, DB_USERNAME the secret’s username):
Then force-redeploy RELEASE_NAME-umami, which keeps the old password until it restarts. The database drops connections briefly at each switchover, and the app cannot open new connections from the ALTER ROLE until its own redeploy finishes, so rotate in a quiet window. If a member stays starting, or running without streaming for several minutes, re-copy it from the leader. This copies the whole database, so it costs network traffic in proportion to its size:

Scaling and Availability

  • The app tier scales with replicas. It is stateless — replicas share only the database and the app secret — so 2 or more gives an always-on tier whose rolling restarts cycle one replica at a time.
  • The database is the availability limit. In single-instance mode a database restart makes the dashboard and collection briefly unavailable; set postgresHA.enabled: true on a new install for automatic failover.
  • The first helm upgrade after an install can restart the bundled database even when no database value changed.
  • Uninstall deletes every volume set the chart created, so all analytics data is lost and does not survive a reinstall. The GVC is yours and is left alone, and your prerequisite secrets survive. Enable backups if the data matters.

Troubleshooting

Symptom: cpln helm install succeeded, but RELEASE_NAME-umami shows no containers and cpln logs returns nothing.Cause: The secret named by app.appSecretName, or the database credentials secret named by postgres.config.credentialsSecretName (HA mode: postgresHA.config.credentialsSecretName), does not exist. The deployment pauses on the unresolved reference.Fix: Read the message naming the secret, then create it as shown in Prerequisites:
The message reads The secret <name> no longer exists. Workload updates are paused until the secret is added or the reference to the secret removed. Once the secret exists the deployment recovers on its own within several minutes, or run cpln workload force-redeployment RELEASE_NAME-umami --gvc GVC_NAME to skip the wait.
Symptom: The website is added and the tracker is embedded, but no pageviews arrive.Cause: Most often publicAccess.enabled is still false, so browsers cannot reach the tracking script or the collect endpoint — or the embedded script points at an address other than the public canonical endpoint. Ad blockers also block the default /script.js and /api/send.Fix: Set publicAccess.enabled=true (see First Run), confirm the <script> tag uses the public address, and set tracker.scriptName / tracker.collectEndpoint to custom paths to reduce ad-blocker interception.
Symptom: The install stops with umami: enable exactly one backing store — set either postgres.enabled or postgresHA.enabled to true, not both, or the variant naming postgres.enabled (default) or postgresHA.enabled (durable HA).Cause: Both postgres.enabled and postgresHA.enabled are true, or both are false.Fix: Enable exactly one — see Choosing a Database Mode. For HA mode set postgres.enabled: false together with postgresHA.enabled: true.
Symptom: All dashboard sessions end at once and everyone has to sign in again.Cause: The payload of the secret named by app.appSecretName changed, or app.appSecretName now points at a different secret. Existing tokens were signed with the old value.Fix: Nothing is lost — users sign in again. To avoid it, keep the app secret stable for the life of the install.
Symptom: helm upgrade stops at render with app.appSecret was removed in 1.1.0, resources.cpu was renamed to resources.maxCpu, config.username was REMOVED in postgres 3.4.0, the postgres block was REMOVED in 2.5.0, backup.minio.accessKey and backup.minio.secretKey were REMOVED, or postgres.credentials was REMOVED in 1.4.0.Cause: Your values still carry a key that moved in template versions 1.1.0 to 1.4.0. The existing release is left untouched and running.Fix: Follow the matching migration note above — Upgrading From 1.0.1, Upgrading From 1.1.0, Upgrading From 1.2.0, Upgrading From 1.3.0 or Upgrading From 1.3.1 — keeping the credentials the database already uses in your database credentials secret.

Important Notes

  • Create the app secret and the database credentials secret before installing. A missing one does not fail the install — the workload waits on it with no logs; see Prerequisites for the diagnostic.
  • Editing the database credentials secret alone changes nothing — rotate with ALTER ROLE plus a forced redeployment of Umami (not the database); see Rotating the Database Password. In HA mode a leader switchover comes first.
  • Change the hardcoded admin / umami password before turning public access on — follow First Run in order.
  • Tracking collects nothing until publicAccess.enabled is true, and the tracking script must be loaded from the public address.
  • Keep the app secret stable — changing it logs every user out. It is not owned by the release: it survives helm uninstall and must be deleted manually.
  • Pass the same app secret and database credentials secret names on every upgrade — a values file is the simplest way.
  • Give each release its own database credentials secret — secret names are org-wide.
  • Uninstall deletes the database volume sets — enable backups if the analytics data matters.

External References

Umami Documentation

Official Umami documentation

Tracker Configuration

Configure the tracking script and its options

Collect API

How events are sent to the collect endpoint

Environment Variables

Umami environment variables reference

Umami Template

View the source files, default values, and chart definition