Skip to main contentSkip to navigation
[email protected]
Client AreaSupport
Hosting Mammoth
HostingMammothYour Data, Our Responsibility
Home
Solutions
Hosting Services
Store
Pricing
About
Blog
API
Contact

Stay Ahead of the Curve

Get the latest insights on cybersecurity, AI innovations, and enterprise data solutions delivered to your inbox.

Hosting Mammoth
HostingMammothEnterprise Solutions

Enterprise-grade data solutions. Hosting, recovery, cybersecurity, and AI-powered services for businesses worldwide.

[email protected]
Sun - Fri, 9:00am - 5:00pm

Services

  • Cloud Hosting
  • Data Recovery
  • Cybersecurity
  • Legal Support
  • MSP Services
  • Web Development
  • AI Services
  • Free Server Migration

Hosting

  • VPS Hosting (NVMe SSD)
  • VDS Hosting (NVMe)
  • Storage VPS (High SSD)
  • GPU Servers
  • Managed Services
  • Cloud Firewall
  • Load Balancer
  • One-Click Apps
  • n8n Hosting
  • Object Storage
  • FAQ

Company

  • Store
  • Pricing
  • About Us
  • Locations
  • Blog
  • Testimonials
  • Contact
  • Affiliate Program
  • White-Label
  • Terms of Service
  • Privacy Policy
  • Browser Cookies
  • SLA

Support

  • Client Area
  • Submit Ticket
  • Knowledge Base
  • Server Status
  • API Documentation

© 2026 Hosting Mammoth. All rights reserved.

Knowledge Base
Getting StartedAccount ManagementVPS HostingGPU ServersStorage VPSCloud FirewallLoad BalancerServer ManagementBilling & PaymentsSupport & TicketsAffiliate ProgramReseller ProgramMarketplace & Appsn8n HostingManaged ServicesServer MigrationAPI & DevelopersSecurityTroubleshootingGlossaryInstall Guides
  1. Home
  2. /
  3. Support
  4. /
  5. Install Guides
  6. /
  7. How To Install Umami Ubuntu
GUIDEInstall Guides

How to Install Umami Analytics on Ubuntu 24.04

15 min read

How to Install Umami Analytics on Ubuntu 24.04 — A Privacy-First Google Analytics Alternative

Umami is the simplest way to get clean, privacy-respecting website analytics without feeding a third-party ad network or adding a cookie banner. This guide walks you through a production-grade Umami v2 install on Ubuntu 24.04 — from fresh VPS to TLS-secured dashboard.

Skip the setup? Deploy Umami in one click. Launch a CloudCore Starter VPS and have your first dashboard live in under 90 seconds.

Table of Contents

  • What is Umami?
  • Umami v2 Features
  • Why Self-Host Umami?
  • Architecture
  • Prerequisites
  • Step 1: Update System Packages
  • Step 2: Install Docker and Docker Compose
  • Step 3: Create the docker-compose.yml
  • Step 4: Start Umami and Run Migrations
  • Step 5: First Login and Password Change
  • Step 6: Add a Website and Install the Tracking Script
  • Step 7: Track Custom Events and Properties
  • Step 8: Reports, Teams, and Shared Views
  • Step 9: Build an Event Funnel
  • Step 10: Bypass Ad Blockers with a CNAME
  • Step 11: Nginx Reverse Proxy and TLS
  • Step 12: Backups and Updates
  • Using the Umami API
  • Troubleshooting
  • FAQ
  • Next Steps
  • What is Umami?

    Umami is a simple, fast, open-source web analytics platform released under the permissive MIT license. It gives you the numbers that matter — unique visitors, pageviews, referrers, countries, devices, and custom events — without cookies, without fingerprinting, and without handing visitor data to Google.

    Compared to Plausible, Umami is simpler to operate, stays fully free as MIT, and needs no license key for commercial use. Compared to Matomo, it is dramatically lighter. Because Umami collects only anonymous, aggregated data and sets no cross-site cookies, you do not need a GDPR cookie banner.

    Umami v2 Features

    Umami v2 is a substantial rewrite of the original v1:

    • Unlimited websites, each with its own tracking ID and dashboard.
    • Teams — invite users, assign roles (owner, admin, view-only), scope access per team.
    • Reports — Insights, Funnel, Retention, UTM, Goals, and User Journey.
    • Shared views — public URLs to share any dashboard without giving stakeholders an account.
    • Custom events and properties — track clicks, form submits, signups with arbitrary metadata.
    • UTM tracking — full utm_source, utm_medium, utm_campaign, utm_term, utm_content.
    • API access — bearer-token REST API for reading data and managing websites.
    • Realtime dashboard and a small Next.js footprint (~200 MB RAM at idle).

    Why Self-Host Umami?

    Umami Cloud Free caps at 10K events/month and 3 websites. Self-hosting wins when:

    • You have more than 10K monthly events — the cloud free tier runs out quickly.
    • You run multiple client sites — no per-website limits.
    • You want full data ownership — every row lives in your own Postgres.
    • You need to bypass ad blockers — only self-hosted can serve the tracker from your own domain.
    • You are under data-residency rules (EU, healthcare, finance).

    Cost Comparison

    ScenarioGA4Umami Cloud ProPlausible CloudSelf-Hosted Umami
    Monthly costFreefrom $20/mofrom $9/moEUR 7.99/mo (VPS)
    Cookie bannerYesNoNoNo
    Data leaves your server?YesYesYesNo
    Event limitSoft/sampledPer tierPer tierDisk space
    WebsitesUnlimited3+10+Unlimited

    Architecture

    Umami v2 is a small, predictable stack:

    • Umami app — a Next.js application serving both the admin UI and the /api/send tracking endpoint on port 3000.
    • Database — PostgreSQL 12+ (recommended) or MySQL 8+ for websites, users, sessions, and events.
    • Tracker — a ~2 KB JS file at /script.js.
    No Redis, no object storage, no workers. Migrations run automatically on container start.

    Prerequisites

    You need:

    • Ubuntu 24.04 LTS VPS with root or sudo access and SSH
    • 2 vCPU, 2 GB RAM, 20 GB disk minimum
    • A domain (e.g. analytics.yourdomain.com) with an A record to your VPS IP
    • Ports 80/443 open for Let's Encrypt and the dashboard
    Recommended Plan: CloudCore Starter
    >
    For production Umami tracking up to several million events per month, we recommend CloudCore Starter: 2 vCPU, 2 GB RAM, 40 GB NVMe, unmetered bandwidth, EUR 7.99/month. Enough headroom for the app, Postgres, Nginx, and backups.

    Connect to your server via SSH:

    bash
    ssh root@your-server-ip

    Step 1: Update System Packages

    Bring the system up to date:

    bash
    sudo apt update && sudo apt upgrade -y
    sudo apt install -y curl ca-certificates gnupg ufw

    Reboot if the kernel was upgraded.

    Step 2: Install Docker and Docker Compose

    Umami is distributed as a Docker image. Use the official docker.com repository — not the distro package. For full instructions see How to Install Docker on Ubuntu 24.04. Quick summary:

    bash
    curl -fsSL https://get.docker.com | sh
    sudo usermod -aG docker $USER
    newgrp docker

    Verify:

    bash
    docker --version
    docker compose version

    Expected output:

    text
    Docker version 27.3.1, build ce12230
    Docker Compose version v2.29.7

    Step 3: Create the docker-compose.yml

    Create a dedicated directory for the Umami stack:

    bash
    sudo mkdir -p /opt/umami
    cd /opt/umami

    Generate a secure APP_SECRET. Umami uses this to sign session tokens — keep it private and back it up:

    bash
    openssl rand -base64 48

    Copy the resulting string; you will paste it into the compose file in a moment.

    Create /opt/umami/docker-compose.yml:

    yaml
    services:
      umami:
        image: ghcr.io/umami-software/umami:postgresql-latest
        container_name: umami
        restart: unless-stopped
        ports:
          - "127.0.0.1:3000:3000"
        environment:
          DATABASE_URL: postgresql://umami:CHANGE_ME_STRONG_DB_PASSWORD@db:5432/umami
          DATABASE_TYPE: postgresql
          APP_SECRET: PASTE_YOUR_OPENSSL_RAND_OUTPUT_HERE
          PORT: 3000
        depends_on:
          db:
            condition: service_healthy

    db: image: postgres:15-alpine container_name: umami-db restart: unless-stopped environment: POSTGRES_DB: umami POSTGRES_USER: umami POSTGRES_PASSWORD: CHANGE_ME_STRONG_DB_PASSWORD volumes: - ./pgdata:/var/lib/postgresql/data healthcheck: test: ["CMD-SHELL", "pg_isready -U umami -d umami"] interval: 10s timeout: 5s retries: 5

    Notes on that file:

    • 127.0.0.1:3000:3000 — Umami listens only on loopback until Nginx proxies it (Step 11).
    • postgres:15-alpine — Umami supports Postgres 12-16; 15 is the current sweet spot.
    • APP_SECRET — rotating this invalidates all existing sessions.
    Replace both CHANGE_ME_STRONG_DB_PASSWORD values with the same generated password (openssl rand -base64 24) and paste your APP_SECRET.

    Step 4: Start Umami and Run Migrations

    Bring the stack up:

    bash
    docker compose up -d

    Expected output:

    text
    [+] Running 3/3
     ✔ Network umami_default  Created
     ✔ Container umami-db     Started
     ✔ Container umami        Started

    Database migrations run automatically on first boot. Tail the logs:

    bash
    docker compose logs -f umami

    Look for Applying migration ... followed by ✓ Ready in 2.1s, then Ctrl+C to stop following.

    Confirm the app responds locally:

    bash
    curl -I http://127.0.0.1:3000

    Expected: HTTP/1.1 200 OK.

    Step 5: First Login and Password Change

    Umami ships with a default administrator: username admin, password umami.

    The dashboard is only on 127.0.0.1:3000. To log in from your laptop, open an SSH tunnel:

    bash
    ssh -L 3000:127.0.0.1:3000 root@your-server-ip

    Browse to http://localhost:3000, enter admin / umami, and immediately change the password under user menu → Profile → Change password. Pick 20+ characters. There is no built-in 2FA yet.

    Step 6: Add a Website and Install the Tracking Script

    In the Umami dashboard, navigate to Settings → Websites → Add website. Fill in Name and Domain (root hostname, no scheme or path). Click Save — Umami generates a Website ID (UUID).

    Click Edit on the new website, then the Tracking code tab:

    html
    <script
      defer
      src="https://analytics.yourdomain.com/script.js"
      data-website-id="b4e8b6c8-1a2d-4f9c-8e20-1234567890ab"></script>

    Standard install

    Paste this snippet into <head> on every tracked page (Next.js root layout, WordPress header plugin, etc.). The defer attribute ensures it never blocks rendering.

    Restrict to specific hostnames

    To keep preview/staging environments out of the data, add data-domains:

    html
    <script
      defer
      src="https://analytics.yourdomain.com/script.js"
      data-website-id="b4e8b6c8-1a2d-4f9c-8e20-1234567890ab"
      data-domains="example.com,www.example.com"></script>

    Events from any other hostname are silently discarded.

    Other useful attributes

    • data-auto-track="false" — disable automatic pageview tracking (useful for SPA routers).
    • data-do-not-track="true" — respect the browser's DNT header.
    • data-cache="true" — cache the session ID in localStorage.
    • data-host-url="..." — override the destination host (useful behind a CDN).

    Step 7: Track Custom Events and Properties

    Pageviews track automatically. For buttons, form submits, and funnel milestones, call window.umami.track():

    html
    <button onclick="umami.track('signup-clicked')">Sign up</button>

    Or with custom properties:

    javascript
    document.querySelector('#checkout').addEventListener('click', () => {
      umami.track('checkout-started', {
        plan: 'cloudcore-starter',
        currency: 'EUR',
        value: 11.99,
      });
    });

    Custom properties appear under Events → Event data and can be filtered, grouped, and used as funnel steps.

    Important limits

    • Event names: 50 chars. Property keys: 50 chars. Values: 500 chars.
    • Properties must be strings, numbers, or booleans (nested objects are flattened).

    Step 8: Reports, Teams, and Shared Views

    Open Reports → Create report and pick a type:

    • Insights — slice any metric by any dimension (country, browser, referrer, UTM, custom property).
    • Funnel — ordered sequence of events or URLs.
    • Retention — cohort retention by day, week, or month.
    • UTM — breakdown by utm_source, utm_medium, utm_campaign, utm_term, utm_content.
    • Goals — count event or URL hits within a date range.
    • Journey — Sankey visualization of visitor paths.

    Teams

    Under Settings → Teams, create a team and invite users as owner, manager, member, or view-only. One team per client is a clean agency pattern — invite each client as view-only so they see only their own numbers.

    Shared public views

    For stakeholders without accounts: open a website → Edit → Share URL → toggle Enable share URL, then send the URL. The shared view renders the dashboard without exposing settings, event IDs, or API keys.

    Step 9: Build an Event Funnel

    Suppose you want to measure a three-step signup funnel: pricing page → CTA click → signup completed.

    Instrument the events in your app code:

    javascript
    document.querySelector('#cta-primary').addEventListener('click', () => {
      umami.track('cta-clicked', { placement: 'hero' });
    });
    umami.track('signup-completed', { plan: selectedPlan });

    Create the funnel report. Go to Reports → Create report → Funnel:

  • Step 1 — URL equals /pricing
  • Step 2 — Event equals cta-clicked
  • Step 3 — Event equals signup-completed
  • Set date range (last 30 days), click Run query.
  • Umami returns a stacked bar chart with drop-off percentages between steps. Save the report, add it to a dashboard, or share via public URL. Keep funnels to 3-5 steps.

    Step 10: Bypass Ad Blockers with a CNAME

    The default /script.js filename is not on major blocklists today, but some privacy tools block anything that smells like analytics. The most reliable countermeasure is to serve the tracker from a first-party subdomain of the tracked site.

    Option A: Subdomain CNAME

    Create a CNAME on the tracked site: stats.example.com CNAME analytics.yourdomain.com. Then load the tracker from the first-party subdomain:

    html
    <script
      defer
      src="https://stats.example.com/script.js"
      data-website-id="b4e8b6c8-1a2d-4f9c-8e20-1234567890ab"
      data-host-url="https://stats.example.com"></script>

    Make sure your Nginx config (Step 11) covers stats.example.com with its own Let's Encrypt cert.

    Option B: Rename the script file

    In Nginx, alias /script.js to a non-obvious path:

    nginx
    location = /pageloader.js {
        proxy_pass http://127.0.0.1:3000/script.js;
    }

    Reference src="https://stats.example.com/pageloader.js". Combined with the CNAME, the tracker is practically invisible to generic blocklists.

    Step 11: Nginx Reverse Proxy and TLS

    Time to put Umami behind a real domain with HTTPS. For Nginx fundamentals see How to Install Nginx on Ubuntu 24.04.

    Install Nginx and Certbot:

    bash
    sudo apt install -y nginx certbot python3-certbot-nginx

    Create /etc/nginx/sites-available/umami:

    nginx
    server {
        listen 80;
        server_name analytics.yourdomain.com;

    location / { proxy_pass http://127.0.0.1:3000; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade";

    proxy_read_timeout 90s; client_max_body_size 2m; } }

    Enable and test:

    bash
    sudo ln -s /etc/nginx/sites-available/umami /etc/nginx/sites-enabled/
    sudo nginx -t && sudo systemctl reload nginx

    Obtain an SSL certificate:

    bash
    sudo certbot --nginx -d analytics.yourdomain.com

    Certbot rewrites the server block for HTTPS and auto-renews via systemd timer. Finally, tighten the firewall:

    bash
    sudo ufw allow OpenSSH
    sudo ufw allow 'Nginx Full'
    sudo ufw enable

    Port 3000 is never exposed — Nginx is the only process listening publicly.

    Step 12: Backups and Updates

    A daily pg_dump is all you need. Create /opt/umami/backup.sh:

    bash
    #!/usr/bin/env bash
    set -euo pipefail
    BACKUP_DIR=/var/backups/umami
    TS=$(date +%Y%m%d-%H%M%S)
    mkdir -p "$BACKUP_DIR"

    docker exec umami-db pg_dump -U umami -d umami \ | gzip > "$BACKUP_DIR/umami-$TS.sql.gz"

    Keep 14 days

    find "$BACKUP_DIR" -name "umami-*.sql.gz" -mtime +14 -delete

    Schedule it:

    bash
    sudo chmod +x /opt/umami/backup.sh
    ( sudo crontab -l 2>/dev/null; echo "15 3   * /opt/umami/backup.sh" ) | sudo crontab -

    To restore:

    bash
    gunzip -c umami-20260416-031500.sql.gz \
      | docker exec -i umami-db psql -U umami -d umami

    Updating Umami

    Umami releases every 2-4 weeks. Update with:

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

    Migrations run automatically. Take a fresh backup before major version bumps.

    Using the Umami API

    Umami exposes a bearer-token REST API for automation.

    Generate an API key under user menu → Profile → API keys → Create API key (shown only once).

    Create a website:

    bash
    curl -X POST https://analytics.yourdomain.com/api/websites \
      -H "Authorization: Bearer YOUR_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{"name": "Client XYZ", "domain": "clientxyz.com"}'

    Read stats:

    bash
    curl -H "Authorization: Bearer YOUR_API_KEY" \
      "https://analytics.yourdomain.com/api/websites/WEBSITE_ID/stats?startAt=1711929600000&endAt=1713139200000"

    Returns pageviews, visitors, sessions, bounce rate, and total time. Full reference: umami.is/docs/api.

    Troubleshooting

    ProblemCauseSolution
    Events not recordedTracking script missing on page, or hostname not in data-domains allowlistOpen browser devtools → Network, confirm script.js loads and /api/send returns 200. Remove or fix data-domains.
    Tracker blocked by uBlock / Brave Shield/script.js matches a generic blocklist entryServe from a first-party CNAME (Step 10) and rename the script path.
    500 error on startupDATABASE_URL wrong, or Postgres not healthy yetRun docker compose logs db — wait for database system is ready to accept connections. Verify user/password/host in the URL.
    Migrations failedManual edits to the schema or a failed mid-upgradeRestore from backup, or run docker compose exec umami npx prisma migrate deploy to reapply.
    Dashboard loads but no data in realtimeApp container cannot reach db servicedocker compose exec umami ping -c1 db — if it fails, the compose network is broken; docker compose down && docker compose up -d.
    413 Request Entity Too LargeNginx client_max_body_size too small for event payloads with many propertiesRaise to 5m in the server block and reload Nginx.
    Timezone shows UTC, want localTZ env var not setAdd TZ: Europe/Madrid (or your zone) to the umami service environment and docker compose up -d.

    Viewing logs

    bash
    docker compose logs -f umami    # app
    docker compose logs -f db       # postgres

    Ctrl+C to stop following.

    FAQ

    Umami vs. Plausible — which one should I self-host?

    Umami is MIT-licensed (trivial commercial use and white-labeling) and has more built-in reports (Funnel, Retention, Journey, UTM) plus a cleaner teams model. Plausible has a more polished default dashboard, but its self-hosted Community Edition is AGPL and lags the Cloud release. For agencies and SaaS teams, Umami is usually the better fit.

    Umami vs. GoatCounter — is Umami overkill?

    GoatCounter is a single-binary Go project with no teams, funnels, or custom events. Perfect for personal sites. If you need funnels, event properties, teams, or to manage dozens of client sites, choose Umami.

    Umami vs. Matomo — which is heavier?

    Matomo is an open-source GA clone with heatmaps, session recordings, and plugins. It needs roughly 4 GB RAM and a dedicated MySQL server. Umami does ~20% of what Matomo does in ~5% of the resources. If you need session recording, use Matomo or Clarity. For numbers, funnels, and UTM — Umami wins on operational simplicity.

    How long does Umami keep data?

    Forever, by default. No built-in retention policy. Expect roughly 1 GB per 10M events. To enforce a window, run a monthly cron that deletes old rows from the event table and runs VACUUM FULL.

    Is Umami really GDPR-compliant out of the box?

    Umami stores no raw IPs, sets no cookies, and derives session IDs from a hashed combination of IP, user agent, and daily salt. This class of aggregated, non-identifying analytics does not require a cookie banner under GDPR/ePrivacy. Custom events attaching a userId or email are personal data and must be covered by your consent flow.

    Can I run Umami multi-tenant?

    Yes. One instance can host hundreds of websites scoped to teams. For hard isolation, run one Umami container per tenant with its own Postgres — the image is small enough to be cheap on a moderately sized VPS.

    Next Steps

    Recommended follow-ups:

    • Connect Umami to Grafana — Postgres is readable by any BI tool.
    • Add server-side events — fire purchase-completed from your payment webhook.
    • Uptime monitoring — add an Uptime Kuma check for /api/heartbeat.
    • Integrate with Next.js — the official @umami/react package provides typed hooks.
    • Pair with Microsoft Clarity — Umami for numbers, Clarity for recordings.

    Skip the Manual Install — Get Umami Pre-Installed
    >
    Our CloudCore Starter VPS comes with a one-click Umami image: Docker, Postgres 15, Umami v2, Nginx, Let's Encrypt, and daily backups all pre-configured.
    >
    - Umami v2 latest, pinned and auto-updated
    - PostgreSQL 15 with daily pg_dump
    - Nginx + Let's Encrypt for your domain
    - ufw locked to ports 22, 80, 443
    - Admin password rotated and emailed to you
    >
    Deploy Your Umami VPS Now — CloudCore Starter from EUR 7.99/month.

    Was this article helpful?

    ← Back to Install GuidesBrowse all categories →

    Still have questions?

    Contact Support →Submit a Ticket