Uptime Kuma vs Prometheus and Grafana is not really a contest, because the two answer different questions. Uptime Kuma checks your sites and ports from the outside and tells you within a minute or two that something stopped answering. Prometheus collects numbers from inside your servers every few seconds, Alertmanager turns them into alerts and Grafana draws them, so you can see why a server is slow or which disk is filling. If you run one or two websites, start with Uptime Kuma. If you run several servers and need to know what is happening inside them, add Prometheus and Grafana. Most teams end up with both. Below: how to connect them, what each cost us in RAM and disk in our lab, and what hosted alternatives charge.
Key facts, checked on 9 October 2026:
- The current versions are Uptime Kuma 2.5.6 (released 9 October 2026; our lab ran 2.5.5 from 16 September), Prometheus 3.15.0 with 3.13.4 as the long-term-support line, Alertmanager 0.34.1, node_exporter 1.12.1 and Grafana 13.2.3, all from the projects' GitHub release pages.
- Uptime Kuma has 92.3k stars on GitHub and lists more than 90 notification services. Version 2.5.5 keeps 365 days of check history by default; we read the setting in our own install.
- 67% of the 1,255 people who answered Grafana Labs' 2025 Observability Survey use Prometheus in production, and companies use eight observability tools on average.
- Prometheus stores "an average of only 1-2 bytes per sample" and keeps 15 days of data unless you change it (Prometheus storage docs).
- In our lab, Uptime Kuma watching 50 targets used 168 MB of RAM. Prometheus, Alertmanager, node_exporter and Grafana scraping 3 servers used 641 MB, and 355 MB after one Grafana setting that we explain below.
Pick this if: the short decision table
| Your situation | Pick | Why |
|---|---|---|
| One to ten websites, and you want to know fast when one goes down | Uptime Kuma | One container, a web form per check, alerts to Telegram, email and 90+ other services |
| Customers ask "is it down or is it me?" | Uptime Kuma | Public status pages are built in; Prometheus has none |
| A server is slow and you don't know why | Prometheus + node_exporter + Grafana | CPU, memory, disk and network every 15 seconds, with weeks of history to compare |
| You want a warning hours before a disk is full | Prometheus + Alertmanager | Alert rules can do maths on trends, such as "free space reaches zero in 4 hours" |
| Five or more servers, or more than one person on call | Both | Kuma says what users see, Prometheus says why; Alertmanager groups and routes alerts |
| You don't want to run another server at all | A hosted free tier | UptimeRobot, Better Stack or Grafana Cloud, within the limits in the cost section below |
One rule applies to every row: the monitor must not live on the server it watches. Our step-by-step guide to self-hosted monitoring on a VPS explains why and walks through the full installation with HTTPS and Telegram alerts. This article is the comparison; that one is the install manual.
What each tool actually does
Uptime Kuma: checks from the outside
Uptime Kuma is a free, open-source uptime monitor you host yourself. It does black-box monitoring, which means it tests a service the way a visitor would, without knowing anything about its insides. It opens your web page and checks the status code or a keyword on it, connects to a TCP port, pings a host, resolves a DNS record or waits for a "push" from a cron job. Each check gets an interval (60 seconds by default), retries and notifications, all set in a web interface.
What it cannot tell you is why. A red monitor says the shop timed out. It doesn't say the database ran out of memory a minute earlier.
Prometheus, Alertmanager and Grafana: numbers from the inside
Prometheus is a time-series database: it stores numbers tracked over time, such as "free bytes on / of server 2". Every 15 seconds Prometheus "scrapes" (downloads) a page of these numbers from small programs called exporters. The standard one for Linux is node_exporter, which reports CPU, memory, disk, network and about a thousand other values. Prometheus evaluates alert rules on those numbers and hands firing alerts to Alertmanager, which groups them, silences duplicates and sends them on. Grafana is the dashboard: it asks Prometheus questions in PromQL, Prometheus's query language, and draws the answers as graphs. This is white-box monitoring: you look inside the machine.
The price is effort. You write YAML files, learn some PromQL and install an exporter on every server. Outside checks need the separate blackbox_exporter, configured in a file, and there is still no status page.
Same failure, two views
We tested this in our lab. At 15:24:21 we stopped node_exporter on one of the three watched servers. Prometheus noticed at its next scrape and marked our InstanceDown alert as pending at 15:24:39. After the rule's two-minute wait it fired at 15:26:39, and Alertmanager received it the same second. Uptime Kuma had a TCP check on the same port. It logged "Connection failed" at 15:24:53 and again at 15:25:53, but kept the monitor in the "pending" state, because we had set two retries. We started the exporter again before the third check, so Kuma never sent a "down" alert. Both tools wait before they shout, and how long you let them wait decides how many false alarms wake you at night.
What we measured in our lab
We ran both setups on a test server in our Amsterdam network: Debian 13 containers with 2 vCPU and 3 GB of RAM each, Docker 29.9.0 from Docker's own repository, and everything started by a normal user called mon that is in the docker group. The targets were two small Debian 13 containers running nginx and the Debian package of node_exporter (1.9.0).
- Uptime Kuma 2.5.5 (image
louislam/uptime-kuma:2) with a SQLite database and 50 monitors: 40 HTTP keyword checks, 5 TCP checks and 5 pings, all every 60 seconds. - Prometheus 3.13.4, Alertmanager 0.34.1, node_exporter 1.12.1 and Grafana 13.2.3, scraping 3 servers plus Prometheus itself and Uptime Kuma's metrics, every 15 seconds.
| Measured in our lab | Uptime Kuma | Prometheus stack |
|---|---|---|
| RAM at the start (Kuma with no monitors, the stack in its first minute) | 148 MB | 582 MB (Prometheus 52, Grafana 505, Alertmanager 14, node_exporter 11) |
| RAM with 50 monitors / 3 scraped servers, after about 35 minutes | 168 MB | 641 MB (Prometheus 53, Grafana 554, Alertmanager 18, node_exporter 16) |
| Same, with Grafana's preinstalled plugins switched off | - | 355 MB (Prometheus 47, Grafana 278, Alertmanager 15, node_exporter 15) |
| Image size as Docker lists it | 2.49 GB | 2.46 GB (Grafana alone 1.94 GB) |
| Data after about 35 minutes | 4.6 MB (1,809 check results) | 3.5 MB of metrics plus 497 MB of Grafana data, almost all of it plugins |
| Disk used by Docker's folders in total | 4.2 GB | 4.1 GB (with the lean Grafana) |
First docker compose up -d | 25 seconds, image download included | 16 seconds (the Prometheus image was already pulled for promtool) |
RAM figures come from docker stats. Three things surprised us.
- Uptime Kuma 2 is a heavy image. It ships Chromium (for browser-based checks) and an embedded MariaDB server, so Docker lists the image at 2.49 GB even if you use neither. In memory it stays light: adding 50 monitors moved it from 148 MB to 168 MB.
- Grafana 13 turned out to be the biggest part of the stack. On first start it downloaded 17 plugins (476 MB) and ran most of them as separate processes of 20 to 35 MB each. Setting
GF_PLUGINS_PREINSTALL_DISABLED=true, which the Grafana configuration docs describe as disabling "all preinstalled plugins", cut Grafana from 554 MB to 278 MB and its plugin folder from 476 MB to nothing. The built-in Prometheus data source still worked: Grafana's health check answered "Successfully queried the Prometheus API." You lose the extra apps such as the Drilldown views until you install them yourself. - Prometheus itself is small at this scale. Each Debian server exposed 1,173 series through node_exporter. With five targets, Prometheus took in about 290 samples per second, which by the 1 to 2 bytes per sample rule is 25 to 50 MB of disk per day, or 0.4 to 0.75 GB for the default 15 days.
A minimal Prometheus setup, checked with promtool
You don't need much configuration to start. Install Docker first (our Docker on a VPS guide covers it), then create a folder with four files. This is the compose.yaml we ran; it publishes Prometheus, Alertmanager and Grafana only on 127.0.0.1, so they are not open to the internet:
# as the mon user, in ~/metrics/compose.yaml
services:
prometheus:
image: prom/prometheus:v3.13.4
restart: unless-stopped
command:
- --config.file=/etc/prometheus/prometheus.yml
- --storage.tsdb.retention.time=15d
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml:ro
- ./rules.yml:/etc/prometheus/rules.yml:ro
- prom-data:/prometheus
ports:
- "127.0.0.1:9090:9090"
alertmanager:
image: prom/alertmanager:v0.34.1
restart: unless-stopped
volumes:
- ./alertmanager.yml:/etc/alertmanager/alertmanager.yml:ro
ports:
- "127.0.0.1:9093:9093"
node-exporter:
image: prom/node-exporter:v1.12.1
restart: unless-stopped
command: --path.rootfs=/host
pid: host
volumes:
- /:/host:ro,rslave
grafana:
image: grafana/grafana:13.2.3
restart: unless-stopped
environment:
- GF_PLUGINS_PREINSTALL_DISABLED=true
volumes:
- grafana-data:/var/lib/grafana
ports:
- "127.0.0.1:3000:3000"
volumes:
prom-data:
grafana-data:
The scrape configuration. Replace the two private addresses with your own servers, each running node_exporter on port 9100 and reachable only from the monitor, for example over WireGuard:
# as the mon user, in ~/metrics/prometheus.yml
global:
scrape_interval: 15s
evaluation_interval: 15s
alerting:
alertmanagers:
- static_configs:
- targets: ["alertmanager:9093"]
rule_files:
- /etc/prometheus/rules.yml
scrape_configs:
- job_name: prometheus
static_configs:
- targets: ["localhost:9090"]
- job_name: node
static_configs:
- targets:
- node-exporter:9100
- 10.141.188.196:9100
- 10.141.188.228:9100
Two alert rules: one for a server that stops answering, one that looks at the last hour of disk use and fires if free space will reach zero within four hours:
# as the mon user, in ~/metrics/rules.yml
groups:
- name: basics
rules:
- alert: InstanceDown
expr: up == 0
for: 2m
labels:
severity: page
annotations:
summary: "{{ $labels.instance }} has not answered for 2 minutes"
- alert: DiskFullIn4Hours
expr: predict_linear(node_filesystem_avail_bytes{fstype!~"tmpfs|overlay"}[1h], 4 * 3600) < 0
for: 15m
labels:
severity: page
annotations:
summary: "{{ $labels.instance }} {{ $labels.mountpoint }} will be full within 4 hours"
And the smallest valid Alertmanager file. It accepts alerts and sends them nowhere yet; the full guide adds Telegram:
# as the mon user, in ~/metrics/alertmanager.yml
route:
receiver: default
group_wait: 30s
repeat_interval: 4h
receivers:
- name: default
Before you start anything, let Prometheus's own tool check the files. promtool is inside the Prometheus image, so nothing extra is installed:
# as the mon user, in ~/metrics
docker run --rm -v ./:/etc/prometheus:ro --entrypoint promtool prom/prometheus:v3.13.4 check config /etc/prometheus/prometheus.yml
docker run --rm -v ./alertmanager.yml:/am.yml:ro --entrypoint amtool prom/alertmanager:v0.34.1 check-config /am.yml
What we saw (the first command also checks the rule file it finds in the config):
Checking /etc/prometheus/prometheus.yml
SUCCESS: 1 rule files found
SUCCESS: /etc/prometheus/prometheus.yml is valid prometheus config file syntax
Checking /etc/prometheus/rules.yml
SUCCESS: 2 rules found
Checking '/am.yml' SUCCESS
A typo, such as a missing space after a dash, makes promtool print the line number instead of SUCCESS. Now start the stack and list the targets:
# as the mon user, in ~/metrics
docker compose up -d
curl -s localhost:9090/api/v1/targets | grep -o '"health":"[a-z]*"' | sort | uniq -c
With the two servers above plus the local node_exporter and Prometheus, you should see 4 "health":"up". When you change a rule later, check it with promtool check rules the same way and reload Prometheus without a restart:
# as the mon user, in ~/metrics
docker compose kill -s SIGHUP prometheus
Compose prints "Killing" and "Killed", which sounds worse than it is: it only delivered the signal. Prometheus kept running and logged "Completed loading of configuration file".
Using both: let Prometheus read Uptime Kuma
Uptime Kuma publishes its results at /metrics, so Grafana can show "the shop was down" on the same graph as "the database ran out of memory". In our 2.5.5 install the endpoint exposed four metric names: monitor_status, monitor_response_time, monitor_response_time_seconds and monitor_uptime_ratio.
The endpoint is protected. Create an API key in Uptime Kuma under Settings, then API Keys. The Uptime Kuma wiki warns that once the first key exists, basic authentication with your login password is permanently disabled for this endpoint, so it accepts only API keys from then on. Save the key in a file and test it, with an empty user name and the key as the password:
# as the mon user, on the Uptime Kuma server, after saving the key in ~/kuma/kuma_api_key
curl -s -o /dev/null -w "%{http_code}\n" http://127.0.0.1:3001/metrics
curl -s -u ":$(cat ~/kuma/kuma_api_key)" http://127.0.0.1:3001/metrics | grep -c '^monitor_'
We got 401 without the key and 400 lines with it, for our 50 monitors. Copy the key file next to prometheus.yml, give it mode 644 because the Prometheus container runs as the user nobody, mount it in compose.yaml with - ./kuma_api_key:/etc/prometheus/kuma_api_key:ro under the Prometheus volumes, and add one more job at the end of prometheus.yml:
# as the mon user, appended to ~/metrics/prometheus.yml
- job_name: uptime-kuma
basic_auth:
password_file: /etc/prometheus/kuma_api_key
static_configs:
- targets: ["10.141.188.6:3001"]
In our lab Kuma ran on another machine, so we also published its port on the private address 10.141.188.6. Use your monitor's private or WireGuard address, never a public one. After docker compose up -d, the query count(monitor_status == 1) in Prometheus returned 50: all fifty Kuma checks green, now stored for 15 days and ready for a Grafana panel.
Self-hosted or hosted: what the free tiers give you
If you'd rather not run a monitor yourself, three well-known services have free tiers. The figures below come from each vendor's own pricing page on 9 October 2026; they change often, so check before you sign up.
| Service | Free tier | First paid step | Good for |
|---|---|---|---|
| UptimeRobot | 50 monitors, checked every 5 minutes, 1 basic status page, 3 months of data; the page pitches it at hobby and non-profit projects | Solo from $9 a month billed yearly, checks every 60 seconds | Outside checks without a server |
| Better Stack | 10 monitors and heartbeats together, 1 status page, checks every 3 minutes (docs) | $29 a month billed yearly ($34 monthly) per responder, 10 monitors included, then $21 a month billed yearly ($25 monthly) for each 50 more; paid checks can run every 30 seconds | On-call rotas and incident handling |
| Grafana Cloud | 10,000 active metric series, 14 days of retention, 3 Grafana users, 100,000 synthetic API test runs a month | Pro: $19 a month platform fee with 10,000 series, then from $6.50 per 1,000 series; 13 months of metric retention | Hosted Prometheus and Grafana |
Our lab numbers next to those limits:
- One Debian server with default node_exporter produced 1,173 series. Grafana Cloud's 10,000 free series therefore cover about eight servers before you trim collectors or pay.
- Fifty HTTP checks every 60 seconds from one location are about 2.16 million runs a month (50 x 1,440 x 30). Grafana Cloud's free 100,000 synthetic runs cover roughly two such checks; the rest is billed from $5 per 10,000 runs before volume discounts.
- UptimeRobot's free plan holds all 50 checks, but each one looks only every 5 minutes, so an outage can run for up to 5 minutes before the first failed check. Uptime Kuma did 60-second checks for those 50 targets in under 200 MB of RAM.
- A hosted checker sees only public addresses. A self-hosted Kuma or Prometheus can test a database port or an exporter that is open only to the monitor.
A sensible mix for many small companies: Uptime Kuma and Prometheus on your own monitoring VPS, plus one free hosted check that watches the monitor itself.
Which server size you need
Size the monitor for what it runs, and keep it in a different city from the servers it watches. RS Computers runs KVM servers in Amsterdam (Netherlands), Dublin (Ireland) and Prishtina (Kosovo), all on NVMe with unmetered traffic and their own IPv4 and IPv6 addresses, so the watched servers and the monitor can sit in different countries. Availability by city is on the plans page.
| What you run | Plan | Why, based on our lab |
|---|---|---|
| Uptime Kuma alone, from a handful of checks to a hundred or so | VPS Nano (1 vCPU, 1 GB RAM, 20 GB NVMe) | Kuma used under 200 MB of RAM with 50 checks, and Docker's folders took 4.2 GB of the 20 GB disk |
| Prometheus, Alertmanager and lean Grafana for up to about ten servers | VPS Micro (2 vCPU, 2 GB RAM, 40 GB NVMe) | The lean stack used about 355 MB; leaves room for Docker, the system and queries |
| Both tools on one server, or Grafana with all plugins | VPS Mini (4 vCPU, 4 GB RAM, 80 GB NVMe) | Kuma plus the default stack used about 810 MB of RAM before the operating system, and about 8 to 9 GB of disk for Docker |
| Dozens of servers, months of retention, or logs as well | VDS Small (4 vCPU, 8 GB RAM, 240 GB NVMe, 10 Gb/s) | Disk and RAM grow with the number of series and the retention you keep |
vCPUs on all plans are shared, which is fine for monitoring: in our lab none of these containers used more than a few percent of a core. If the monitor outgrows its plan, upgrade it from the client area; it stays the same server after a short reboot. Then put HTTPS in front of the web interfaces with our Caddy, Nginx or Traefik guide instead of opening ports 3000 and 3001.
Frequently asked questions
Is Uptime Kuma a replacement for Prometheus?
No. Uptime Kuma checks whether a site, port or host answers from the outside and alerts you when it doesn't. Prometheus collects metrics such as CPU, memory and disk from inside your servers and keeps their history. Kuma tells you that something is down; Prometheus helps you find out why.
Can Prometheus do uptime checks like Uptime Kuma?
Yes, with the separate blackbox_exporter, which probes HTTP, TCP, ICMP and DNS targets that you list in a configuration file. It has no web form and no status page, so for simple website checks Uptime Kuma is quicker to set up and easier to hand to non-technical colleagues.
How much RAM does Uptime Kuma need?
In our lab, Uptime Kuma 2.5.5 used 148 MB of RAM with no monitors and 168 MB with 50 monitors checked every 60 seconds, measured with docker stats. A 1 GB VPS is enough for it on its own. Its Docker image is large, 2.49 GB, because it includes Chromium and MariaDB.
Do I need Grafana if I have Prometheus?
Prometheus has a basic built-in page for running queries and simple graphs, which is enough for testing. For dashboards you keep open or share with a team, Grafana is the usual choice.
Can Grafana show Uptime Kuma data?
Yes, through Prometheus. Uptime Kuma exposes its check results at /metrics, protected by an API key. Prometheus scrapes that endpoint like any exporter, and Grafana then charts monitor_status and response times next to your server metrics.
Is the Grafana Cloud free tier enough for a small company?
For a few servers, often yes. The free tier includes 10,000 active metric series and 14 days of retention (checked 9 October 2026). In our lab one Debian server with default node_exporter produced 1,173 series, so about eight servers fit before you trim collectors or move to the paid Pro tier.
Start with the question you can't answer today
If you don't know when your site goes down, set up Uptime Kuma this week; it takes an evening. If you know it went down but not why, add Prometheus, node_exporter and Grafana, using the files above and the full installation guide. Pick a monitoring server on the VPS and VDS plans page, in a different city from the servers it watches. If you'd like us to set it up for you, the work is quoted per job: message us on Telegram.