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 tracking endpoint on the same port. 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
standardworkload serving the dashboard, API, and tracking/collect endpoint on port3000. Runs a single replica by default; setreplicasto2or 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 as a subchart: the backing store for all users, websites, sessions, and events.
- PostgreSQL (HA, optional) — The 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.
- Identity & Policy — A least-privilege policy granting the Umami identity
revealon exactly two secrets: the app secret you create, and the active database’s credential secret. - Cron Backup Workload (optional) — When database backups are enabled.
This template does not create a GVC. You must deploy it into an existing GVC.
Prerequisites
One opaque secret must exist before you install. It holds Umami’s app secret, which signs auth tokens and sessions — anyone holding it can forge a login — so it is never a Helm value and never lands in the release.1
Create the app secret
Generate a random value and store it as the secret’s payload:Set
app.appSecretName to the name you used.2
Keep it for the life of the install
The value must stay stable — changing it invalidates every issued token and logs every user out. In a multi-replica install all replicas read this one secret, which is what lets a session established against one replica be honored by another.
postgres.config.password or postgresHA.postgres.password) before installing as well; it ships with a change-me placeholder default.
Once the secret exists, install the template using your preferred method:
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
First Run Sequence
Umami’s bootstrap admin is a hardcodedadmin / umami, seeded by the first database migration, and there is no environment variable to override it — the credentials are published in Umami’s own documentation. A public default install would therefore stand on the internet with known credentials, so the install starts private and you publish it once the password is changed.
This is a sequence, not a lockdown: the tracking endpoint is the product, and collection does not work until public access is on.
1
Install with the default private access
Install with
publicAccess.enabled: false (the default). The canonical endpoint refuses external requests, while in-GVC callers still reach the workload per internalAccess.type.2
Reach the dashboard over a port forward
Forward the workload’s port to your machine:Then open
http://localhost:3000/login in a browser and sign in as admin / umami.cpln port-forward is a top-level command, not a subcommand of cpln workload.3
Change the admin password
In the dashboard, go to Settings → Profile and change the password. The old password is rejected from that moment on.
4
Publish the dashboard and tracking endpoint
Set
publicAccess.enabled: true and run a helm upgrade. The firewall change takes up to a couple of minutes to propagate — roughly 50 seconds in a measured run — so re-test the public URL rather than trusting the first response. Your changed password applies over the public endpoint immediately; the old umami password is rejected there too.Upgrading From 1.0.1
Version1.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:
Two further changes need no action but are worth knowing:
publicAccess.enablednow defaults tofalse. An upgrade that does not set it explicitly makes the install private and stops data collection. Set it totrueexplicitly once the admin password is changed — see First Run.- The chart-created
{release}-umami-configsecret is gone. It existed only to hold the app secret; the template now creates no secret of its own.
The render guards are non-destructive against a running release. Tripping one exits non-zero without creating a new revision, and the workload keeps serving at its current version — you lose nothing by hitting it mid-upgrade.
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.
To switch to HA mode, set
postgres.enabled: false and postgresHA.enabled: true.
Configuration
Key configuration values (see the template’svalues.yaml for the complete set):
Application
image— The Umami open-source container image.replicas— Number of stateless app-tier replicas.1is the proven single-instance shape;2or 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 the app secret.resources— CPU and memory per replica:minCpu/minMemoryare the reservation,maxCpu/maxMemorythe limit.app.appSecretName— Name of the prerequisite opaque secret holding the app secret. It must exist before you install, and its value must stay stable — see Prerequisites.app.disableTelemetry— Whentrue(default), opts out of Umami’s anonymous usage telemetry.
Tracker
tracker.scriptName— Also serve the tracking script under a custom path (e.g.s.js→/s.js) instead of only 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. The custom path is baked into the script Umami serves, so the snippet you embed uses it automatically.
"" (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.
Custom tracker paths are aliases, not replacements. With
scriptName and collectEndpoint set, the default /script.js still returns the tracker and the default /api/send still accepts and records events. Custom paths help because your site loads the unblocked path — they do not close the defaults off.Access
publicAccess.enabled— Serve the dashboard and tracking endpoint on the canonical*.cpln.appHTTPS endpoint. Defaults tofalse, which blocks external requests at the edge; in-GVC callers still reach it perinternalAccess. Tracking collects nothing while it is off, so turn it on once the admin password is changed — see First Run.internalAccess.type— Internal firewall scope of the Umami workload:
Access changes take up to a couple of minutes to propagate — every measured transition returned the stale value for the first 25–50 seconds. Re-poll before concluding a knob is broken.
Backing Store
Enable exactly one ofpostgres (single-instance, default) or postgresHA (HA) — see Choosing a Database Mode. In both modes, change the database password before installing (postgres.config.password / postgresHA.postgres.password).
Connecting
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 withpostgres.backup.enabled or postgresHA.backup.enabled (matching your database mode), and complete the storage setup for your provider before installing. These values are a pass-through to the backing database template, which owns and documents the backup itself; the backup runs as a scheduled job in that store.
- AWS S3
- Google Cloud Storage
- S3-compatible (MinIO)
1
Create a bucket
Create an S3 bucket. Set
backup.aws.bucket and backup.aws.region 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 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.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 / postgres-highly-available template README.
Important Notes
- Create the app secret before installing. A missing prerequisite secret does not fail the install —
helm installreports success and the workload then sits at zero replicas with no container logs at all. Creating the secret afterwards needs acpln workload force-redeploymentto take effect; see Prerequisites. - Change the hardcoded
admin/umamipassword before you make the install public. It is seeded by the first database migration and cannot be overridden at install time. This is whypublicAccess.enableddefaults tofalse— follow First Run in order. - Tracking collects nothing until
publicAccess.enabledistrue— browsers on the sites you track must reach the tracking script and the collect endpoint. Publishing is a required step, not an optional one. - The upgrade that publishes the install bounces the bundled database for roughly two minutes, because it is the first upgrade after the install.
/api/heartbeatstays200throughout and is not the signal to watch — it never touches the database. - Upgrading from
1.0.1fails at render if you carryapp.appSecret,resources.cpu, orresources.memoryforward. Each guard names its replacement and leaves the running release untouched — see Upgrading From 1.0.1. - The app secret must stay stable for the life of the install — changing its payload logs every user out. Back it up outside Control Plane. It is yours, not the release’s: it survives
helm uninstalland must be deleted manually. - Custom tracker paths are aliases —
/script.jsand/api/sendstay live and keep recording even whentracker.scriptName/tracker.collectEndpointare set. replicas≥ 2 is recommended for production — replicas are independent and share the database and the app secret, so a session opened against one is honored by the others; 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
postgresHAand/or enable backups for durable production data.
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