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 hardcodedadmin / 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.
What Gets Created
Prerequisites
One opaque secret must exist before you install. Secrets are org-level, so no--gvc flag is involved.
Create the app secret
app.appSecretName to this name.Choose the database password
postgres.credentials.username, postgres.credentials.password and postgres.credentials.database into a dictionary secret it creates, and both Umami and the database read it. Nothing to create — but the password ships as the placeholder change-me-umami-db, so set postgres.credentials.password to a value of your own before installing. This applies in both database modes.Installation
Once the app secret exists, install the template into your GVC, naming the secret and replacing the database password placeholder:--values) rather than --set if you do not want the database password in your shell history — and because every later upgrade must pass them again. If you run more than one release of this template in the same org, also give each its own postgres.config.credentialsSecretName — see Backing Store.
UI
CLI
Terraform
Pulumi
Configuration
Application
Tracker
/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
postgres.enabled: false and postgresHA.enabled: true. The credentials still come from postgres.credentials.* in both modes. 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, give each its own credentials secret name — postgres.config.credentialsSecretName, or postgresHA.config.credentialsSecretName in HA mode. A second release left on the default name is refused at install and creates nothing; the first release is unaffected.
Database backups are configured under postgres.backup / postgresHA.backup — see Backing Up.
Access
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:
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 hardcodedadmin / 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.
Install with public access off
publicAccess.enabled at its default false. Wait until the workload reports ready: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.Change the admin password
Publish the dashboard and tracking endpoint
publicAccess.enabled=true, passing the same app secret name and database password you installed with (or the same values file):cpln workload get RELEASE_NAME-umami --gvc GVC_NAME -o yaml.Add your website and embed the tracker
<script> tag into the HTML of your site. It loads the tracking script from the public address and posts events to the collect endpoint.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:- AWS S3
- Google Cloud Storage
- S3-compatible (MinIO)
Create a bucket
backup.aws.bucket and backup.aws.region on the active store to match.Set up a cloud account
backup.aws.cloudAccountName to its name.Create a bucket-scoped IAM policy
backup.aws.policyName to its name:Restoring a Backup
- The database workload is
RELEASE_NAME-postgres(single-instance) orRELEASE_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
psqlnor a cloud CLI, so run the restore from a client that can reach both the bucket and the database — your own machine with acpln port-forwardto 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.
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:config.username was REMOVED in postgres 3.4.0) and tells you to create a credentials secret yourself; ignore that part — this template creates it from postgres.credentials.*. The MinIO keys, by contrast, are a real prerequisite secret: create it as shown in Backing Up.
Upgrading From 1.2.0
Version 1.3.0 moved the HA database credentials onto the same chart-created secret as single-instance mode. Carrying the old block forward fails at render withthe postgres block was REMOVED in 2.5.0. The three username, password and database values that sat in a postgres block under postgresHA now come from postgres.credentials.username, postgres.credentials.password and postgres.credentials.database, and this chart writes them into the secret named by postgresHA.config.credentialsSecretName.
Delete that block from your values and set postgres.credentials.* to the same values it held — the HA database was initialised with them. Do not create the credentials secret yourself. This path has not been rehearsed on an existing HA install; 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 oldaccessKey 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.
Scaling and Availability
- The app tier scales with
replicas. It is stateless — replicas share only the database and the app secret — so2or 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: trueon a new install for automatic failover. - The first
helm upgradeafter 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 app secret survives. Enable backups if the data matters.
Troubleshooting
The Umami workload sits at 0 replicas after install while helm reported success
The Umami workload sits at 0 replicas after install while helm reported success
cpln helm install succeeded, but RELEASE_NAME-umami shows no containers and cpln logs returns nothing.Cause: The secret named by app.appSecretName 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 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.The dashboard shows no visitors
The dashboard shows no visitors
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.Render fails with enable exactly one backing store
Render fails with enable exactly one backing store
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.A second release is refused because a resource is managed by a different release
A second release is refused because a resource is managed by a different release
cannot be updated because it is being managed by a different release, naming the database credentials secret, and creates nothing.Cause: Secret names are org-wide, and both releases are trying to create the same credentials secret (default my-umami-db-credentials). The first release owns it.Fix: Give the new release its own postgres.config.credentialsSecretName (or postgresHA.config.credentialsSecretName in HA mode) and install again. The first release is unaffected.Every user is logged out after a change
Every user is logged out after a change
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.Upgrade fails with a key that was REMOVED or RENAMED
Upgrade fails with a key that was REMOVED or RENAMED
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, or backup.minio.accessKey and backup.minio.secretKey were REMOVED.Cause: Your values still carry a key that moved in template versions 1.1.0 to 1.3.1. 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 or Upgrading From 1.3.0 — keeping the credentials the database already uses. Do not create a database credentials secret yourself; this template creates it.Important Notes
- Create the app secret before installing, and change
postgres.credentials.passwordfrom itschange-meplaceholder. A missing app secret does not fail the install — the workload waits on it with no logs. - Change the hardcoded
admin/umamipassword before turning public access on — follow First Run in order. - Tracking collects nothing until
publicAccess.enabledistrue, 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 uninstalland must be deleted manually. - Pass the same app secret name and database password on every upgrade — a values file is the simplest way.
- Give each release its own
credentialsSecretName— secret names are org-wide, and a second release on the default name is refused at install. - Uninstall deletes the database volume sets — enable backups if the analytics data matters.