Install Uptime Kuma on Ubuntu Server

Why Ubuntu for Uptime Kuma?

Ubuntu Server is the default choice for running monitoring infrastructure. Uptime Kuma on Ubuntu gives you a production-ready monitoring dashboard with proper systemd integration, firewall rules, and full access to notification providers. This guide covers Docker deployment, UFW configuration, setting up notifications (SMTP, Discord, Slack), and the key differentiator: monitoring your Docker containers directly via the Docker socket.

Prerequisites

  • Ubuntu 22.04 or 24.04 LTS server
  • Docker and Docker Compose installed (guide)
  • 256 MB of free RAM
  • 500 MB of free disk space
  • SSH access with a sudo-capable user
  • A domain name (optional, for remote access and public status pages)

Install Docker

If Docker is not already installed:

sudo apt update && sudo apt install -y ca-certificates curl gnupg
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt update && sudo apt install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin
sudo usermod -aG docker $USER

Log out and back in for the group change.

Configure UFW Firewall

sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow ssh
sudo ufw allow 3001/tcp comment "Uptime Kuma"
sudo ufw enable

If you put Uptime Kuma behind a reverse proxy, replace the port 3001 rule with ports 80 and 443 instead and access Kuma only through the proxy.

Docker Compose Configuration

Create the project directory:

mkdir -p ~/uptime-kuma && cd ~/uptime-kuma

Create docker-compose.yml:

services:
  uptime-kuma:
    image: louislam/uptime-kuma:2.2.1
    container_name: uptime-kuma
    restart: unless-stopped
    volumes:
      - uptime-kuma-data:/app/data
      # Mount Docker socket to monitor container status
      - /var/run/docker.sock:/var/run/docker.sock:ro
    ports:
      - "3001:3001"
    environment:
      # Optional: set the data directory explicitly
      - DATA_DIR=/app/data
    healthcheck:
      test: ["CMD-SHELL", "node -e \"const http = require('http'); const options = { hostname: '127.0.0.1', port: 3001, path: '/api/health', timeout: 2000 }; const req = http.request(options, (res) => { process.exit(res.statusCode === 200 ? 0 : 1); }); req.on('error', () => process.exit(1)); req.end();\""]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 30s

volumes:
  uptime-kuma-data:

Start it:

docker compose up -d

Verify:

docker compose ps
curl -s http://localhost:3001/api/health

First-Time Setup

  1. Open http://your-server-ip:3001 in a browser
  2. Create your admin account (username + password)
  3. You are immediately in the dashboard, ready to add monitors

Add Your First Monitor

Click Add New Monitor and configure:

  • Monitor Type: HTTP(s)
  • Friendly Name: My Website
  • URL: https://example.com
  • Heartbeat Interval: 60 seconds
  • Retries: 3

Click Save and the monitor starts checking immediately.

Set Up Notifications

Uptime Kuma supports 90+ notification providers. Here are the most common:

SMTP Email

Go to Settings > Notifications > Setup Notification:

  • Type: SMTP
  • SMTP Host: smtp.gmail.com (or your provider)
  • SMTP Port: 587
  • Security: STARTTLS
  • Username: your email
  • Password: app-specific password (for Gmail, generate one in Google account settings)
  • From: [email protected]
  • To: [email protected]

Discord

  1. In your Discord server, go to Server Settings > Integrations > Webhooks > New Webhook
  2. Copy the webhook URL
  3. In Uptime Kuma: Settings > Notifications > Discord, paste the webhook URL

Slack

  1. Create a Slack incoming webhook at https://api.slack.com/messaging/webhooks
  2. In Uptime Kuma: Settings > Notifications > Slack, paste the webhook URL

Telegram

  1. Message @BotFather on Telegram, create a bot, get the token
  2. Get your chat ID by messaging @userinfobot
  3. In Uptime Kuma: Settings > Notifications > Telegram, enter bot token and chat ID

Monitor Docker Containers

The Docker socket mount (/var/run/docker.sock:/var/run/docker.sock:ro) lets Uptime Kuma monitor container status directly.

To add a Docker container monitor:

  1. Click Add New Monitor
  2. Monitor Type: Docker Container
  3. Container Name / ID: the container name (e.g., vaultwarden)
  4. Docker Host: select the default Docker host (auto-detected from socket)

This monitors whether the container is running. If it stops, you get an alert. Combine this with HTTP monitors for a full picture — the container can be running but the app inside can be unresponsive.

Security Note on Docker Socket

Mounting the Docker socket gives Uptime Kuma read access to all container information. The :ro flag makes it read-only, which limits the attack surface. If you want tighter security, use a Docker socket proxy like tecnativa/docker-socket-proxy:

services:
  docker-socket-proxy:
    image: tecnativa/docker-socket-proxy:0.3.0
    container_name: docker-socket-proxy
    restart: unless-stopped
    environment:
      - CONTAINERS=1
      - POST=0
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
    networks:
      - internal

  uptime-kuma:
    image: louislam/uptime-kuma:2.2.1
    container_name: uptime-kuma
    restart: unless-stopped
    volumes:
      - uptime-kuma-data:/app/data
    ports:
      - "3001:3001"
    environment:
      - DOCKER_HOST=tcp://docker-socket-proxy:2375
    networks:
      - internal

volumes:
  uptime-kuma-data:

networks:
  internal:

Ubuntu-Specific Optimization

Systemd service for auto-start. Docker Compose with restart: unless-stopped handles this automatically, but if you want explicit systemd control:

sudo tee /etc/systemd/system/uptime-kuma.service > /dev/null <<EOF
[Unit]
Description=Uptime Kuma
After=docker.service
Requires=docker.service

[Service]
Type=oneshot
RemainAfterExit=yes
WorkingDirectory=/home/$USER/uptime-kuma
ExecStart=/usr/bin/docker compose up -d
ExecStop=/usr/bin/docker compose down

[Install]
WantedBy=multi-user.target
EOF

sudo systemctl daemon-reload
sudo systemctl enable uptime-kuma

Log rotation. Prevent monitoring logs from filling the disk:

Add to /etc/docker/daemon.json:

{
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "10m",
    "max-file": "3"
  }
}
sudo systemctl restart docker

Automatic security updates:

sudo apt install -y unattended-upgrades
sudo dpkg-reconfigure -plow unattended-upgrades

Troubleshooting

Dashboard loads but monitors show “pending”

Uptime Kuma needs a moment after startup to begin checking monitors. Wait 30-60 seconds. If monitors stay pending, check the container logs:

docker compose logs -f uptime-kuma

Cannot connect to Docker socket

If Docker container monitors fail with a socket error:

# Verify the socket exists and is readable
ls -la /var/run/docker.sock

The container must run as root or the socket must be readable by the container user. The default image runs as root, so this should work out of the box.

Notifications not sending

Test the notification channel from the Uptime Kuma UI before relying on it. Check:

  • SMTP: verify credentials, check if your provider requires app passwords (Gmail does)
  • Discord/Slack: verify the webhook URL is correct and the channel exists
  • Check container logs for notification errors: docker compose logs uptime-kuma | grep -i notification

High memory usage over time

Uptime Kuma stores monitoring history in SQLite. Over months, the database grows. Configure data retention under Settings > General > Keep monitor history for — 180 days is a reasonable default.

Port 3001 not accessible from outside

Check UFW:

sudo ufw status

Ensure the rule for port 3001 exists. If Docker is bypassing UFW, see the iptables note in the Vaultwarden Ubuntu guide.

Resource Requirements

  • RAM: ~100 MB idle with a few monitors, ~256 MB with 50+ monitors
  • CPU: Low. One HTTP check per minute per monitor is negligible.
  • Disk: ~50 MB for the application, SQLite database grows with monitoring history (typically 100-500 MB after months)

Comments