Running Self-Hosted Analytics on a VPS

TL;DR / Summary: A privacy-friendly analytics tool on a VPS needs almost no resources, but it does need a retention policy. Left alone, a visit table grows until the disk fills and the database slows to a crawl.

The workload is smaller than you think

Self-hosted analytics without cookies stores far less than a traditional platform. There is no cross-site tracking, no long user history, and often no personal data at all—just page views, referrers, and coarse device information.

That means the database is small and the queries are simple aggregates. A single vCPU and 1 GB of RAM handles a site with tens of thousands of monthly visits comfortably.

The resource risk is not traffic spikes. It is unbounded growth combined with a reporting query that scans a large table.

A realistic specification

One vCPU, 1 GB RAM, 25 GB SSD is ample for a single site. If you run several sites on one instance, the limit is usually disk rather than CPU.

Memory matters more than CPU because the database will cache indexes and query results. Below 1 GB, the database starts evicting cache and aggregate queries become noticeably slower.

  • CPU — 1 vCPU is enough; analytics is mostly idle
  • RAM — 1 GB minimum, 2 GB comfortable for multiple sites
  • Disk — 25 GB, with retention configured from day one
  • Bandwidth — modest; the tracking script is tiny

Do not size for the marketing page’s claimed capacity. Size for your actual traffic and let retention control growth.

The tracking script cost

Privacy-friendly analytics scripts are usually a few kilobytes, served from your own domain. That is both a performance benefit and a privacy benefit, since there is no third-party request.

Serve it with a long cache lifetime and compression. It is the single most requested asset on every page, so caching it properly reduces load more than any server tuning.

Retention is the whole game

Raw visit data has diminishing value over time. You need recent detail and long-term aggregates, not three years of individual page views.

Set raw retention to something like ninety days and keep monthly aggregates indefinitely. Most tools support this split natively; where they do not, a scheduled job can summarise and delete.

Check the retention setting after every upgrade. A reset during an update is a quiet way for the table to start growing again.

Retention is not a storage decision. It is a performance decision.

Backups and their real value

Analytics data is less critical than transactional data, but a year of history is still worth keeping. A nightly dump retained for a fortnight, plus a monthly archive, is sufficient.

The monthly archive can be compressed aggressively. Aggregate data compresses well, and it is the part you are most likely to want in two years.

Store one archive off the server. A backup on the same disk is not a backup, and analytics is exactly the kind of low-priority data that gets forgotten until the disk fails.

Running it behind a reverse proxy

If you already run a reverse proxy for other services, put analytics behind it rather than exposing a second public port. One entry point is easier to secure and easier to monitor.

Forward the real client IP correctly. Analytics that logs the proxy’s address instead of the visitor’s produces useless geography and useless referrer data.

Check that the forwarded headers are trusted only from the proxy. A misconfigured header allows anyone to spoof their address, which corrupts the data.

Preventing bot pollution

Bot traffic inflates numbers and hides real trends. Most privacy-friendly tools filter common crawlers by user agent, and that catches the majority.

Add a filter for requests without a referrer from your own pages if the tool supports it. Direct hits with no session are usually bots.

Review the top referrers monthly. A sudden spike from an unexpected source is almost always a scraper, and filtering it changes the picture significantly.

What to monitor

Watch three things: disk usage, database size, and the time taken by your main dashboard query. Those three reveal most problems before users notice slow pages.

Set a disk alert at eighty percent. Analytics is the service most likely to fill a disk silently, because it grows without any human action.

Log rotation matters too. Application logs on a low-traffic service can still grow over months if nothing prunes them.

Is it worth self-hosting

For a single site, a hosted analytics service is often cheaper in time. Self-hosting makes sense when you run several sites, want full data ownership, or need to avoid third-party scripts for compliance reasons.

If those reasons apply, a modest instance from virtual servers VPS is more than enough capacity, and the operational work is a few hours a year.

The service is genuinely low-maintenance once retention is configured. The mistake is treating it as set-and-forget before setting the one thing that controls its long-term size.

Aggregating for long-term trends

Raw pages are useful for a month and useless for a year. Aggregate into daily or weekly totals and keep those indefinitely; they are small and they answer the questions people actually ask.

Aggregation also removes personal data from the long-term set, which simplifies any privacy obligations the site may have.

Schedule the aggregation before the deletion, in that order. A job that deletes first and aggregates second loses the data it was meant to summarise.

Dashboards that stay fast

Point dashboards at aggregates rather than raw tables. A dashboard querying a year of raw rows will be slow on a small box, and slow dashboards stop being used.

Cache the expensive dashboard query for a few minutes. Analytics does not need to be real-time, and a five-minute cache removes most of the load.

Review the dashboard monthly and delete panels nobody reads. Every unused panel is a query that still runs.