# Deploy Uptime Kuma with the uptime-kuma template

Source: https://docs.quake.ai/resources/deployments/deploy-uptime-kuma-template
Markdown: https://docs.quake.ai/resources/deployments/deploy-uptime-kuma-template.md

---

# Deploy Uptime Kuma with the uptime-kuma template

Stand up [Uptime Kuma](https://github.com/louislam/uptime-kuma), an open-source uptime-monitoring and status-page tool, on a single Quake AI instance using the [validated OpenTofu template](/docs/platform/validation#how-infrastructure-templates-are-checked) `uptime-kuma`. You apply the template, reach the dashboard over the floating IP, create the admin account, add monitors for a service you run, send an alert to a notification channel, and publish a public status page.

Uptime Kuma watches the services you deploy and tells your users when something is down. You run it yourself; this is a self-hosted tool you operate, not a managed service.

<Figure size="md" caption="What you'll build: an Uptime Kuma host on a single instance, with a restricted admin dashboard, monitors polling your services, and a public status page served over HTTPS through a Caddy reverse proxy">

```d2
direction: right

dev: You {shape: person}
viewer: Status page viewer {shape: person}
fip: Floating IP
instance: Ubuntu instance {
  caddy: Caddy\nreverse proxy
  kuma: Uptime Kuma\ndashboard + checks
  caddy -> kuma: proxies 443 to 3001
}
app: Your service

dev -> fip: HTTPS dashboard
viewer -> fip: HTTPS status page
fip -> instance.caddy
instance.kuma -> app: HTTP / TCP / ping checks
```

</Figure>

<PricingCompanion
  components={[
    { kind: "template", slug: "uptime-kuma", required: true },
  ]}
/>

## Prerequisites

You need:

- OpenTofu 1.6.0 or later (or Terraform 1.6.0 or later) installed locally.
- Your OpenStack credentials sourced into the shell (`source openrc.sh`). See [the OpenStack CLI guide](/docs/tools/openstack-cli).
- An SSH keypair that already exists in your project. Record its name for the `key_name` variable.
- A copy of the `uptime-kuma` template directory from [the template reference page](/resources/iac-templates/uptime-kuma).
- A service you want to monitor (an HTTP endpoint, a TCP port, or a host that answers pings). Any app you have already deployed works.
- Your workstation's public IP address, so you can open the dashboard port to it for first-boot setup. Find it with `curl -sS https://api.ipify.org`.

A domain is optional for first boot. You add it later to serve the dashboard and the public status page over HTTPS.

## Step 1: Set the variables and apply the template

The dashboard listens on port 3001 over plain HTTP. The template's security group restricts port 3001 to `dashboard_allowed_cidr`, which defaults to the private network only, so the raw dashboard stays off the public internet. To reach the dashboard from your workstation for first-boot setup, set `dashboard_allowed_cidr` to your own address.

Copy the template's example variables file and open it:

```bash
cp terraform.tfvars.example terraform.tfvars
```

Set `key_name` to the SSH keypair already in your project, and `dashboard_allowed_cidr` to your workstation's public IP with a `/32` suffix:

```hcl
key_name               = "YOUR_KEY_NAME"
dashboard_allowed_cidr = "YOUR_IP/32"
```



If you would rather not expose port 3001 at all, leave `dashboard_allowed_cidr` at its default and reach the dashboard over an SSH tunnel instead: `ssh -L 3001:localhost:3001 ubuntu@YOUR_FLOATING_IP`, then open `http://localhost:3001`. Once you add a domain, Caddy serves the dashboard over HTTPS on port 443 and you no longer need port 3001 open.



Initialize the working directory, preview the plan, and apply:

```bash
tofu init
tofu plan
tofu apply
```

OpenTofu provisions a private network, a router, a security group, a block volume mounted at `/var/lib/docker`, an instance, and a floating IP. On first boot, cloud-init mounts the data volume, installs Docker Engine, and starts Uptime Kuma from a compose file on port 3001.

When the apply finishes, read the outputs:

```bash
tofu output
```

Record `floating_ip`, `dashboard_url`, and `status_page_url`.

## Step 2: Create the admin account

Uptime Kuma does not ship a default password. You create the admin account the first time you open the dashboard.

cloud-init takes a minute or two after the instance reaches `ACTIVE`. Open `dashboard_url` (for example `http://YOUR_FLOATING_IP:3001`) in your browser. If the page does not load yet, wait and retry; you can watch the container start over SSH:

```bash
ssh ubuntu@YOUR_FLOATING_IP "sudo docker ps --filter name=uptime-kuma"
```

When the setup screen appears, enter a username and a strong password to create the admin account. Uptime Kuma signs you in and opens an empty dashboard.

## Step 3: Add monitors for your service

A monitor is one check that Uptime Kuma runs on a schedule. Add one of each common type for the service you want to watch.

1. Select **Add New Monitor**. Set **Monitor Type** to `HTTP(s)`, **Friendly Name** to a label such as `API health`, and **URL** to your service's health endpoint (for example `https://api.example.com/health`). Set **Heartbeat Interval** to `60` seconds. Select **Save**.
2. Add a second monitor with **Monitor Type** `TCP Port`. Set **Hostname** to your service host and **Port** to the port you depend on (for example `5432` for a database). Select **Save**.
3. Add a third monitor with **Monitor Type** `Ping`. Set **Hostname** to the host you want to reach. Select **Save**.

Each monitor shows a live status and a heartbeat bar. Within a couple of intervals, a reachable service shows green. To confirm the failure path, stop the monitored service briefly: the monitor turns red and records a downtime event.

## Step 4: Send alerts to a notification channel

A monitor is useful once it tells you about a failure. Add a notification channel and attach it to your monitors.

1. Go to **Settings** > **Notifications** > **Setup Notification**.
2. Choose a **Notification Type**. Email (SMTP), a webhook, and chat integrations (Slack, Discord, Telegram) are all built in. For a webhook, set the URL your receiver listens on.
3. Select **Test** to send a sample alert and confirm it arrives, then **Save**.
4. Enable **Default enabled** so new monitors use the channel, or open each monitor and attach the notification under **Notifications**.

When a check fails, Uptime Kuma sends an alert through the channel and a recovery message when the service returns.

## Step 5: Publish a public status page

A status page is a public, read-only view of the monitors you choose. It is separate from the admin dashboard, which stays restricted.

1. Go to **Status Pages** > **New Status Page**. Set a **Name** and a **Slug** such as `public`. The page is served at `/status/public`.
2. On the page editor, add the monitors you want visible. A status page shows only the monitors you add, so leave internal checks (such as a database port) off a public page.
3. Set the page to **Published** and select **Save**.

The status page is now reachable at `http://YOUR_FLOATING_IP:3001/status/public`. Status pages are meant to be public, so you expose this path deliberately while keeping the admin dashboard restricted.

## Step 6: Serve the dashboard and status page over HTTPS

The template leaves ports 80 and 443 open for a reverse proxy. [Caddy](https://caddyserver.com) obtains and renews a TLS certificate automatically once a domain resolves to the instance.

1. Create a DNS **A record** for your domain (for example `status.example.com`) pointing at `YOUR_FLOATING_IP`. Follow [How to point a domain at a Quake AI resource](/docs/network/how-to/point-domain-to-quake-ai). Wait until the record resolves:

```bash
dig +short status.example.com
```

2. SSH to the instance and create `/opt/uptime-kuma/Caddyfile`:

```text
status.example.com {
  reverse_proxy 127.0.0.1:3001
}
```

3. Add Caddy to the compose file at `/opt/uptime-kuma/docker-compose.yml` so it runs alongside Uptime Kuma:

```yaml
services:
  caddy:
    image: caddy:2
    restart: unless-stopped
    network_mode: host
    volumes:
      - /opt/uptime-kuma/Caddyfile:/etc/caddy/Caddyfile
      - caddy_data:/data
volumes:
  caddy_data:
```

4. Apply the changes and confirm both containers run:

```bash
cd /opt/uptime-kuma
sudo docker compose up -d
sudo docker compose ps
```

Open `https://status.example.com/status/public` and confirm the padlock. For background on certificate issuance and renewal, see [How to issue and auto-renew a TLS certificate with Let's Encrypt](/docs/network/how-to/lets-encrypt-certificate). Once HTTPS works, close direct access to port 3001 by setting `dashboard_allowed_cidr` back to the private network in `terraform.tfvars` and running `tofu apply`.

## What you built

- **Applied the `uptime-kuma` template** to provision a network, security group, data volume, instance, and floating IP, and let cloud-init install Docker and start Uptime Kuma
- **Created the admin account** on the dashboard's first-boot screen
- **Added HTTP, TCP, and ping monitors** for a service you run
- **Sent alerts to a notification channel** and confirmed delivery
- **Published a public status page** and served it over HTTPS through a Caddy reverse proxy

## Scope of this deployment

This template runs a single-VM Uptime Kuma host, not a managed monitoring cloud. The instance is CPU-only and runs in one region, so run it in a different region from the workloads it watches: a monitor that shares a failure domain with the service it checks cannot report a region-wide outage. You operate the instance, Docker, Uptime Kuma, and the data volume yourself: back them up, patch them, and snapshot the volume before you resize or rebuild the host.

## Next steps

- [Uptime Kuma template](/resources/iac-templates/uptime-kuma): the template reference, parameters, and resource map
- [Deploy Umami with the analytics-umami template](/resources/deployments/deploy-analytics-umami-template): add product analytics alongside uptime monitoring
- [Deploy the monitoring stack](/resources/iac-templates/monitoring-stack): add Prometheus and Grafana for infrastructure metrics
- [How to point a domain at a Quake AI resource](/docs/network/how-to/point-domain-to-quake-ai): the DNS step in full
- [Security hardening checklist](/docs/security/hardening-checklist): tighten SSH access and exposure before you serve real traffic

## Clean up

When you no longer need the deployment, destroy everything the template created:

```bash
tofu destroy
```

Then remove the DNS A record you created in step 6. Because the monitors, history, and status pages all live on the instance and its attached volume, `tofu destroy` removes them along with the infrastructure. Export any configuration you want to keep before you destroy.
