Quick start: Set up your monitoring system in 5 minutes
A website crash at 2:00 AM is every sysadmin’s worst nightmare. Customers can’t complete purchases. Management calls non-stop. Worst of all, you only find out when users start filing complaints.
Instead of spending $15–$30 every month on services like Better Stack or Pingdom, you can easily self-host your own monitoring station. Uptime Kuma is a lightweight, open-source tool that consumes under 150MB of RAM and requires just a single configuration file to run.
Create a project directory and open the configuration file:
mkdir -p uptime-kuma && cd uptime-kuma
nano docker-compose.yml
Paste the following configuration into docker-compose.yml:
version: '3.8'
services:
uptime-kuma:
image: louislam/uptime-kuma:1
container_name: uptime-kuma
restart: always
ports:
- "3001:3001"
volumes:
- ./kuma-data:/app/data
Start the container in detached mode:
docker compose up -d
Pulling the image takes around 30 to 60 seconds. Once finished, navigate to http://your-server-ip:3001. The browser will prompt you to create an admin account on your first visit. Once you set your password, you will be taken straight to the dashboard.
Under the hood: How each component works
Why use Docker Compose instead of standalone commands?
Many developers get into the habit of running docker run directly in the terminal. While quick at first, you will likely forget your volume mounts or port mappings after a server reboot several months down the road. The result? Total loss of your uptime history.
Writing everything into a Compose file lets you manage infrastructure as code (IaC):
- louislam/uptime-kuma:1: Locks to major version 1. The container will automatically receive security patches without risking unexpected breaking changes.
- restart: always: Automatically restarts the container if the process crashes or after a host reboot.
- ./kuma-data:/app/data: Persists the SQLite database and probe configurations. Even if you remove the container or upgrade the image, your data stays intact on the host storage.
Adding your first monitored endpoint
From the dashboard, click Add New Monitor in the top-left corner:
- Monitor Type: Select
HTTP(s)for websites or REST APIs. If you want to check network latency or packet loss, choosePing. - Friendly Name: Choose a clear, recognizable name, e.g., Production API Gateway.
- URL: Enter the endpoint to check, e.g.,
https://api.yourdomain.com/healthz. - Heartbeat Interval: Keep the default of 60 seconds. Every minute, Uptime Kuma sends an HTTP request. Any 2xx status code is marked as up, while 5xx errors or timeouts exceeding 48 seconds trigger an incident.
- Retries: Set this to
2or3. This prevents false alarms caused by brief, 1–2 second network hiccups.
Configuring a Telegram bot for instant alerts
Telegram is one of the best alert channels available: it is completely free, delivers messages in under a second, and supports granular group permissions.
- Open Telegram, start a chat with @BotFather, send
/newbot, and follow the prompts. BotFather will provide an HTTP API Token formatted like123456789:ABCdefGhI.... - Message @userinfobot and tap Start to retrieve your personal Chat ID. To deliver alerts to an on-call team, invite the bot to your group and use the group ID (typically prefixed with a minus sign, such as
-1001234567890). - In Uptime Kuma, go to Settings > Notifications > Setup Notification.
- Select Telegram, then enter the Token and Chat ID you just generated.
- Click Test. If your phone buzzes immediately with a test notification, the integration works. Remember to toggle Default enabled so this channel applies to all future monitors.
System optimization: Production-ready security and stability
1. Close port 3001 and use a Reverse Proxy with HTTPS
Exposing port 3001 directly to the public internet introduces unnecessary security risks. You should restrict public access to this port and route traffic through Nginx or Cloudflare Tunnel to enable free SSL certificates.
In your docker-compose.yml file, update the port mapping to:
ports:
- "127.0.0.1:3001:3001"
This binds the port strictly to the loopback interface, allowing access only from a local reverse proxy on the same VPS.
2. Create a public Status Page for end users
Uptime Kuma includes a built-in Status Page feature. You can group public-facing services, add your brand logo, and assign a custom domain such as status.yourdomain.com. During major outages, an external status page dramatically cuts down on duplicate support tickets sent to your engineering team.
3. Catch silent failures with Keyword Search
Many critical database errors (such as MySQL connection drops on WordPress) still return an HTTP 200 status code alongside a blank page or inline error text. Relying solely on status codes can produce false-positive green checks.
To avoid this, switch the Monitor Type to HTTP(s) – Keyword. Specify a fixed string that consistently appears in your site header or footer (e.g., Copyright 2026). Uptime Kuma will only mark the service as healthy when the response body actually contains that keyword.
Real-world production tips
- Never host Uptime Kuma on the same server as your target services: If the VPS suffers a power failure or bandwidth saturation, both your application and your monitor will crash at the exact same moment. No one will be left to send the alert. Invest in an independent, low-cost VPS (1 vCPU, 1GB RAM for around $3–$5/month) from a different cloud provider dedicated exclusively to monitoring.
- Automate your data directory backups: All historical telemetry lives inside
./kuma-data. Set up a nightly cronjob to compress this folder and sync backups off-site to S3 or Google Drive via rclone. These backup archives typically stay under a few megabytes. - Choose your probe interval wisely: Avoid dropping your check interval to 5–10 seconds unless strictly necessary. Aggressive polling bloats web server logs, wastes CPU cycles, and may trigger WAF rate limits or IP blocks on services like Cloudflare due to scraping or DoS mitigation rules. A 60-second interval is the sweet spot for 95% of production use cases.

