BLOG

Self-Hosting Analytics with Umami

Dave Cilluffo ·
analyticsprivacyUmamiself-hostingweb development

Google Analytics is overkill for most sites and a privacy nightmare for all of them. Here’s how we replaced it with something better.


The Moment I Stopped Caring About Bounce Rate Segments

I stopped using Google Analytics about a year ago. Not because of some grand privacy crusade, but because I looked at my dashboard one day and realized I was tracking 47 different metrics for a website that gets maybe 500 visits a month. That’s not analytics. That’s hoarding.

I manage over a dozen websites at TwelveTake Studios. Some are client sites, some are creative projects, some are experiments. For all of them, I needed the same thing: a simple answer to “is anyone actually looking at this?” Google Analytics was never the right tool for that question. It was always the default tool, which is a very different thing.

So I replaced it. With something open source, self-hosted, privacy-respecting, and — critically — something I actually look at. Here’s the whole story.


Why Not Google Analytics

Let me be specific about what’s wrong with GA, because “it’s bad for privacy” is true but vague. The problems are concrete and practical.

GA4 is genuinely worse than Universal Analytics. If you went through the UA-to-GA4 migration, you already know this. Google took a product that was overpowered but at least comprehensible, and replaced it with something that’s overpowered and confusing. The event-based model is theoretically more flexible, but in practice it means every report requires more configuration, the real-time view is less useful, and simple questions like “how many people visited my site yesterday” now involve navigating a labyrinth of menus. I’ve talked to developers with a decade of experience who still can’t find what they’re looking for in GA4.

You’re handing Google your users’ data for free. This is the part that should bother more people. Google Analytics isn’t free as in “gift.” It’s free as in “you are the product.” Every visitor to your site generates data that Google uses to refine their advertising network. You’re doing unpaid data collection for one of the largest advertising companies on the planet. For small site owners, Google gets far more value from your GA data than you do.

Most features are irrelevant for small and medium sites. Conversion funnels. Audience segments. Attribution modeling. E-commerce tracking. Cohort analysis. If you’re running a SaaS with millions of users, sure, you might need some of that. If you’re running a blog, a portfolio site, or a small business page, you need none of it. The features aren’t just unused — they’re noise that makes the useful data harder to find.

Cookie consent banners are a UX disaster. Because GA uses cookies for tracking, you’re legally required (in the EU, and increasingly elsewhere) to show a consent banner. Those banners are ugly, annoying, and they’re the first thing your visitors see. Some percentage of users will bounce immediately rather than deal with the banner. You’re degrading the experience of your site to collect data you don’t need, for a tool that’s too complex for your use case, that feeds information to a company that doesn’t need your help.

The tracking script adds page weight. The GA4 tag, including gtag.js, adds tens of kilobytes of JavaScript to every page load for a third-party service. On a static site where I’ve spent time optimizing every asset, adding unnecessary third-party scripts feels wrong on principle.

Ad blockers break your numbers anyway. Here’s the practical killer: a significant percentage of technical users run ad blockers that block Google Analytics. Estimates vary, but it’s commonly cited around 25-40% of visitors depending on your audience. If your site attracts developers, the number is higher. So your analytics are systematically undercounting the visitors you care about most. You’re making privacy tradeoffs and adding page bloat for data that isn’t even accurate.


What You Actually Need From Analytics

Before picking a replacement, I sat down and listed every piece of analytics data I’d actually looked at in the previous six months. The list was short:

  • Page views over time — is traffic going up, down, or flat?
  • Top pages — what content are people actually reading?
  • Referrers — where are visitors coming from?
  • Device and browser breakdown — am I testing on the right platforms?
  • Country/region — just rough geographic distribution

That’s it. No funnels. No conversion tracking. No audience segments. No event tracking beyond basic page views. For 90% of websites, this is the complete list of useful analytics.

If you’re running an e-commerce operation or a SaaS product, your needs are different and more complex. But most of us aren’t. Most of us just want to know if our content is reaching anyone, and where those people are coming from.


Enter Umami

Umami is an open-source, self-hosted web analytics platform. It does exactly what I described above, and almost nothing else, which is its greatest strength.

The core pitch:

  • Privacy-first by design. No cookies. No personal data collection. No fingerprinting. It’s GDPR, CCPA, and PECR compliant out of the box, which means no consent banners. This isn’t just a marketing bullet point — the architecture genuinely doesn’t collect personal data. There’s nothing to consent to.
  • Lightweight tracking script. The snippet you add to your site is around 2KB. Compare that to GA4’s footprint.
  • Clean, modern dashboard. You open it, you see your numbers, you close it. There’s no learning curve.
  • Multi-site support. One Umami instance can track as many websites as you want. Each site gets a unique tracking ID. For someone managing 14+ sites, this is essential.
  • Built on familiar technology. Umami is a Next.js application backed by PostgreSQL (or MySQL). If you’re a web developer, there’s nothing exotic in the stack.
  • Active development. The project has a strong open-source community and regular releases.

There’s a hosted version (Umami Cloud) if you don’t want to self-host, but the whole point for me was keeping the data on my own server.


Setting It Up

Here’s a practical walkthrough. I’m running this on an Ubuntu 24.04 VPS managed with HestiaCP, but the process is similar for any Linux server.

Prerequisites

You’ll need:

  • Node.js (LTS version — check Umami’s docs for the current minimum)
  • PostgreSQL (or MySQL, but I use PostgreSQL)
  • A domain or subdomain for your analytics dashboard (e.g., analytics.yourdomain.com)
  • Nginx (or another reverse proxy)

If you’re using HestiaCP, CyberPanel, or similar, PostgreSQL and Nginx are likely already available or easy to install.

Database Setup

Create a PostgreSQL database and user for Umami:

sudo -u postgres psql
CREATE USER umami WITH PASSWORD 'your-secure-password';
CREATE DATABASE umami_db OWNER umami;
GRANT ALL PRIVILEGES ON DATABASE umami_db TO umami;
\q

Clone and Configure

cd /opt
git clone https://github.com/umami-software/umami.git
cd umami

Create your environment file:

cp .env.example .env

Edit .env and set your database connection string:

DATABASE_URL=postgresql://umami:your-secure-password@localhost:5432/umami_db

That’s the only required configuration. There are optional settings for things like disabling telemetry, changing the default hash salt, and configuring the app URL, but the defaults are sane.

Build and Initialize

npm install
npx prisma migrate deploy
npm run build

The Prisma migration creates all the necessary database tables. The build step compiles the Next.js application.

Test it:

npm start

By default, Umami runs on port 3000. If everything’s working, you’ll see it at http://your-server-ip:3000. The default login is admin / umami — change this immediately.

Running as a Service

You can use Docker, PM2, or a systemd service. I prefer running things directly with systemd because it’s one less layer of abstraction and it integrates with the OS process management that’s already there.

Create a systemd service file:

sudo nano /etc/systemd/system/umami.service
[Unit]
Description=Umami Analytics
After=network.target postgresql.service

[Service]
Type=simple
User=www-data
WorkingDirectory=/opt/umami
ExecStart=/usr/bin/node /opt/umami/.next/standalone/server.js
Restart=on-failure
RestartSec=10
Environment=NODE_ENV=production
Environment=DATABASE_URL=postgresql://umami:your-secure-password@localhost:5432/umami_db
Environment=PORT=3000

[Install]
WantedBy=multi-user.target

Note: the standalone server path may vary depending on how Umami is configured to build. Check next.config.js for output: 'standalone' — if it’s set, the above path works. Otherwise, use npm start as your ExecStart command instead.

sudo systemctl daemon-reload
sudo systemctl enable umami
sudo systemctl start umami

Reverse Proxy with Nginx

Set up a subdomain (e.g., analytics.yourdomain.com) and proxy traffic to the Umami port. If you’re using HestiaCP, create the web domain first through the panel, then customize the Nginx config.

A basic Nginx config:

server {
    listen 443 ssl http2;
    server_name analytics.yourdomain.com;

    ssl_certificate     /path/to/your/cert.pem;
    ssl_certificate_key /path/to/your/key.pem;

    location / {
        proxy_pass http://127.0.0.1:3000;
        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;
    }
}

If you’re using Let’s Encrypt (and you should be), tools like Certbot or HestiaCP’s built-in SSL provisioning handle certificate management. The specifics depend on your setup.

DNS

Point your subdomain to your server’s IP in Cloudflare (or wherever you manage DNS). I use Cloudflare for all my domains, so this is just adding an A record for analytics pointing to my VPS IP. If you’re proxying through Cloudflare, make sure the orange cloud is on — it works fine with the reverse proxy setup.


Adding Umami to an Astro Site

This is the easy part. Once you’ve added a site in the Umami dashboard and received your tracking ID, you add a single script tag to your site’s <head>.

In an Astro project, open your base layout component (typically src/layouts/Layout.astro or wherever you define the <head>) and add:

<head>
  <!-- ...existing head content... -->
  <script
    defer
    src="https://analytics.yourdomain.com/script.js"
    data-website-id="your-website-id-here"
  ></script>
</head>

That’s it. One line. No npm packages, no configuration files, no build plugins. The script is tiny, loads asynchronously with defer, and starts collecting anonymous page view data immediately.

If you want to exclude yourself from tracking during development, Umami respects localhost by default — visits from localhost aren’t tracked. For production, you can add your IP to an ignore list in the Umami settings, or use the data-do-not-track attribute if you want to respect the browser’s Do Not Track setting.

For those who want to track specific events (button clicks, form submissions, etc.), Umami supports custom events with a simple data attribute:

<button data-umami-event="signup-button">Sign Up</button>

But honestly, I don’t use event tracking on most of my sites. Page views and referrers tell me what I need to know.


What the Dashboard Looks Like

The Umami dashboard is refreshingly boring, and I mean that as the highest compliment.

When you log in, you see a list of your websites. Click one, and you get:

  • A real-time visitor count at the top
  • A page views / unique visitors graph with adjustable time ranges
  • Top pages ranked by views
  • Top referrers showing where your traffic comes from
  • Browser, OS, and device breakdowns
  • Country and language distribution

Everything loads fast. The interface is responsive. There’s no “learning the tool” phase. You open it, glance at the numbers, and get on with your day.

There’s also a comparison view for looking at different time ranges side by side, and you can share public dashboard links if you want to give someone read-only access to your stats without creating an account.

The data updates in real-time. If you publish a blog post and share it, you can watch the views tick up live. It’s more satisfying than it should be.


Multi-Site Management

This is where Umami really earns its keep for someone in my position. I manage well over a dozen websites. Some get decent traffic, some are niche projects that might see 20 visitors a week. Having a single analytics dashboard for all of them is enormously convenient.

Adding a new site takes about 30 seconds:

  1. Log into Umami
  2. Go to Settings, then Websites
  3. Click “Add website”
  4. Enter the name and domain
  5. Copy the tracking ID
  6. Add the script tag to the site

No separate accounts. No per-site billing. No juggling multiple dashboards. One Umami instance, one URL to bookmark, all your data in one place.

For TwelveTake Studios, this means I can quickly check how a new site launch is performing, compare traffic patterns across related projects, and spot anomalies without logging into a dozen different services.


The Self-Hosting Philosophy

Running your own analytics is part of a broader pattern that I’ve leaned into hard over the past couple of years. At TwelveTake Studios, we also built and self-host ClusterBox, our own forms and newsletter platform. It started as a Mailchimp alternative for our own use and grew from there.

The reasoning is the same every time:

You own your data. It lives on your server, in your database. No third party has access to it. Nobody is mining it, selling it, or using it to train models. If you decide to stop using the tool, your data doesn’t disappear or become inaccessible.

No third-party dependencies. Services shut down, get acquired, change their pricing, or pivot their product. When you self-host, the only person who can pull the rug out is you.

No surprise pricing changes. This one hits close to home for anyone who’s been on the receiving end of a SaaS pricing “adjustment.” When you self-host on infrastructure you already pay for, the marginal cost of adding another service is effectively zero.

No privacy concerns to explain to clients. When a client asks “who has access to the analytics data,” the answer is simple: “We do. Nobody else.” Try saying that with Google Analytics.

Self-hosting isn’t free. It costs time and requires some technical comfort. You’re responsible for updates, backups, and uptime. But for developers who are already managing servers, the incremental effort of adding something like Umami is minimal. You’re already doing the hard part.


Alternatives I Considered

Umami wasn’t the only option I evaluated. Here’s a quick rundown of what else is out there:

Plausible Analytics is excellent. It’s open source, privacy-focused, and has a beautiful dashboard. The hosted version (Plausible Cloud) is reasonably priced and worth considering if you don’t want to self-host. The self-hosted version (Plausible Community Edition) uses ClickHouse as its data store, which adds some operational complexity compared to Umami’s PostgreSQL setup. If I weren’t self-hosting, Plausible Cloud would be my top recommendation.

Fathom is a solid paid option. Clean interface, privacy-respecting, good reputation. But it’s not open source and there’s no self-hosted option. For what I was trying to accomplish, that was a dealbreaker.

Matomo (formerly Piwik) is the heavyweight open-source analytics platform. It can do almost everything GA can do, which is both its strength and its weakness. It’s more complex to set up, more resource-intensive to run, and the interface reflects that complexity. If you need GA-level features without GA’s privacy issues, Matomo is the answer. But if you want simplicity, it’s overkill.

GoatCounter deserves a mention too. It’s minimal, open source, and the developer is refreshingly opinionated about keeping it simple. It’s worth a look if you want something even lighter than Umami.

Umami won for the combination of simplicity, self-hosting ease, multi-site support, and a dashboard that doesn’t require a training course to navigate.


Is Self-Hosting Analytics Right for You?

I want to be honest: self-hosting isn’t for everyone, and that’s fine.

If you don’t manage your own servers and don’t want to start, Plausible Cloud is a great paid alternative that shares most of Umami’s privacy philosophy. If you’re a solo blogger who just wants to know if anyone’s reading, even something as simple as checking your server access logs might be enough.

But if you’re already running a VPS, if you’re comfortable with the command line, if you care about owning your data — Umami is one of the easiest wins in the self-hosting world. The setup takes an afternoon. The maintenance is minimal. And every time you open your dashboard and see clean, simple analytics data that belongs entirely to you, on a server you control, collected without compromising your visitors’ privacy — it feels like the web working the way it should.

I haven’t looked at a Google Analytics dashboard in over a year. I don’t miss it.


If you have questions about any of this, or want to talk about self-hosting in general, reach out at contact@twelvetake.com.

Share this post

If this was useful, consider buying us a coffee.