Deployment guide

How to Host Umami on a VPS

Deploy on a VPS Cloud →

Tutorial

Self-hosting

How to Host Umami on a VPS

Umami is an open-source web analytics tool that is lightweight and privacy-friendly: it measures your audience without cookies or collecting personal data. Self-hosted on your VPS, it makes you the owner of your traffic statistics, without handing them to an ad network. Here is how to deploy it with Docker, a PostgreSQL database, a reverse proxy and a TLS certificate — and how to fix the three issues that block most deployments at startup.

7 min read10 steps
Contents· Why self-host Umami on a VPS1/8
  1. 01Why self-host Umami on a VPS
  2. 02The concrete benefits of a self-hosted Umami
  3. 03Hardware and software requirements
  4. 04Deploy Umami with Docker and HTTPS
  5. 05Common startup issues
  6. 06Updating Umami
  7. 07Umami Cloud vs self-hosted
  8. 08The official documentation

Why self-host Umami on a VPS

Umami is a lightweight alternative to Google Analytics: open source, cookieless, no data sent to third parties. On a VPS, you retain full control — no SaaS account, no site limit, no shared data. The Docker stack is minimal: a Node.js container for the app and a PostgreSQL container for the database. The whole setup takes under ten minutes on a standard VM with root access, and your data stays on your server.

Compared to Google Analytics 4, Umami doesn't require consent for anonymised statistics in most European jurisdictions. Compared to Matomo, its memory footprint is significantly lower, and its Docker setup is a single docker-compose.yml. For an agency managing ten clients, a single Umami instance with ten sites replaces a per-user or per-domain SaaS subscription. Version 2.14 (July 2026) added native custom events support and a CSV-exportable dashboard — two features long awaited by marketing teams.

The concrete benefits of a self-hosted Umami

  • Privacy-compliant: no cookies, no personal data, often no consent banner required.
  • Your audience statistics stay on your server, with no sharing to a third party.
  • A tracking script of a few kilobytes, with no cookie and no personal data collected.
  • Clear, multi-site dashboard from a single instance.
  • Fixed cost regardless of the volume of page views.

Hardware and software requirements

Umami runs on any VPS with Docker installed. The recommended minimum is 1 vCPU and 512 MB RAM for personal or SMB use; above 200,000 monthly page views, 1 GB RAM avoids PostgreSQL slowdowns. You will need: Docker Engine (≥ 20.10) and Docker Compose V2 (docker compose, not docker-compose), a domain or subdomain pointing to your VPS, and a reverse proxy (nginx or Caddy) to serve Umami over HTTPS. Debian 12 and Ubuntu 22 are the reference distributions; the commands below assume root or sudo access.

On the server side, open ports 80 and 443 in your firewall (ufw allow 80/tcp && ufw allow 443/tcp). Umami only needs HTTPS exposed externally; the application port (3000 by default) stays internal and is never opened directly. If you're using a ServOrbit VPS, the default security group already allows 80 and 443.

Deploy Umami with Docker and HTTPS

  1. Prepare the VPS and Docker

    Over SSH, update the system and install Docker via curl -fsSL https://get.docker.com | sh. Create mkdir -p /opt/umami && cd /opt/umami.

  2. Write the docker-compose.yml

    Define two services: ghcr.io/umami-software/umami:postgresql-latest and a postgres database. Fill in DATABASE_URL and a random APP_SECRET.

  3. Start the containers

    Run docker compose up -d. Umami listens locally on port 3000; the database is initialised automatically on first start.

  4. Configure the reverse proxy

    With Caddy: stats.your-domain.com { reverse_proxy localhost:3000 }. The Let's Encrypt certificate is obtained and renewed automatically.

  5. Add your site and the script

    Log in (admin/umami by default, change it immediately), add your site and paste the tracking snippet provided into the <head> of your pages.

Common startup issues

Three root causes account for the vast majority of failures reported in 2026 community guides. Here they are with their diagnosis and fix.

1. Restart loop "Can't reach database server" — DATABASE_URL does not match POSTGRES_PASSWORD

This is the most common copy-paste trap: DATABASE_URL contains the password in plain text inside the connection string, and that password must be exactly the same as the value of POSTGRES_PASSWORD in the db service. If you change one without the other, Umami starts, fails to reach the database, and restarts in a loop — with no clear error message in the Docker logs.

Verify that both variables are consistent:

# in .env or in the compose file
POSTGRES_PASSWORD=strong_password

# in DATABASE_URL, the same password in position 3
DATABASE_URL=postgresql://umami:strong_password@db:5432/umami

If you use variable interpolation (${POSTGRES_PASSWORD}), make sure Docker Compose is actually loading your .env file.

2. Umami crashes 5 to 10 seconds after startup — depends_on without healthcheck

By default, depends_on: db only waits for the PostgreSQL container to be started, not for it to be ready to accept connections. Umami then tries to connect while PostgreSQL is still initialising its data files, fails, and exits.

Add a healthcheck on the db service and a condition: service_healthy in Umami's depends_on:

services:
  db:
    image: postgres:15-alpine
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U umami"]
      interval: 10s
      timeout: 5s
      retries: 5
  umami:
    image: ghcr.io/umami-software/umami:postgresql-latest
    depends_on:
      db:
        condition: service_healthy

With this configuration, Umami only starts once PostgreSQL is responding on its socket.

3. 502 error after docker compose pull — published port has changed

After an update (docker compose pull + docker compose up -d), nginx may return a 502 error if the configuration changed between image versions: the internal port may have been remapped or the host binding changed. First check the actual state of the containers:

docker compose ps

Look at the PORTS column to confirm that the Umami container is publishing on the expected port (3000 by default). If the port has changed, update the proxy_pass (or reverse_proxy) directive in nginx or Caddy to reflect the new port, then reload the service (nginx -s reload or systemctl reload caddy).

4. docker-compose (v1) vs docker compose (v2) — silent failure

Guides published before 2025 often use docker-compose (hyphen), the unmaintained Python client. On a fresh Docker Engine install, this command doesn't exist: the terminal just returns command not found, without saying that v2 is called docker compose (space). Verify with docker compose version — if it responds, you have v2. All examples in this guide use docker compose (v2).

Updating Umami

  1. Back up the database

    Before any update: docker compose exec db pg_dump -U umami umami > umami-backup-$(date +%F).sql. Keep this file outside the Docker volume — it won't survive a volume removal.

  2. Pull the latest image

    docker compose pull. Umami publishes releases on GitHub (github.com/umami-software/umami/releases) — check release notes for schema migrations or environment variable changes.

  3. Restart the stack

    docker compose up -d. Umami runs migrations automatically on startup. Check logs with docker compose logs -f app and wait for the Listening on port 3000 message.

  4. Verify the version in the UI

    Settings → About. If the version is unchanged, the image may not have been re-pulled: docker compose images shows the digest of each running image.

  5. Check tracking works

    Open a tracked site in a private tab and wait 30 seconds — the Realtime page should record the visit. A persistent 0 after a restart usually indicates a tracking script issue on the frontend side.

Umami Cloud vs self-hosted

Umami offers a managed Cloud plan (umami.is/pricing) from $9/month for teams who prefer not to manage infrastructure. Self-hosting on a VPS makes sense if you already have a VM, manage multiple sites, or if your organisation's data policy prohibits sending data to an external SaaS — even GDPR-compliant ones. Both options share the same codebase, features, and export format.

Change the default administrator password on your first login, and back up the PostgreSQL database regularly: it is what holds your entire audience history.

The official documentation

For advanced configuration and options specific to the tool, refer to the official Umami documentation. This guide covers going live on a VPS; the vendor's documentation remains the reference for fine-tuning, major updates and specific use cases.

Deploy your instance on a ServOrbit Cloud VPS

A ServOrbit Cloud VPS with Docker preconfigured and scalable resources lets you install this tool without friction, and adjust RAM and vCPU as usage grows.