This guide takes a fresh 1 GB VPS to a working Uptime Kuma dashboard: Docker, the container, a private way into the dashboard, the admin account, and a first monitor that checks a service on the same server. Every command below is one we ran on 2026-11-08, and every number comes from that run's logs.
Tested on: Vultr vc2-1c-1gb (1 vCPU, 1 GB RAM, 25 GB SSD), Ubuntu 24.04.5 LTS, Docker 29.9.3, Uptime Kuma 2.5.9 (image louislam/uptime-kuma:2), SQLite. The full memory test is in Uptime Kuma RAM usage on a 1 GB VPS.
Not covered: a domain name with HTTPS, notifications (email, Telegram and so on), and backups. We didn't run those on this box, so they aren't written up here yet.
1. Check what the server has
Log in as root and look at memory and swap before installing anything.
free -m
swapon --show
On our fresh installs free -m reported 955 MB total and 620 to 657 MB available. Vultr's Ubuntu 24.04 image already had a 2.3 GB swap file (/swapfile), which matters later: when memory gets tight the kernel can move part of Kuma to swap instead of killing it.
2. Install Docker
curl -fsSL https://get.docker.com | sh
docker --version
The install script took 52 seconds and gave us Docker 29.9.3.
3. Start Uptime Kuma
docker run -d --restart=always \
-p 127.0.0.1:3001:3001 \
-v kuma-data:/app/data \
-e UPTIME_KUMA_DB_TYPE=sqlite \
--name kuma louislam/uptime-kuma:2
What each part does:
-p 127.0.0.1:3001:3001opens the dashboard on the server itself only, not to the internet. On our box ufw was logging outside connection attempts within minutes of boot, so keep this binding and use the tunnel in the next step.-v kuma-data:/app/datakeeps the database in a Docker volume, so removing or upgrading the container doesn't lose your monitors. Ours was 1.2 MB idle and 5.0 MB after the 110-monitor test.-e UPTIME_KUMA_DB_TYPE=sqlitepicks SQLite up front. Without it, version 2 opens a "Which database would you like to use?" screen with Embedded MariaDB, MariaDB/MySQL and SQLite. Our numbers are all SQLite; we didn't measure MariaDB.--restart=alwaysbrings Kuma back after a reboot or a crash.
The first pull of the full image is large: louislam/uptime-kuma:2 was 2.53 GB on disk, and the 2-slim tag was 861 MB. After the pull, the container answered HTTP about 6 seconds after docker run. Check that it's up:
curl -sI http://127.0.0.1:3001/ | head -1
docker logs kuma 2>&1 | tail -5
The log should end with Kuma listening on port 3001.
4. Open the dashboard through an SSH tunnel
Because the port only listens on the server's 127.0.0.1, reach it from your own computer through SSH. Run this on your computer, not on the server:
ssh -L 3001:127.0.0.1:3001 root@YOUR_SERVER_IP
Leave that session open and go to http://localhost:3001 in your browser. Closing the SSH session closes the tunnel; Kuma keeps running on the server.
5. Create the admin account
The first page is "Create your admin account" with Username, Password and Repeat Password. Use a long, unique password. Anyone who can reach this page before you can claim the account, which is one more reason to keep the port on 127.0.0.1.
6. Let Kuma check services on the same server
This is the step that cost us our first run. If you want Kuma to watch something on the same box (a website served by nginx, an app on port 8080), the request leaves the container and comes back to the host through the Docker bridge. Vultr's Ubuntu 24.04 image had ufw active with only 22/tcp open, and it dropped that traffic. Every HTTP monitor aimed at the host's nginx timed out, while ping monitors to the same address were fine.
Allow the Docker bridge network to reach the port you're monitoring. For a web server on port 80:
ufw allow from 172.17.0.0/16 to any port 80 proto tcp
Change 80 to your service's port. Then test from inside the container (172.17.0.1 is the host as seen from Docker's default bridge):
docker exec kuma node -e "require('http').get('http://172.17.0.1/', r => { console.log(r.statusCode); process.exit() })"
Before the rule it hung (we gave up after 8 seconds); after it, it printed 200. Checks against outside sites don't need this rule. We only tested targets on the host itself.
7. Add your first monitor
Click "Add New Monitor", pick HTTP(s), and enter the URL. For a site on the same server, use http://172.17.0.1/ (with the port if it isn't 80), not localhost: inside the container, localhost is the container itself.
Our test monitors used a 60-second interval and no retries. When the first check comes back, the monitor turns green with "200 - OK" in the event list.
8. Check how much memory is left
free -m
docker stats --no-stream kuma
What we saw on the 1 GB box: Kuma's process used about 170 MB idle and about 181 MB with 110 monitors, and the server still had 455 MB available. Installing Docker and nginx first had already taken available memory from 657 MB to 539 MB in that run.
docker stats jumps around: at the same process size it read anywhere from 123 MiB to 215 MiB in our runs. Look at free -m "available" for the question "is the box running out?"
9. Optional: cap Kuma's memory
If Kuma shares the server with other apps, you can put a ceiling on it so one process can't take the whole box:
docker update --memory=256m --memory-swap=256m kuma
With 110 monitors all up, Kuma ran for about 5 minutes under this 256 MB cap at about 167 MiB, with no out-of-memory kill and no restart. That's a short test, so watch it for a while on your own box. Docker container memory limits explains how the two flags work together.
What's next
- Whether 1 GB is enough, with the full numbers at 0, 20, 60 and 110 monitors: Uptime Kuma RAM usage on a 1 GB VPS.
- Whether to self-host monitoring at all: Should you self-host Uptime Kuma or pay for monitoring?