Self-host Umami on a VPS

Run Umami, simple cookie-free website analytics, on your own VPS with PostgreSQL in Docker and HTTPS on your own domain.

To self-host Umami on a VPS, run its Docker Compose setup (Umami and PostgreSQL) with the app on localhost, change the default admin / umami login before anyone can reach it, and serve it over HTTPS on a domain such as stats.example.com. On VPSNine the Umami one-click app does all of that except naming the domain, which takes one command.

Umami counts page views, referrers, devices and custom events without cookies. It suits a few sites that want light statistics without a heavy database to look after.

What you need

  • The Budget plan (2 GB) is enough for Umami and PostgreSQL with modest traffic. Umami publishes no minimum; a busy site grows the database, so watch disk and memory and move up when PostgreSQL wants more. The plans page has the specs.
  • A domain or subdomain for it, like stats.example.com. The tracking script has to load over HTTPS from your sites, so this isn't optional.

Install it with the one-click app

Order a server with the Umami app. It installs Docker and runs the compose setup from Umami's repository (Umami's image and postgres:15-alpine) in /opt/umami, with generated secrets in /opt/umami/.env. Umami listens only on 127.0.0.1:3000. Umami ships with the login admin / umami; the installer changes that password through Umami's API before anything can reach it, and Umami has no public sign-up.

  1. From your computer, open a tunnel to it:

    bash
    ssh -L 3000:127.0.0.1:3000 root@203.0.113.10

    In that session, run cat /root/umami-admin.txt for the password, then open http://localhost:3000 and log in as admin.

  2. Set up HTTPS (next section).

  3. Add your website in Umami's settings and paste its tracking script into your pages. Each website gets its own script and dashboard.

On the server, curl http://127.0.0.1:3000/api/heartbeat answers when Umami is up.

Put it on your domain with HTTPS

Point an A record for stats.example.com at the server, allow ports 80 and 443 in the panel firewall, then run:

bash
vps9-https stats.example.com

It installs Caddy from Caddy's own packages, writes a Caddyfile that proxies the domain to Umami on 127.0.0.1:3000, and reloads Caddy, which gets and renews the certificate. Umami needs no settings changed for this, so there's no app step. From then on, log in at https://stats.example.com, and the tracking script loads from that domain:

html
<script defer src="https://stats.example.com/script.js" data-website-id="your-website-id"></script>

Copy the exact snippet from Umami's website settings, which fills in the ID for you.

Doing it by hand on another server

Umami's install guide uses the compose file in its repository:

bash
git clone https://github.com/umami-software/umami.git
cd umami
docker compose up -d

Before starting it, edit the compose file: set your own database password, set APP_SECRET to a random string (openssl rand -hex 32), and bind the port to 127.0.0.1:3000:3000 so Docker doesn't publish it to the internet. Then open it through an SSH tunnel and change the admin / umami password straight away. Put Caddy or nginx in front for HTTPS, as in Serve a site with nginx and HTTPS.

Updates and backups

Read the release notes, then:

bash
cd /opt/umami
docker compose pull
docker compose up -d

The one-click app turns on the operating system's automatic security updates; Umami's images are yours to update.

Back up the database with pg_dump, and keep /opt/umami/.env with it, since it holds the database password and app secret:

bash
cd /opt/umami
docker compose exec -T db pg_dump -U umami umami > /root/umami-$(date +%F).sql
cp .env /root/umami-env-$(date +%F)

Copy both off the server. Backups you should run shows how to schedule it.

When it goes wrong

  • Visits from some people never show up: some ad blockers block Umami's default script name. Umami can serve the script and its collection endpoint under other names with TRACKER_SCRIPT_NAME and COLLECT_API_ENDPOINT. Add them to the umami service's environment in /opt/umami/compose.yaml, for example TRACKER_SCRIPT_NAME: stats.js and COLLECT_API_ENDPOINT: /api/hit, run docker compose up -d, and change the src in your pages to match.
  • No visits at all: the script isn't loading. Open your site with the browser's developer tools on the Network tab and check the request to stats.example.com succeeds, and that data-website-id matches the website in Umami.
  • https://stats.example.com doesn't load: DNS doesn't point at the server yet, or ports 80 and 443 are closed in the panel firewall. Check with getent hosts stats.example.com on the server and run vps9-https stats.example.com again once it resolves.

Be first when orders open

Join the waitlist and we'll send you one email when VPSNine launches. Pick a plan if you already know which one you want, and we'll size the first servers around it.

  • One email, on launch day
  • Monthly or yearly, no lock-in
  • 14-day money-back guarantee