Pingdom and UptimeRobot check your websites from the outside and tell you when one stops answering. Atlassian Statuspage is the page where you tell your customers about it. Uptime Kuma and Gatus do both jobs on a server of your own, for a fixed server price instead of a price per check. We pointed both at the same test services on the same server, and then broke those services on purpose. What the three services charge, and what you give up by leaving them, is at the end.
The short answer
Pick Uptime Kuma if you want to click your monitors together in a web interface, in Swedish if you like, and want a status page you can talk to your customers on: it has incident posts with a history, maintenance that shows on the page, and it alerted within 9 to 50 seconds in our test with its default settings. Accept that it is one account with no roles, that it used about ten times the memory of Gatus, and that it has no supported API for adding monitors from a script.
Pick Gatus if you would rather keep your monitors in one text file under version control, want strict checks on response time, body and certificate, and want something tiny: it used 12 to 17 MB of memory with 50 monitors. Accept that its whole dashboard is the status page, that announcements are lines in the same file, that it has no Swedish, and that with its defaults it waits for three failed checks, so it alerted after two to almost three minutes.
Whichever you pick, run it somewhere other than what it watches, and have something outside check the checker. A monitor in the same data centre as your sites goes quiet exactly when you need it most.
What we tested
We installed both on the same fresh Melonslab VC-P Alloy (2 vCPU, 8 GB) with Debian 13. Uptime Kuma 2.5.6 came from our guide Uptime Kuma with rootless Podman, step by step, and every step worked as written. Gatus 5.37.0 has no guide of ours, so we ran it the same way, rootless under a user of its own, as a Quadlet unit behind the same Caddy, with its configuration in a file and its data in SQLite. The section How we ran Gatus has the unit file and the configuration.
On the same server we ran test services that we could break when we liked:
- a small website that answered "All systems go", which we stopped, and changed to say something else;
- a page that always answered with error 500, and one that took 15 seconds to answer;
- a TLS service with a certificate that expired two days later, signed by a test authority of our own that we told both apps to trust;
- a TCP port, which we stopped together with the website;
- a DNS lookup of our test domain through Quad9, and a ping to Quad9;
- a heartbeat, a job that reported in every minute, which we stopped.
Both apps checked all of them every 60 seconds, which is their default, with a report expected from the heartbeat every two minutes, and sent alerts by email, to a webhook and to ntfy. The email went to Mailpit, a test mail catcher on the server, so no real mail was sent, and the webhook went to a small receiver that wrote down the time of every call. We then stopped the website and the TCP port four times for five minutes, at random points in the check cycle, and timed every alert from the moment we stopped them. We also tried a maintenance window, built a public status page on a domain of its own with incidents and badges, added 41 more monitors to reach 50 in each and left them running for three hours, rebooted the server, and backed up and restored Gatus.
Pingdom, UptimeRobot and Statuspage were not tested. We did not sign up for any of them. What this page says about them comes from their own pricing pages and documentation, linked where we use them and read on 14 October 2026.
The numbers
| Uptime Kuma 2.5.6 | Gatus 5.37.0 | |
|---|---|---|
| Containers | 1 | 1 |
| Image on disk | 1.76 GB | 51 MB |
From useradd to the first page | 70 seconds | 15 seconds |
| Memory at rest after a reboot, 9 monitors | 118 MB | 12 MB |
| Memory with 50 monitors | 120 to 141 MB | 12 to 17 MB |
| CPU with 50 monitors, every 60 seconds | 2.5% of one core | 0.5% of one core |
| Data growth with 50 monitors | 0.5 MB an hour, about 12 MB a day | 2.3 MB in the first hour, then 0.2 MB an hour |
| Alert after a site stopped, default settings | 9 to 50 seconds | 2 minutes 2 seconds to 2 minutes 44 seconds |
| All-clear after it was back | 9 to 50 seconds | 62 to 104 seconds |
| False alarms in our test | none | none |
| Monitors set up in | the web interface | a YAML file |
| Public status page | separate pages you choose monitors for, with incidents | the dashboard itself, with announcements |
| Users | one account | no accounts; optionally one password or single sign-on for the whole site |
| Swedish interface | yes | no |
| Licence | MIT | Apache 2.0 |
Memory is what podman stats showed for each container, at rest five minutes after a reboot and as the range over three hours with 50 monitors. CPU is the average share of one core over those three hours, from the containers' own counters. The installation times are how long the commands took to run, the image download included, until the first page answered. Both images were already the latest release on 14 October 2026.
A monitor can't report its own outage
This is the most important point on the page, and it is true of both apps.
Our test ran both apps on the same server as the services they watched, because that was the only way to break those services on purpose. In real use, that is the setup to avoid. If the server stops, or its data centre loses power or its network, the monitor stops with it. It sends no alert, because it is not running, and its status page goes down too, at the moment your customers look for it. Even if it runs on another server in the same data centre, a network fault there takes both out at once.
The fix is cheap, and you can do one or both:
- Run the monitor on a second, separate server, ideally with another provider or at least in another data centre, and point it at your sites over the internet. A small server is enough: Gatus used at most 17 MB and Uptime Kuma 141 MB with 50 monitors.
- Have something outside watch the monitor. A free external check, such as UptimeRobot's free plan or a second monitor on another server, can fetch your status page every few minutes and tell you when it stops answering. Gatus has a
/healthaddress for this, and for Uptime Kuma you check the status page itself. Two self-hosted monitors on two servers can also watch each other. We tried that with our two: when we stopped Uptime Kuma, its status page answered with error 502 and Gatus alerted 2 minutes 17 seconds later, and when we stopped Gatus, Uptime Kuma alerted 6 seconds later.
Neither turns your monitor into Pingdom. One extra server is one more place to check from, not dozens, as the section on what you give up explains. But it is the difference between finding out from a monitor and finding out from a customer.
Setup
Uptime Kuma is one container and one Caddy block. On its first visit it asks which database to use, where SQLite is the simple choice, and for an account, and then you add monitors in a form. Our guide also gives the container an address of its own so that it can reach apps behind Caddy on the same server. The image is big, 1.76 GB, since it carries Node.js, Chromium for its browser checks and an embedded MariaDB, and that download was most of its 70 seconds.
Gatus is one container, one Caddy block and one YAML file. It has no setup page and no accounts: it starts monitoring what the file lists, and the page shows the results. The image is 51 MB, a single program. We chose SQLite over PostgreSQL for its storage: it is one file in a volume, the backup is one command, and Gatus keeps only the last 100 results per monitor, so the file stays small. PostgreSQL would add a second container and more memory for no gain at this size. Without either, Gatus keeps everything in memory and forgets it at every restart.
We used the same containers.conf change from our Uptime Kuma guide for Gatus, so that it too could reach services behind Caddy on the same server.
Checks and alerts
Both check websites, keywords in the page, TCP ports, DNS answers, ping, certificates and heartbeats. Uptime Kuma has more kinds, about 40, among them databases, game servers, Docker containers and a real browser. Gatus has fewer, but every check is a list of conditions you combine: the status code, the response time, the body as text or JSON, the IP address and the days left on the certificate.
How fast they alerted. The difference came from the defaults, not from speed. Uptime Kuma alerts at the first failed check: when we stopped the website, the alert came 9, 14, 16 and 50 seconds later in our four rounds, depending on where in its 60-second cycle we stopped it. Gatus waits for three failed checks in a row, and for two good ones before the all-clear: its alerts came after 2 minutes 2 seconds to 2 minutes 44 seconds, and the all-clear after 62 to 104 seconds. The TCP port behaved the same in both. Every outage gave exactly one alert and one all-clear on each channel, and the email, webhook and ntfy messages arrived within a second of each other. Both are settings: Uptime Kuma has Retries, and Gatus has failure-threshold and success-threshold on each alert.
False alarms. Neither sent a single alert we had not caused, in about five hours with 9 to 50 monitors. The only alert outside our tests was Uptime Kuma's, during our reboot: it saw the slow page go down as the server shut down, which was true. Our services were on the same server, though, so this says nothing about a flaky network between a monitor and a site far away, which is where Gatus' three failures in a row earn their delay.
What counted as down differed:
- The slow page, 15 seconds, was up in Uptime Kuma, whose timeout is 48 seconds at a 60-second interval, and down in Gatus after its 10-second timeout. Both timeouts can be changed, and Gatus can also fail a check on
[RESPONSE_TIME] < 2000. - The certificate with two days left: Uptime Kuma kept the monitor up and sent a separate warning, "server certificate tls.example.com will expire in 1 days", once we had ticked Certificate Expiry Notification, which is off for new monitors. It warns 21, 14 and 7 days before by default. In Gatus, the condition
[CERTIFICATE_EXPIRATION] > 168hturned the monitor red and alerted like any other failure. - When we changed the keyword page, Uptime Kuma alerted 54 seconds later and Gatus after 2 minutes 47 seconds.
- The heartbeat: when our job stopped reporting, Uptime Kuma alerted two minutes after its last report, as set. Gatus noted the first missing report 3 minutes 42 seconds after the last one, but had not alerted when we started the job again after six and a half minutes: it checks a heartbeat once per interval, here two minutes, and still wanted three failures, which would have taken almost eight minutes. With
failure-threshold: 1on that alert, the next try alerted 2 minutes 10 seconds after the last report. Set that for every heartbeat in Gatus.
Alert channels. Uptime Kuma has about 100 kinds of notification, set up in forms: email, webhooks, ntfy, Matrix, Slack, Teams, Telegram, Pushover, SMS services and many more. Gatus has about 40, set in the file, among them email, a custom webhook, ntfy, Matrix, Slack, Teams, Telegram, PagerDuty and Twilio. Two things we noticed with Gatus' email: it refused to send its password over an unencrypted connection, which is right, so use port 587 with STARTTLS, as our test did; and when sending failed, it tried again at the next check instead of giving up.
Maintenance windows
Both kept quiet when we stopped the website during a planned window.
- Uptime Kuma has Maintenance in its menu: a one-off window, a recurring one, a cron expression or a manual one you end yourself, for the monitors and status pages you choose. During ours, the monitor and its badge showed Maintenance in blue instead of down, and the status page showed it too.
- Gatus has a
maintenance-windowslist per monitor, or one window for all, with a start time, a length, a time zone and the weekdays, in the file. It sent no alerts, but its page kept showing the failed checks in red, with no sign of maintenance. Tell your visitors with an announcement.
Neither can start a window from your calendar or an API call without a script.
Status page
Uptime Kuma keeps the monitoring and the public page apart. You make one or more status pages, choose which monitors each shows and under which headings, and give each a domain of its own: we entered status.example.com under Domain Names in the page's settings, added a Caddy block for it pointing at Uptime Kuma, and the status page opened at the domain's front page, while the admin interface stayed at its own address. You post incidents on the page with a title, Markdown text and a colour. In 2.5.6 an incident can be resolved, and resolved ones move to Past Incidents below, so customers see a history. Each monitor shows its last checks and its uptime in per cent. Badges for status, uptime, response time and certificate expiry come from /api/badge/, for monitors that are on a public status page.
Gatus has no separate page: the dashboard is the status page, and it shows every monitor in the file, with the last checks and response times. You can hide a monitor's address with hide-hostname and hide-url, but you cannot show one set of monitors to customers and another to yourself in the same Gatus, so run two if you need that. Incidents are announcements in the file, each with a time, a type (outage, warning, information, operational) and a Markdown message. Archived ones moved to Past Announcements at the bottom, under a list of days. A custom domain is just the Caddy block. Badges for health, uptime and response time come from /api/v1/endpoints/…/badge.svg.
History differs too. Uptime Kuma keeps every check for 365 days by default and draws charts from them. Gatus keeps the last 100 results and 50 events per monitor and the uptime for 30 days, which is enough for a status page and not for a report a year later.
Neither sends emails to subscribers when you post an incident, as Statuspage does. Uptime Kuma's status pages have an RSS feed; Gatus has none.
Users and permissions
Uptime Kuma has one account. Everyone who manages monitors shares it, with two-step login if you turn it on, and there are no roles, no read-only users and no log of who changed what. Its API keys only open its Prometheus metrics.
Gatus has no accounts at all. The file is the configuration, so who may change monitors is who may change the file, or the Git repository it comes from, which also gives you a history of every change. The page itself is public, or you protect all of it with one username and password, or with single sign-on through OpenID Connect, which also hides it from your customers.
If several people need their own logins with different rights, neither does it, and that is one of the clearest reasons to stay with a service.
Config as code
Gatus is built for it. All 50 of our monitors, their alerts, announcements and maintenance windows were one YAML file, and Gatus noticed a changed file by itself and reloaded it, within about a minute in our test. A mistake in the file is the danger: when we broke it on purpose, Gatus stopped, failed every restart, and the status page and all alerts were gone until we fixed the file. Check podman logs gatus after every change. Gatus' option skip-invalid-config-update: true keeps the old configuration running instead, which its README advises against, since the next restart then fails anyway. Values such as passwords can come from environment variables, which we filled from podman secret.
Uptime Kuma is set up by clicking. It has no supported API for monitors: we added our 50 through the socket connection its own web interface uses, with a small script, which works but can change with any release. Its JSON backup and import were removed in version 2. For a handful of monitors that someone clicks together once, that is fine; for hundreds, or a team that reviews changes, it is not.
Swedish
Uptime Kuma comes in Swedish: it followed our browser's language and showed "Användarnamn", "Lösenord" and "Logga in", and you can change it under Settings > Appearance > Language. Only about 50 of its 1,600 texts were left in English, mostly words like "Ping", "URL" and "Token". The public status page follows each visitor's browser in the same way: ours said "Alla system i drift", while the incidents, headings and monitor names stayed as we wrote them.
Gatus is in English only. The texts you write yourself, the title, the monitor names and the announcements, can be in Swedish, but labels such as "Healthy", "Unhealthy" and "Past Announcements" stay in English.
Resources
We added 41 monitors to each, 33 web pages, 3 keyword checks, 2 TCP ports, 2 DNS lookups and a ping, for 50 in all, and left both running for three hours with a check every 60 seconds.
Memory. Uptime Kuma used 120 to 141 MB, 134 MB on average, a little more than the 118 MB it used with nine monitors. Gatus used 12 to 17 MB, 16 MB on average.
CPU. Uptime Kuma used 2.5% of one core on average, and Gatus 0.5%. Neither would be noticed on a server with two cores.
Disk. Both write to SQLite. Uptime Kuma's data grew evenly, by about 0.5 MB an hour, or 12 MB a day. It keeps every check for 365 days, so at that rate it would reach about 4.5 GB after a year with 50 monitors; Settings > Monitor History shortens that. Gatus grew by 2.3 MB in the first hour, while it filled up to its 100 results per monitor, and then by 0.2 MB an hour, mostly the uptime figures it keeps for 30 days. After the test, each data volume held about 6 MB, most of it SQLite's write-ahead log.
Both fit with room to spare on the smallest server you would run a monitor on. For a second monitoring server, Gatus also fits beside other things on one that is already busy.
Updates and backups
Uptime Kuma's guide follows the 2-rootless tag, which gets every release of version 2 through Podman's daily auto-update. Gatus follows the stable tag in the same way, which was the same image as 5.37.0 when we tested. Uptime Kuma released six versions between 22 August and 9 October 2026; Gatus releases every one to four months, most recently on 24 September 2026.
Uptime Kuma's backup is one volume, with the container stopped for a moment: monitors, history, the account and the notification settings with their passwords. Ours was 2.2 MB after five hours with up to 51 monitors. Gatus' backup is the volume with the SQLite file and the YAML file; keep the passwords in the podman secrets somewhere safe too, since neither holds them. We exported the Gatus volume, 1.7 MB after an hour, removed it, imported it again, and the history was all there. Both came back by themselves after a reboot.
Licence and cost
We checked the projects' own pages on 14 October 2026.
- Uptime Kuma is open source under the MIT licence, made by Louis Lam and its community. There is no paid edition and no hosted service from the project.
- Gatus is open source under the Apache 2.0 licence, made by TwiN. Its README points to Gatus.io, a hosted version, which listed plans from Free, without a published page, through Standard at 10 US dollars a month for one status page with 30 monitors checked every two minutes, to Enterprise at 500 US dollars.
Run on your own servers, both cost nothing beyond the servers. Two small ones, one for your sites and one for the monitor, is the honest setup.
Pingdom, UptimeRobot and Statuspage today
What follows is from their own pages, read on 14 October 2026, not from our tests. Prices are what the pages showed us, without VAT.
Pingdom, from SolarWinds, prices its Synthetic Monitoring by the number of checks on its pricing page: from 16 euros a month, or 14.33 euros a month billed yearly, for 10 uptime checks, one advanced check and 50 SMS alerts, and 66 euros a month, or 60.50 billed yearly, for 50 uptime checks, 10 advanced checks and 200 SMS. The page lists unlimited users, email and SMS alerts, maintenance windows and public status pages. Pingdom's checks come from "probe servers, located around the world", and a failed check is only "marked as confirmed Down if the second test fails" from another probe, "as geographically different as possible", according to its documentation. Its public status page is one per organisation, can use your own domain, cannot be password protected, and shows the results of your checks; the page does not mention incident posts.
UptimeRobot's pricing page lists:
- Free: 50 monitors checked every 5 minutes, basic status pages, no SMS or voice credits and no logins for colleagues, "Good for hobby and non-profit projects". Its terms say that "UptimeRobot is available for any use, including commercial and business use", and that the free plan "includes 1 status page with a unique UptimeRobot URL only".
- Solo: 10 euros a month, 9 billed yearly, for 10 monitors, or 22 euros for 50, checked every 60 seconds, with 3 status pages on your own domain, maintenance windows and 10 to 20 SMS or voice credits.
- Team: 41 euros a month, 35 billed yearly, for 100 monitors every 30 seconds, 3 seats, 100 status pages, webhooks, password-protected status pages, subscribers to them and 30 SMS or voice credits.
Its monitors can check from chosen locations, listed as "Location-specific monitoring".
Atlassian Statuspage is a status page, not a monitor: Atlassian's integrations page says to "Integrate Statuspage with DataDog, New Relic, Librato or Pingdom to update your page as soon as an issue is detected", or to update it through the REST API or by email. Its pricing page lists public pages as Free, with 100 subscribers, 25 components and 2 team members; Hobby at 29 US dollars a month, with 250 subscribers, 5 team members, your own domain and email notifications only; Startup at 99 US dollars, with 1,000 subscribers, 10 team members and SMS and webhook notifications; and Business at 399 US dollars. Private pages, for staff only, start at 79 US dollars a month.
What you give up compared with Pingdom and Statuspage
Your own monitor costs a fixed server price, keeps your checks and alerts on servers in Sweden, and has no limit on monitors or how often they run. Be honest about what you leave behind:
- Checks from many places. Pingdom checks from probes around the world and asks a second probe before it calls a site down. Your monitor checks from one place, so it cannot tell a site that is down from a network problem between the two, or say that your site is slow from Asia. Uptime Kuma 2.5 has a Globalping monitor type that borrows volunteer probes worldwide, with a limit of 250 tests an hour without an account; we did not test it.
- SMS and phone calls. Pingdom and UptimeRobot include SMS credits, and UptimeRobot voice calls. Neither app sends SMS itself: Uptime Kuma and Gatus send through paid services such as Twilio, with an account of your own, or you use ntfy, Pushover or Telegram on the phone instead.
- A status page that stays up. Statuspage and the other services run your status page on their infrastructure, away from yours. Yours is only as available as the server it runs on, which is why it belongs on a different server from your sites.
- Subscribers. Statuspage emails and texts your customers when you post an incident. Neither app has subscribers.
- Team accounts. Pingdom lists unlimited users and Statuspage up to 25 team members on Business. Uptime Kuma has one account and Gatus none.
- Running it. Updates, backups and the server are yours, and if the monitor stops, nobody else notices unless you set up the outside check.
How we ran Gatus
We ran Gatus like our app guides: rootless in Podman under a user of its own, as a Quadlet unit behind Caddy from the Podman guide, with the configuration as a file and the passwords as podman secrets. Gatus fills ${SMTP_PASSWORD} and ${HEARTBEAT_TOKEN} in its file from environment variables, which is where the secrets go. It publishes on 127.0.0.1:8150.
As root, create the user:
useradd -m -s /bin/bash gatus
loginctl enable-linger gatus
machinectl shell gatus@
As gatus, create ~/.config/containers/containers.conf exactly as in step 2 of the Uptime Kuma guide, so that Gatus can reach apps behind Caddy on the same server. Then the secrets, with your email provider's password, and a token for the heartbeat:
printf %s 'the-smtp-password' | podman secret create smtp-password -
openssl rand -hex 24 | tr -d '\n' | podman secret create heartbeat-token -
podman secret inspect --showsecret --format '{{.SecretData}}' heartbeat-token
The last command shows the token, for the job that reports in. Create ~/gatus/config.yaml:
storage:
type: sqlite
path: /data/data.db
ui:
title: "Status | Example"
header: "Example"
dashboard-heading: "Status"
dashboard-subheading: "Our services right now"
alerting:
email:
from: "status@example.com"
username: "status@example.com"
password: "${SMTP_PASSWORD}"
host: "smtp.example.com"
port: 587
to: "anna@example.com"
default-alert:
send-on-resolved: true
endpoints:
- name: Website
group: Public
url: "https://www.example.com/"
conditions:
- "[STATUS] == 200"
- "[BODY] == pat(*Welcome*)"
- "[CERTIFICATE_EXPIRATION] > 336h"
alerts:
- type: email
- name: Mail
group: Public
url: "tcp://mail.example.com:993"
conditions:
- "[CONNECTED] == true"
alerts:
- type: email
external-endpoints:
- name: Nightly backup
group: Internal
token: "${HEARTBEAT_TOKEN}"
heartbeat:
interval: 25h
alerts:
- type: email
failure-threshold: 1
The website is down if it does not answer 200, if the page lacks the word "Welcome", or if its certificate expires within 14 days. failure-threshold: 1 makes a missed heartbeat alert at once, see above. Add announcements: and maintenance-windows: as described in their sections, and other alert types from Gatus' README.
Create ~/.config/containers/systemd/gatus.container:
[Unit]
Description=Gatus
[Container]
ContainerName=gatus
Image=ghcr.io/twin/gatus:stable
# The directory, not the file, so that Gatus sees changes
Volume=%h/gatus:/config:ro
Volume=gatus-data:/data
Secret=smtp-password,type=env,target=SMTP_PASSWORD
Secret=heartbeat-token,type=env,target=HEARTBEAT_TOKEN
# Only Caddy, on this server, can reach Gatus
PublishPort=127.0.0.1:8150:8080
# ping needs raw sockets
AddCapability=NET_RAW
AutoUpdate=registry
[Service]
Restart=always
[Install]
WantedBy=default.target
Start it:
systemctl --user daemon-reload
systemctl --user start gatus
systemctl --user enable --now podman-auto-update.timer
podman logs gatus
The log lists Validated 2 endpoints and then each check. Go back to root with exit, switch to machinectl shell caddy@, add this block to ~/Caddyfile and restart Caddy with systemctl --user restart caddy:
status.example.com {
reverse_proxy 127.0.0.1:8150
}
https://status.example.com is now your status page. The nightly job reports in with:
curl -fsS -X POST -H "Authorization: Bearer THE_TOKEN" \
"https://status.example.com/api/v1/endpoints/internal_nightly-backup/external?success=true"
To back up, as gatus:
umask 077
mkdir -p ~/backup
systemctl --user stop gatus
podman volume export gatus-data > ~/backup/gatus-data.tar
cp ~/gatus/config.yaml ~/backup/
systemctl --user start gatus
Keep the SMTP password and the token somewhere safe too: podman secrets are not in the backup. To restore, stop Gatus, podman volume rm gatus-data, podman volume create gatus-data, podman volume import gatus-data ~/backup/gatus-data.tar, and start it again.
Which one to pick
A small company that wants alerts and a status page for its customers: Uptime Kuma. It is the closest to UptimeRobot plus a simple Statuspage: monitors in a form, alerts at the first failure, incidents with a history, maintenance that shows on the page, and Swedish. Its weak points are one shared account, a big image and about 140 MB of memory with 50 monitors, no supported API, and no subscribers. Follow the Uptime Kuma guide, on a VC-P Alloy, and preferably not the one your sites run on.
A team that keeps its servers in Git: Gatus. One YAML file holds every check, alert and announcement, with conditions on status, body, response time and certificate, in under 20 MB of memory. Its weak points are a dashboard that is also the public page, announcements you edit in a file, no accounts, no Swedish, and defaults that wait for three failed checks before alerting, also on a missed heartbeat. Run it as in How we ran Gatus; it fits on any server, also beside other apps.
Stay with Pingdom or UptimeRobot if you need checks from many countries, SMS or calls included, or several colleagues with their own logins. Stay with Statuspage if you have many customers who subscribe to your incidents by email or SMS.
Whichever you run, put it on a second server, and point one free outside check at it.