Uptime Kuma on a VPS: Docker, Caddy HTTPS, Alerts and Cost (2026)

Deploy Uptime Kuma 2 on a small VPS in a different city from your servers: localhost-only Docker, Caddy HTTPS, the right monitors and alerts, Globalping checks and version 2 backups.

Title card reading “Uptime Kuma on a VPS” for the HourlyVPS guide to self-hosted uptime monitoring with Docker, Caddy HTTPS and alerts

To run Uptime Kuma on a VPS, start the official louislam/uptime-kuma:2 Docker container with its data in a volume and port 3001 bound to 127.0.0.1, create the admin account through an SSH tunnel, then put Caddy in front for HTTPS. Uptime Kuma is a free, MIT-licensed, self-hosted monitor that checks HTTP(S), TCP, ping, DNS and keyword targets and alerts you through Telegram, Discord, email or any of its 90-plus notification services; version 2.5.5, released September 16, 2026, was current on October 3, 2026.

Where the server runs matters as much as the install. A monitor on the same machine or in the same data center as your apps fails with them and sends nothing. This guide puts Uptime Kuma on the smallest plan in a different city from your apps, adds outside-in checks through its built-in Globalping monitor type, and backs it up the way version 2 requires: the data folder, because the old JSON export is gone.

Key takeaways

  • Run Uptime Kuma in a different city from the servers it watches: a monitor on the same server or in the same facility fails with them and sends nothing.
  • Bind port 3001 to 127.0.0.1 and create the admin account through an SSH tunnel, because until an admin exists, whoever reaches the setup screen first can claim the instance.
  • Uptime Kuma 2 removed the JSON export, so the data directory is the only supported backup: stop the container, archive the volume and copy it off the server.
  • Since version 2.1.0 the Globalping monitor type adds checks from probes in other countries, within a free budget of 250 tests per hour, or 500 with a free token.
  • The project publishes no RAM minimum; on a 1 GB plan, choose SQLite and skip embedded MariaDB and the Browser Engine monitor.

Uptime Kuma on a VPS: the short version

  1. Deploy an Ubuntu 24.04 LTS VPS with 1 GB of RAM in a different city from the servers you want to watch. Secure SSH and allow only ports 22, 80 and 443.
  2. Install Docker Engine.
  3. Start Uptime Kuma with the README’s Docker command, published on localhost only: -p 127.0.0.1:3001:3001.
  4. Open an SSH tunnel to port 3001, choose SQLite as the database and create the admin account.
  5. Point a subdomain at the server and add a three-line Caddy site block with reverse_proxy 127.0.0.1:3001.
  6. Turn on two-factor authentication, set Trust Proxy and the Primary Base URL.
  7. Add monitors and notifications, then a status page if other people need one.
  8. Back up the uptime-kuma volume every night and copy it off the server.

Plan the server: location first, then size

Why monitor from a different location?

Uptime Kuma runs every check from one place: the server it is installed on. If that server shares a failure with the things it watches, the alert never leaves. This table shows what each placement can and cannot see.

Where Uptime Kuma runsWhat it catchesWhat it misses
On the same server as your appsCrashed apps, expired certificates, a full disk that breaks one serviceAnything that takes the server or its network down: the monitor goes down too, silently
On another server in the same data centerA crashed or overloaded serverFacility-wide power, network or routing problems that hit both servers at once
On a server in another cityServer and data-center outages, routing problems between the two citiesProblems only users in other regions see, and failure of the monitor itself
Another city, plus Globalping checksReachability from probes in the countries you chooseFailure of the monitor itself
Two instances in two cities, watching each otherAll of the above, including a dead monitorBoth cities failing at the same time
Failure domains for a single-location monitor. Uptime Kuma itself has no multi-location mode; the Globalping monitor type is covered below.

HourlyVPS takes orders in Istanbul today; New York is coming soon, and the locations page shows the current status of each city. If your apps run with another provider or in another region, an Istanbul server is already a separate city and network. If they run in Istanbul, put the monitor somewhere else: a small server at another provider now, or our second city once it opens. Distance shows up in response-time graphs. Our guide on how to choose a VPS location puts the physical floor for a round trip from Istanbul at about 18 ms to Frankfurt and 79 ms to New York, so judge latency by its trend, not by the absolute number.

A monitor that is down sends no alerts, so something should watch it too. A low-cost fix is a second small Uptime Kuma in another city, with an HTTP(s) monitor on each instance pointing at the other one’s HTTPS address. A hosted free plan pointed at your Uptime Kuma URL does the same job (compared in the cost section).

How much RAM does Uptime Kuma need?

Uptime Kuma’s README and wiki publish no RAM or CPU minimum. They do document what makes it heavier. The Docker Tags page says the full 2 image bundles an embedded MariaDB server and Chromium for the “Browser Engine” monitor type, while 2-slim leaves both out and is about 300 to 400 MB smaller. On Docker Hub on October 3, 2026, the compressed amd64 download was 602 MB for 2 and 182 MB for 2-slim.

Your setupPlanReasoning
Personal or small-team monitoring: HTTP, keyword, TCP, ping, DNS and push monitors on SQLiteQuartz Q1 (1 vCPU, 1 GB, 25 GB NVMe)Ubuntu Server documents 1 GB as the minimum RAM for its cloud images. SQLite is a file inside the Uptime Kuma process, so no second server competes for memory.
Embedded MariaDB, Browser Engine monitors, or other containers on the same serverQuartz Q2 (1 vCPU, 2 GB, 50 GB NVMe)Embedded MariaDB runs a second database server inside the container, and the Browser Engine type drives a headless Chromium.
Hundreds of monitors at short intervals, or a long historyQuartz Q4 (2 vCPU, 4 GB, 80 GB NVMe)Every check writes a heartbeat; version 2.5.5 keeps 365 days of history by default, so more monitors and shorter intervals mean more database work.
Uptime Kuma publishes no hardware minimum. The plan choices are our reasoning from the documented image contents and Ubuntu’s 1 GB cloud-image minimum, not benchmark results.

After a day of real checks, read actual usage with sudo docker stats --no-stream uptime-kuma and move up a plan if memory stays near the limit or the container restarts on its own. On a 1 GB plan, a swap file gives a short memory spike somewhere to go before the out-of-memory killer acts; see how to add swap on Ubuntu 24.04.

Traffic is small but not zero. An HTTP(s) monitor with the default GET method downloads the whole response every time: a 60-second check of a page that transfers 100 KB runs 43,200 times in 30 days and pulls about 4.3 GB. For plain up/down checks of heavy pages, switch the monitor’s method to HEAD if the target answers it correctly. Istanbul plans include the monthly traffic allowance listed for each plan, prorated for a server that exists for part of a billing period.

Quartz Q1

KVM · 1 Gbps port · Istanbul · initial credit $5

vCPU
1 shared
RAM
1 GB
NVMe
25 GB
Traffic
Istanbul: 2 TB/month
  • Per hour$0.01/hour
  • Per day (24 h)$0.24/day
  • Monthly cap$5.00/month

Deploy Quartz Q1 Plan details for Quartz Q1

Install Uptime Kuma with Docker

Start from a hardened server: a sudo user, SSH keys, root and password logins off, and UFW allowing only SSH, HTTP and HTTPS. Our guides on connecting to a VPS over SSH and the VPS security checklist cover that in about 15 minutes. Then follow how to install Docker on a VPS, which uses Docker’s official apt repository. Run every command below as your sudo user.

Step 1: Start the container on localhost only

The README’s Docker command publishes port 3001 on every address of the server. Ports that Docker publishes bypass UFW, so a firewall rule would not hide it. The README offers a localhost-only variant; use it from the start:

sudo docker run -d --restart=always -p 127.0.0.1:3001:3001 -v uptime-kuma:/app/data --name uptime-kuma louislam/uptime-kuma:2
  • -v uptime-kuma:/app/data keeps everything in a named Docker volume: the SQLite database kuma.db, db-config.json with your database choice and, if you pick it, the embedded MariaDB files under /app/data/mariadb. The README warns that NFS is not supported; keep this on local disk.
  • :2 tracks the latest 2.x release. The old latest tag is deprecated and still points at version 1. Pin a release such as 2.5.5 if you want to choose when upgrades happen.
  • --restart=always starts Uptime Kuma again after a reboot or a crash.

Check that it is running. The image has a built-in health check that runs every 60 seconds and gives the app a 180-second start period, so the status shows (health: starting) first and then (healthy):

sudo docker ps --filter name=uptime-kuma
sudo docker logs --tail 20 uptime-kuma

Prefer Docker Compose? The project’s compose.yaml stores data in a ./data folder next to the file and publishes 3001:3001. Change that line to "127.0.0.1:3001:3001" before docker compose up -d. On a 1 GB server that will only use SQLite, the louislam/uptime-kuma:2-slim image runs the same app without embedded MariaDB and Chromium.

Step 2: Create the admin account through an SSH tunnel

Until an admin account exists, anyone who can reach Uptime Kuma sees the setup screen and can create that account. The server refuses a second setup only once a user exists. So finish setup privately, before the dashboard gets a public address. From your own computer, open a tunnel:

ssh -L 3001:127.0.0.1:3001 you@SERVER_IP

Keep that session open and browse to http://localhost:3001 on your computer. Our guide to local SSH port forwarding explains the syntax. Then:

  1. Choose the database. Uptime Kuma 2 asks on first start: SQLite (“a simple database file, recommended for small-scale deployments”), Embedded MariaDB (full image only) or an external MariaDB/MySQL. On a 1 GB server, pick SQLite. Treat the choice as final: the migration guide says moving an existing SQLite database to MariaDB cannot be done directly and is not officially supported.
  2. Create the admin username and password. Uptime Kuma rejects passwords its strength check rates “Too weak”; a password manager makes a long one painless.
  3. Open Settings > Security and set up two-factor authentication with an authenticator app.

Add HTTPS with Caddy and lock down the dashboard

Uptime Kuma’s reverse proxy page recommends serving it over HTTPS behind a proxy. Two details shape the setup: Uptime Kuma does not support a subdirectory such as example.com/uptime, so give it a subdomain, and its dashboard runs over WebSocket. Caddy needs no extra configuration for that: its reverse_proxy directive performs the upgrade and tunnels WebSocket connections by itself, where Nginx and Apache need extra Upgrade and Connection headers.

Create an A record (and an AAAA record if you use IPv6) such as status.example.com pointing at the server. Install Caddy from its official repository and open ports 80 and 443 as described in our Caddy reverse proxy guide. Then add this site block, the one from Uptime Kuma’s wiki, to /etc/caddy/Caddyfile:

status.example.com {
	reverse_proxy 127.0.0.1:3001
}

Reload Caddy and open the hostname in a browser. Caddy gets the certificate on the first request:

sudo systemctl reload caddy

Now finish the settings that depend on the proxy:

  • Settings > Reverse Proxy > HTTP Headers: set Trust Proxy to Yes. Caddy sends X-Forwarded-For and X-Forwarded-Host by default, and with this on Uptime Kuma logs the real client address. It is safe here because port 3001 is reachable only through Caddy.
  • Settings > General > Primary Base URL: enter https://status.example.com or press Auto Get. The Push URLs the dashboard shows, and the links that several notification types (Slack, Microsoft Teams, Pushover, PagerDuty and others) put in alerts, are built from it.
  • Leave authentication on. The Disable Auth option exists for setups where something such as Cloudflare Access or Authelia authenticates users in front of Uptime Kuma. Without that, it opens your dashboard to anyone.

Behind Cloudflare’s proxy? The wiki says WebSockets must be enabled in the Cloudflare dashboard. Use the Full (strict) SSL mode; our Caddy guide explains Caddy behind Cloudflare. Uptime Kuma can also run a Cloudflare Tunnel itself from Settings > Reverse Proxy, which needs no open ports; this guide sticks to Caddy.

Which Uptime Kuma monitor type should you use?

Uptime Kuma 2.5.5 offers more than 30 monitor types, from plain HTTP to databases, MQTT, SNMP and game servers. Three are hidden when Uptime Kuma runs in Docker, because they need the host itself: system services, SIP Options Ping and Tailscale Ping. These types cover most servers:

Monitor typeWhat counts as UPUse it forWatch out for
HTTP(s)An accepted status code, 200–299 by default, after up to 10 redirectsWebsites, APIs, health endpointsA GET downloads the full response on every check
HTTP(s) – KeywordThe same, plus a word that must appear in the response (or, with Invert Keyword, must not)Pages that can return 200 while broken, such as a database error pageThe search is case-sensitive
TCP PortA TCP connection to host:port opensSSH, databases, mail and game portsAn open port says nothing about the app behind it
PingICMP echo replies arriveBasic reachability and network latencySome networks and firewalls drop ICMP
DNSA query for the record type succeeds (A, AAAA, CAA, CNAME, MX, NS, PTR, SOA, SRV or TXT) through the resolver you set, 1.1.1.1 by defaultCatching a changed, hijacked or missing recordAdd a condition, such as the A record equals your server’s IP, or any answer counts as UP
HTTP(s) – Json QueryA JSONata expression on the response, compared with an expected value (==, !=, contains, or a numeric < <= > >=)Health endpoints that report status in JSONThe expression must return a single value, not an object or array
PushYour server or job calls the monitor’s URL within the intervalCron jobs, backups, servers that cannot be reached from outsideNo call within the interval means DOWN
Docker ContainerThe container is runningContainers on the same hostNeeds /var/run/docker.sock mounted, which gives Uptime Kuma full control of Docker; the wiki advises against exposing Kuma to the internet then
From the Uptime Kuma 2.5.5 monitor editor and source code, and the Docker container wiki page.

Point monitors only at systems you run or have permission to check. Our acceptable use policy forbids scanning networks you do not own; a TCP monitor on your own database port is fine.

Settings that prevent false alarms and missed ones

  • Heartbeat Interval: 60 seconds by default. The editor accepts lower values but warns that intervals below 20 seconds may result in poor performance.
  • Retries: version 2 creates new monitors with 0 retries, so one failed check sends an alert. One or two retries at the default 60-second retry interval filter one-off network blips, at the cost of a slower alert.
  • Request Timeout: 48 seconds by default for most types (10 for Ping), and never more than 80% of the interval.
  • Certificate Expiry Notification: off by default on each HTTPS monitor, so tick it. The warning days live in Settings > Notifications and default to 7, 14 and 21 days before expiry. Domain Name Expiry Notification is on by default.
  • Resend Notification if Down X times consecutively: 0 (off) by default; set it if a single alert is easy to miss.
  • Upside Down Mode: flips the result. A TCP monitor on your app server’s database port with Upside Down on alerts you if that port ever becomes reachable from the internet.
  • Maintenance: schedule a window from the menu to pause notifications for chosen monitors and show a message on status pages during planned work.

Check from other countries with the Globalping monitor

Since version 2.1.0 (February 2026), Uptime Kuma has a Globalping monitor type. Instead of checking from your server, it asks a probe in Globalping‘s free, community-hosted network to run a ping, HTTP(s) or DNS measurement and records the result. The location field accepts a continent, country, region, city, ASN, ISP or cloud region, one location per monitor. The default is “world”, which picks any probe; the editor’s help text suggests narrowing to a small region, plus the datacenter filter, for steadier latency.

The limit is a test budget: 250 tests per hour without an account, counted per IP address, or 500 with a free API token saved in Uptime Kuma’s settings. Globalping’s credits page counts one test per probe result, and Uptime Kuma asks for one probe per check, so every check, including retries, costs one test. That decides how many Globalping monitors one instance can run:

IntervalTests per monitor per hourMonitors without a token (250/hour)Monitors with a free token (500/hour)
60 s6048
120 s30816
300 s122041
600 s64183
Arithmetic from Globalping’s published limits as of October 3, 2026, before retries. All Globalping monitors on the instance share one budget.

Use Globalping for a few outside-in checks of your most important URLs, from the regions your users are in, and normal monitors from your server for everything else. Probes are volunteer-hosted, so a single failure can be the probe’s own network; give Globalping monitors at least one retry.

Watch cron jobs and backups with Push monitors

A Push monitor turns the check around: Uptime Kuma waits for a request and marks the monitor DOWN if none arrives within the heartbeat interval. The editor shows a URL in this form:

https://status.example.com/api/push/PUSH_TOKEN?status=up&msg=OK&ping=

Call it from the job itself, and only when the job succeeds. This crontab line on the server that runs a nightly backup reports success at about 02:30; set the Push monitor’s interval a little longer than the schedule, such as 90000 seconds (25 hours):

30 2 * * * /usr/local/bin/nightly-backup.sh && curl -fsS -m 10 -o /dev/null "https://status.example.com/api/push/PUSH_TOKEN?status=up&msg=OK&ping="

A failed backup, a full disk or a dead server all end the same way: no call, so you get an alert. The same works for a job that a systemd timer starts, such as the nightly PostgreSQL dump in our PostgreSQL guide: add the curl call as the last line of the job’s script. With set -e at the top, the script stops at the first error and never reaches it.

Set up Telegram, Discord and email notifications

Add channels under Settings > Notifications > Set Up Notification, or from any monitor’s edit page. Uptime Kuma ships more than 90 notification types. Every form has a Test button; use it before you rely on an alert. Tick Default enabled to attach a channel to new monitors, and Apply on all existing monitors to add it to the ones you already have.

ChannelWhat Uptime Kuma asks forWhere to get itNotes
TelegramBot Token and Chat IDCreate a bot with @BotFather, send it a message, then press Auto Get next to Chat ID; it reads the Bot API’s getUpdatesIf you reuse a bot that already runs on a webhook, Auto Get finds nothing: the Bot API serves no getUpdates while a webhook is set. A separate alert bot avoids that. Our Telegram bot guide covers both modes.
DiscordDiscord Webhook URLServer Settings > Integrations > View Webhooks > New Webhook (needs the Manage Webhooks permission)Discord’s webhook docs say webhooks need no bot user or authentication, so anyone with the URL can post: keep it secret. Want a real bot instead? See how to host a Discord bot on a VPS.
Email (SMTP)Hostname, port, security, username, password, From and ToYour mail provider’s SMTP settingsOutbound port 25 is blocked on new HourlyVPS servers (AUP). Use port 587 with “None / STARTTLS” or 465 with “TLS”. Since version 2, subject and body templates use LiquidJS, with case-sensitive variables.
Field names from the Uptime Kuma 2.5.5 notification forms.

Before the first real outage, pause a test monitor’s target or point a monitor at a URL that returns 404, and check that the DOWN and UP messages arrive where you expect, on the phone you actually carry.

Create a public status page

A status page shows chosen monitors to your users without giving them a login. Create one under Status Pages > New Status Page with a name and a slug; it appears at https://status.example.com/status/your-slug. The slug default is reserved. Add monitors in groups, a description and a footer, and save. Worth knowing, from the status page wiki and the source code:

  • It is not live like the dashboard: the server caches status page data for 5 minutes and heartbeat data for 1 minute, and the page reloads itself every 300 seconds by default (the Refresh Interval setting).
  • Each status page has an RSS feed at /status/your-slug/rss, and badges are available for monitors on public status pages.
  • You can post an incident message at the top of a page. There is no email sign-up for visitors in 2.5.5, so people follow a page by opening it or through its RSS feed.
  • Put the status page on a server outside the infrastructure it reports on, for the same reason as the monitor itself.

To serve a page on its own domain, such as status.yourbrand.com, create the DNS record, add a second site block to the Caddyfile and reload Caddy. Then enter the domain under Domain Names in the status page’s sidebar. Caddy passes the host name through, and Uptime Kuma uses it to pick the page:

status.yourbrand.com {
	reverse_proxy 127.0.0.1:3001
}

Back up, restore and update Uptime Kuma

Uptime Kuma 2 removed the old JSON Backup/Restore feature. The migration guide is explicit: backing up the data directory is currently the only supported backup method. For the install above, that directory is the uptime-kuma volume. Stop the container for a few seconds so the database files are consistent, archive the volume with the --volumes-from pattern from Docker’s volume backup docs, and start it again.

A nightly backup of the data volume

Save this as /usr/local/sbin/kuma-backup.sh with sudo nano. The trap line starts Uptime Kuma again even if the archive step fails:

#!/bin/sh
# Uptime Kuma backup: stop, archive the data volume, start again
set -eu
BACKUP_DIR=/var/backups/uptime-kuma
STAMP=$(date +%F-%H%M)
mkdir -p "$BACKUP_DIR"
docker stop uptime-kuma
trap 'docker start uptime-kuma' EXIT
docker run --rm --volumes-from uptime-kuma -v "$BACKUP_DIR:/backup" ubuntu \
  tar czf "/backup/kuma-data-$STAMP.tgz" -C /app data
chmod 600 "$BACKUP_DIR"/kuma-data-*.tgz
find "$BACKUP_DIR" -name 'kuma-data-*.tgz' -mtime +14 -delete

Make it executable, run it once and check the archive:

sudo chmod 700 /usr/local/sbin/kuma-backup.sh
sudo /usr/local/sbin/kuma-backup.sh
sudo ls -lh /var/backups/uptime-kuma

Schedule it in root’s crontab with sudo crontab -e. This line runs it at 03:15 server time:

15 3 * * * /usr/local/sbin/kuma-backup.sh >> /var/log/kuma-backup.log 2>&1

Checks pause for the few seconds the container is stopped. If a second instance watches this one, give that monitor one retry so the nightly stop does not page you.

Copy the backup off the server

An archive on the same disk does not survive a deleted or broken server. Copy it to another machine every night; the rsync and checksum steps in our delete-VPS checklist work for these archives too, and our restic backup guide sends them to S3-compatible storage, encrypted. Treat the archive as a secret: it holds password hashes, 2FA secrets, bot tokens, webhook URLs and SMTP passwords.

Restore on a fresh server

Install Docker on the new server, copy the newest archive to your home folder, and unpack it into a new volume before the first start:

cd ~
sudo docker volume create uptime-kuma
sudo docker run --rm -v uptime-kuma:/app/data -v "$PWD:/backup" ubuntu tar xzf /backup/kuma-data-2026-10-03-0315.tgz -C /app
sudo docker run -d --restart=always -p 127.0.0.1:3001:3001 -v uptime-kuma:/app/data --name uptime-kuma louislam/uptime-kuma:2

The restored instance starts checking and alerting at once, so stop the old one first or expect duplicate alerts. Then move the DNS record to the new IP address. Rehearse this once on a Quartz Q1 billed by the hour: a two-hour drill uses $0.02 of server time, and deleting the server afterwards stops billing. Ordering it needs an initial credit, which prepays that server’s hours. A stopped server is still billed, because its vCPU, memory, disk and IP addresses stay reserved for you; only deleting the server stops billing.

Update Uptime Kuma

The official update steps for a docker run install are: pull the new image, remove the container and run the same command again. The volume keeps your data. Back up first:

sudo /usr/local/sbin/kuma-backup.sh
sudo docker pull louislam/uptime-kuma:2
sudo docker stop uptime-kuma
sudo docker rm uptime-kuma
sudo docker run -d --restart=always -p 127.0.0.1:3001:3001 -v uptime-kuma:/app/data --name uptime-kuma louislam/uptime-kuma:2

With Compose, run docker compose pull and then docker compose up -d --force-recreate in the project folder.

Upgrading from 1.x? Read the migration guide first: stop Uptime Kuma, back up the data directory, switch the tag to :2 and watch the logs while it aggregates the heartbeat table into the new format. The author’s 20 monitors with 90 days of data took about 7 minutes, and slower hardware with more monitors can take hours; an interrupted migration means restoring the backup and starting again, and rootless images are not recommended for this step. Rehearse it by restoring last night’s backup on an hourly server and upgrading there first.

Advice in older tutorialsStatus in Uptime Kuma 2.xUse instead
louislam/uptime-kuma:latest or :1latest is deprecated and still points at v1:2, :2-slim or a pinned 2.x.x tag
Settings > Backup > Export JSONRemovedBack up the data directory or volume
Alpine-based imagesDroppedThe Debian-based 2 or 2-slim images
New monitors retry onceNew monitors start with 0 retriesSet retries on each monitor yourself
Custom placeholders in email templatesLiquidJS templates; variables are case-sensitivename, msg, status, heartbeatJSON, monitorJSON, hostnameOrUrl
DNS Cache setting on HTTP monitorsRemovedThe nscd cache bundled in the Docker image
Node.js 14, 16 or 18 for non-Docker installsUnsupportedNode.js 20.4 or newer
From the v1 to v2 migration guide and the Docker Tags page, as of 2.5.5.

Troubleshooting Uptime Kuma on a VPS

SymptomLikely causeFix
The dashboard loads but never connects, or keeps reconnectingWebSocket is not passed through: Nginx or Apache without the Upgrade and Connection headers, or WebSockets turned off in CloudflareCaddy needs no extra lines. Check Caddy’s logs with sudo journalctl -u caddy, and enable WebSockets in Cloudflare if the record is proxied.
http://SERVER_IP:3001 does not openExpected: the port is bound to 127.0.0.1Use the HTTPS hostname, or the SSH tunnel. Do not publish 3001 to work around it.
A monitor says DOWN, but the site works in your browserThe target blocks your server’s IP, a firewall drops the check, or the request times outTest from inside the container, as the troubleshooting wiki suggests: sudo docker exec -it uptime-kuma bash, then curl -I or ping the target.
A site behind Cloudflare answers Uptime Kuma with 403Cloudflare’s Browser Integrity Check blocks itAllow your Uptime Kuma server’s IP in Cloudflare IP Access rules, or use a WAF skip rule with a secret header, per the Cloudflare side note.
IPv6-only targets are always DOWNDocker containers get no IPv6 connectivity by defaultAttach Uptime Kuma to an IPv6-enabled Docker network (docker network create --ipv6 …), following Docker’s IPv6 docs.
response timeout: incomplete response within a intervalThe target answers slower than the Request Timeout, which can be at most 80% of the intervalRaise the timeout (and the interval, if the cap stops you), or find out why the target is slow.
Forgot the admin password, or lost the 2FA deviceNo other admin loginsudo docker exec -it uptime-kuma npm run reset-password, or npm run remove-2fa the same way.
The disk keeps fillingHistory is kept for 365 days by defaultLower the retention under Settings > Monitor History.
SQLITE_BUSY: database is locked or a corrupted databaseData on NFS, which the README says is not supported, or UPTIME_KUMA_SQLITE_SINGLE_CONNECTION=false, which the environment variables page warns can cause this errorKeep /app/data on a local volume or directory, remove that variable, and restore from backup if the database is damaged.
Causes and fixes from Uptime Kuma’s README, wiki and 2.5.5 source code.

What does self-hosted monitoring cost?

The software is free; the server is the cost. HourlyVPS bills by the hour, and charges for a server stop at the plan’s monthly price in each billing period (one month from your order date). So the same server covers both jobs: a trial or a restore drill costs only its hours, and an always-on monitor never costs more than a monthly VPS, with no contract. This is what the smallest plan costs over those lifetimes; our hourly vs monthly guide explains the cap.

Quartz Q1 (1 vCPU, 1 GB): a 2-hour trial, a day, a week and a month of Uptime Kuma
DurationHours on the meterCost $0.01/hour · cap $5.00/monthNote
2 hours2$0.02
1 day24$0.24
7 days168$1.68
30 days720$5.00Capped at the monthly price
Charges stop at $5.00 after 500 hours (about 20.8 days) in a billing period; the rest of that period is free.

A pair of instances watching each other doubles the server bill: each Q1 costs at most $5.00 per billing period. There is no prepaid monthly plan: leave a server on and its charges stop at the monthly price in each billing period (after 500 hours, about 20.8 days), with no contract and no annual term. Compare every plan on the pricing page.

How does that compare with a hosted service? UptimeRobot is a common reference point:

OptionPriceMonitorsShortest intervalWhere checks run from
Uptime Kuma on Quartz Q1Up to $5.00/month (the monthly cap)No limit in the software; the server’s size sets it20 s before the editor warns about performanceYour server’s city, plus Globalping probes
UptimeRobot Free$0, described as for hobby and non-profit projects505 minutesUptimeRobot’s network
UptimeRobot SoloFrom $9/month billed annually ($108/year)10 (50 on a higher tier)60 secondsUptimeRobot’s network, multi-location
UptimeRobot Team$35/month billed annually ($420/year)10030 secondsUptimeRobot’s network, multi-location
UptimeRobot plans from uptimerobot.com/pricing as of October 3, 2026; monthly billing costs more. HourlyVPS prices render from our live price list.

UptimeRobot’s pricing page also lists SSL monitoring as a paid-plan feature, while Uptime Kuma’s certificate-expiry alerts come with the free software. A hosted service is the better fit if you do not want to run another server, if you want checks confirmed from several regions before an alert, or if you need team seats and phone-friendly escalation out of the box. Self-hosting Uptime Kuma fits when you want many monitors at short intervals, checks of private targets such as databases and internal ports, status pages on your own domain at no extra cost, and the monitoring data on a server you control. The two also combine well: a free hosted check is a cheap way to watch your Uptime Kuma instance itself.

Deploy this setup

Run Uptime Kuma 24/7 in a different city from your servers

Quartz Q1 · 1 shared vCPU · 1 GB RAM · 25 GB NVMe · Istanbul

  • Per hour$0.01/hour
  • Per day (24 h)$0.24/day
  • Monthly cap$5.00/monthFor this job
Deploy Quartz Q1

Starts with a $5 initial credit, which goes into the server’s balance and pays for its hours.

Billed by the hour, never more than $5.00 per billing period. Delete the server and billing stops.

FAQ

Is Uptime Kuma free?

Yes. Uptime Kuma is open source under the MIT license, with no paid edition or monitor limit. You pay only for the server it runs on; the project publishes no hardware minimum, so start small with SQLite and check real usage with docker stats.

What port does Uptime Kuma use?

It listens on port 3001 by default; the UPTIME_KUMA_PORT environment variable changes it. In Docker, publish it as 127.0.0.1:3001:3001 and let a reverse proxy such as Caddy serve it on 443, so the port itself is never reachable from the internet.

Can Uptime Kuma monitor from multiple locations?

Not by itself: every regular check runs from the server Uptime Kuma is installed on. The Globalping monitor type, added in version 2.1.0, runs ping, HTTP and DNS checks from probes in a location you choose, one location per monitor, and a second instance in another city adds an independent vantage point.

Should Uptime Kuma use SQLite or MariaDB?

Uptime Kuma's setup screen recommends SQLite for small-scale deployments, and it is the lighter choice on a 1 GB server. Embedded MariaDB comes only with the full Docker image, and the project offers no supported way to move an existing SQLite database to MariaDB, so decide at setup.

Can I run Uptime Kuma on the same server as my website?

You can, and it will catch crashed apps and expiring certificates, but it cannot tell you when that server or its network goes down, because it goes down too. Run it on a separate server, ideally in another city.

Does Uptime Kuma have an API?

It has REST endpoints for push monitors, status badges, public status page data and Prometheus metrics at /metrics; the metrics endpoint takes HTTP basic auth with your login, or an API key once you create one under Settings > API Keys. The Socket.IO API the dashboard uses is internal, and the project says it is not officially supported for third-party integrations.

Does Uptime Kuma need a domain name?

Not to run: you can reach the dashboard through an SSH tunnel to port 3001. For HTTPS through a reverse proxy, and for a public status page, give it a domain or subdomain of its own, because Uptime Kuma does not support running under a subdirectory such as example.com/uptime.

Sources

  1. Uptime Kuma README (install, features)Uptime Kuma on GitHub · github.com · checked
  2. Reverse ProxyUptime Kuma wiki · github.com · checked
  3. Docker Tags (full vs slim, rootless)Uptime Kuma wiki · github.com · checked
  4. Migration From v1 To v2Uptime Kuma wiki · github.com · checked
  5. How to UpdateUptime Kuma wiki · github.com · checked
  6. Status PageUptime Kuma wiki · github.com · checked
  7. Ubuntu Server system requirementsUbuntu Server documentation · ubuntu.com · checked
  8. Tests and credits (free hourly limits)Globalping (jsDelivr) · globalping.io · checked
  9. Volumes: back up, restore, or migrate data volumesDocker Docs · docs.docker.com · checked
  10. UptimeRobot pricingUptimeRobot · uptimerobot.com · checked
All posts