Self-host Umami on a managed VPS: your web analytics on your own server

When you self-host Umami on a managed VPS, the analytics of your websites stay on a machine of your own, which our teams keep up to date and monitor day and night. Umami is free software under the MIT license that measures traffic without cookies. This guide follows its official documentation: installing with Docker Compose and PostgreSQL, HTTPS, the first login, the tracking script, what the project says about personal data, useful settings, backups and updates.

Simon Vasconcelos Lee By Published on 15 November 202612-minute read

All guides

In short

  1. The MIT license lets you use, modify and redistribute Umami freely, at work or anywhere else, as long as you keep its copyright notice.
  2. Install it with Docker Compose: the project’s file starts Umami and its PostgreSQL database, the only supported database since version 3.
  3. Generate APP_SECRET and TWO_FACTOR_ENCRYPTION_KEY at random, serve Umami over HTTPS on its own subdomain, then change the admin account’s password right away.
  4. Add your website, then paste its tracking script into the <head> of your pages: the tracker does not use cookies.
  5. Dump the database every day with pg_dump, keep the .env file somewhere safe, and update with docker compose pull.

What Umami does

Umami is an open-source web and product analytics platform. Its documentation describes a tool that brings traffic, campaigns, visitor behavior, conversions, retention and revenue together, from the first visit to the outcomes that matter to your business. It is written in TypeScript on Next.js, and its Docker image runs under an unprivileged account.

One instance tracks several websites: each one gets its own ID and tracking script, and your colleagues find their way around through accounts and teams.

What the MIT license allows

Umami is published under the MIT license, in the name of Umami Software, Inc. It grants, free of charge, the right to use, copy, modify, merge, publish, distribute, sublicense and sell copies of the software. You can therefore run it for your business and for your clients’ websites, with no license to buy.

Its only condition: the copyright notice and the permission notice go with all copies or substantial portions of the software. Like any MIT license, it provides the software “as is”, without warranty.

Cookies and personal data: what the project says

The documentation presents Umami as analytics without cookies, without cross-site tracking and without the automatic collection of personal data. Self-hosted, it keeps your analytics on your own server: you decide where they live and how long they stay.

QuestionWhat the project saysSource
CookiesThe web tracker does not use cookies; whether your site needs a cookie notice depends on the other services you use and the requirements that applyFAQ
Data collectedPageviews, referrer URLs, browsers, operating systems, device types and approximate locationFAQ
IP addressThe sessions table has no column for the IP address; a session ID is a hash of the website, the address, the browser and a salt that rotates every month by defaultSchema and code, version 3.4.1
RetentionSelf-hosted, data is kept until you delete itFAQ
GDPRUmami is designed with privacy in mind, and compliance depends on how you configure and use itFAQ
Data you sendA visitor ID or event properties you choose to send are your responsibilityIntroduction

Three tracking script settings go further, if you wish: data-exclude-search removes search parameters from the recorded URLs, data-exclude-hash removes the hash, and data-do-not-track turns tracking off for browsers that expose the Do Not Track preference. The documentation notes that this last setting is not, on its own, a complete consent management solution.

If you identify logged-in visitors with data-distinct-id or umami.identify(), the documentation recommends an internal user ID or a hash rather than an email address: the value can be read in the page’s HTML.

Installing with Docker Compose and PostgreSQL

The repository ships a docker-compose.yml that starts Umami and its PostgreSQL database. Since version 3, PostgreSQL is the only supported database, version 12.14 at minimum, and the documentation recommends setting it to the UTC timezone. On a server with Docker installed, create a folder and start with its secrets, generated at random with openssl, as the documentation suggests:

Terminal
cat > .env <<EOF
POSTGRES_PASSWORD=$(openssl rand -hex 24)
APP_SECRET=$(openssl rand -hex 32)
TWO_FACTOR_ENCRYPTION_KEY=$(openssl rand -hex 32)
EOF
chmod 600 .env

Then place this compose.yaml next to it. It follows the project’s file at version 3.4.1, with two changes: the secrets come from the .env file, and the port is published on 127.0.0.1 only.

compose.yaml
services:
  umami:
    image: ghcr.io/umami-software/umami:latest
    ports:
      - "127.0.0.1:3000:3000"
    environment:
      DATABASE_URL: postgresql://umami:${POSTGRES_PASSWORD}@db:5432/umami
      APP_SECRET: ${APP_SECRET}
      TWO_FACTOR_ENCRYPTION_KEY: ${TWO_FACTOR_ENCRYPTION_KEY}
    depends_on:
      db:
        condition: service_healthy
    init: true
    restart: always
    healthcheck:
      test: ["CMD-SHELL", "curl http://localhost:3000/api/heartbeat"]
      interval: 5s
      timeout: 5s
      retries: 5
  db:
    image: postgres:15-alpine
    environment:
      POSTGRES_DB: umami
      POSTGRES_USER: umami
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
    volumes:
      - umami-db-data:/var/lib/postgresql/data
    restart: always
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}"]
      interval: 5s
      timeout: 5s
      retries: 5
volumes:
  umami-db-data:
Terminal
docker compose up -d
curl -s http://127.0.0.1:3000/api/heartbeat

The installation documentation gives no figure for memory or CPU. The size depends on the traffic of the tracked websites and on the volume of data you keep. On a managed VPS, tell us about your usage and we recommend the right size.

HTTPS: the reverse proxy

Umami listens over HTTP on port 3000, and the documentation suggests serving it behind your web server, through a reverse proxy. Give it its own subdomain, such as stats.example.com, pointed at the server with A and AAAA records. Serving Umami under a path goes through BASE_PATH, a variable read when the application is built: with the published image, the subdomain is the direct route.

The proxy must also pass on the visitor’s address. Umami reads it from the headers it receives, including X-Real-IP and X-Forwarded-For: it uses it to tell visitors apart and to locate their country. If your proxy uses another header, CLIENT_IP_HEADER names it.

With Caddy

Caddy obtains the Let’s Encrypt certificate and enables HTTPS by itself. Its reverse_proxy directive sets X-Forwarded-For by default: these three lines are all you need.

Caddyfile
stats.example.com {
  reverse_proxy 127.0.0.1:3000
}

With Nginx and Certbot

This block follows the Nginx example from the Umami documentation, listening on port 80 so that Certbot can set up HTTPS:

Nginx block
server {
  listen 80;
  listen [::]:80;
  server_name stats.example.com;

  location / {
    proxy_pass http://127.0.0.1:3000;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  }
}

Certbot then installs the certificate and takes care of renewing it:

Terminal
sudo certbot --nginx

The first login: the admin account and two-factor authentication

When it creates its database, Umami opens an administrator account: username admin, password umami. The documentation asks you to change this password at your first login.

  1. Open your HTTPS address and log in with admin and umami.
  2. Open Settings from the profile button in the sidebar, then Profile, and click Change password.
  3. In the Security tab, enable two-factor authentication: scan the QR code with your authenticator app, enter the six-digit code, then store the ten backup codes somewhere safe, as they are shown only once.

Keep TWO_FACTOR_ENCRYPTION_KEY with your backups: the documentation warns that losing or changing this key makes stored secrets unreadable, and each user must then enroll in two-factor authentication again.

Adding a website and its tracking script

  1. In Websites, click Add website.
  2. Give the website a name, then its domain: Umami uses it to filter your own pages out of the referrers list.
  3. Open Edit on that website and copy the code from the Tracking code section.
  4. Paste it into the <head> of your pages, then visit your website: data appears in the dashboard right away.
The tracking code, in the head
<script defer src="https://stats.example.com/script.js" data-website-id="your-website-id"></script>

A script name of your own

Some ad blockers block anything that looks like analytics. Self-hosted, Umami is already served from your own domain, and two variables go further: TRACKER_SCRIPT_NAME gives the script another name than script.js, and COLLECT_API_ENDPOINT renames the collection endpoint, instead of /api/send. The script then calls the new endpoint by itself; only the source of the tracking code changes on your pages.

compose.yaml, under environment
TRACKER_SCRIPT_NAME: "stats.js"
COLLECT_API_ENDPOINT: "/api/collect"

Useful settings

These environment variables go into the umami service of compose.yaml, then docker compose up -d recreates the container to pick them up:

VariableWhat it doesValue
DISABLE_TELEMETRYTurns off the anonymous telemetry Umami sends to the project to improve the application1
PRIVATE_MODETurns off all external network calls, including website icons, served from DuckDuckGo by default1
DISABLE_UPDATESTurns off the check for new versions1
IGNORE_IPExcludes IP addresses and CIDR ranges from data collection, such as those of your officesA comma-separated list
SALT_ROTATIONSets how often the salt behind session IDs rotatesmonth by default
REDIS_URLAdds a Redis cache, which the documentation recommends for high-traffic websites or several instancesYour Redis address
MCP_ENABLEDOpens the /mcp endpoint: your AI assistant reads your analytics read-only, with an API key created under Settings, API keys1

Backups

Everything Umami keeps lives in its PostgreSQL database: accounts, websites, teams and analytics. Dump it every day and right before each update: self-hosted, this data is kept with no time limit. Next to the database, the .env file holds the secrets that make it usable:

ItemWhat it holdsBack up
The PostgreSQL databaseAccounts, websites, teams, reports and all analyticsRequired, with pg_dump
.envThe database password, APP_SECRET and the two-factor authentication keyRequired, encrypted
compose.yamlYour instance’s configurationRecommended

Dumping the database while it runs

pg_dump makes a consistent dump while the database is in use. The custom format, -Fc, is compressed and restores with pg_restore:

Terminal, in the compose.yaml folder
docker compose exec -T db pg_dump -U umami -d umami -Fc > umami-$(date +%F).dump

Schedule this command on the server at least once a day, prune the dumps, which pile up, and send a copy elsewhere. Kept on the server’s disk, these dumps are also part of its nightly backups.

Restoring

  1. Stop Umami, leaving the database running: docker compose stop umami.
  2. Restore the dump into the database, replacing existing objects.
  3. Start Umami again, then check that your websites and their analytics are there.
Terminal
docker compose stop umami
docker compose exec -T db pg_restore -U umami -d umami --clean --if-exists < umami-YYYY-MM-DD.dump
docker compose start umami

Repeat this drill from time to time, on a copy: that is how you check that a backup works.

Updates

The documentation gives two commands, from the compose.yaml folder. The database stays in its volume:

Terminal
docker compose pull
docker compose up --force-recreate -d

On restart, the container applies the schema migrations by itself. Version 3.4.0, of 17 September 2026, carried two of them, for annotations and API keys; version 3.4.1, of 23 October 2026, carries none. After a major upgrade, such as the move to version 3, the documentation suggests running ANALYZE in PostgreSQL so that dashboards get their speed back:

Terminal
docker compose exec db psql -U umami -d umami -c "ANALYZE;"

Who does what on a managed VPS

Self-hosting means running the server on top of the application. On a managed VPS, our teams take charge of the server and proactively monitor your instance; Umami remains your software, with its settings and its data.

TopicOur teamsYou
The serverSystem and security updates, server interventions includedThe timing that suits your business
MonitoringServer monitored 24/7, with intervention without waiting for your callReading your instance’s logs
UmamiProactive monitoring: errors, slowdowns and disk space spotted, fix recommendedIts installation, updates and settings, which you apply, yourself or through your AI assistant
Websites and analyticsThe server that carries them, monitored and backed upAccounts, tracked websites, the tracking script and how long data is kept
BackupsEvery night, encrypted and kept off the machine; restores includedUmami’s own dumps, and the restore request, when you need one
MigrationYour current server migrated, free of chargeThe timing of the switch

If you would rather have our teams work inside the application itself, that service is billed by the hour or at a fixed rate, with an estimate shared before the work starts.

Umami, on a server run for you

With a Simafri Managed VPS, our teams keep your Umami instance’s server up to date, monitor it day and night and step in without waiting for your call; they also proactively monitor your instance and recommend useful fixes, which you apply, yourself or through your AI assistant. Backups are encrypted every night and kept off the machine, restores are included, and migrating your current server is complimentary.

Explore Managed VPS

Frequently asked questions

Is Umami free for a business?

Yes. Umami is under the MIT license: you can use, modify and redistribute it at work with no license to buy, as long as you keep its copyright notice. What remains is the cost of the server that runs it.

Does Umami use cookies?

No. The project’s FAQ states that the Umami web tracker does not use cookies. Whether your website needs a cookie notice depends on the other services you use on it and the requirements that apply.

Does Umami work with MySQL?

Not since version 3: Umami supports PostgreSQL, version 12.14 at minimum. A version 2 instance on MySQL first moves its data to PostgreSQL with the project’s migration guide, then upgrades to version 3.

How do I install Umami with Docker Compose?

Start from the project’s docker-compose.yml, which runs Umami and PostgreSQL, with random secrets in a .env file and the port published on 127.0.0.1. Run docker compose up -d, then put an HTTPS reverse proxy in front, on a subdomain.

What are the default Umami login credentials?

At installation, Umami creates an admin account with the password umami. Change it at your first login, under Settings then Profile, and enable two-factor authentication in the Security tab once TWO_FACTOR_ENCRYPTION_KEY is set.

How do I rename the Umami tracking script?

On a self-hosted instance, TRACKER_SCRIPT_NAME gives the script another name than script.js, and COLLECT_API_ENDPOINT renames the /api/send collection endpoint. Then change the source of the tracking code on your pages.

How do I back up Umami?

Dump the PostgreSQL database every day with pg_dump, from the database container, and keep the .env file separately, as it holds APP_SECRET and the two-factor authentication key. Restore with pg_restore, and test the restore regularly.

Does a managed VPS cover Umami?

A managed VPS covers the server: system, security, monitoring and backups. Our teams also proactively monitor your instance and recommend useful fixes, which you apply. Work inside the application is billed by the hour or at a fixed rate.

Contact us