Uptime KumaをDockerで構築して死活監視する方法
Uptime KumaをDockerで別VPSに構築し、Webサイト、ポート、DNS、cronを監視します。メールやTelegram、Discord、webhook通知と公開ステータスページの設定方法を解説します。
構築するもの
外部から他のサーバーや Web サイトを監視し、応答しなくなった瞬間にメール、Telegram、Discord、または webhook で通知する小規模なコンテナを 1 つ構築します。Uptime Kuma は 1 つの Node プロセスで動作し、この構成では SQLite ファイルを使用します(v2 では組み込みまたは外部の MariaDB も使用できます)。そのため、256-512 MB の RAM で無理なく動作し、ライブダッシュボード、履歴グラフ、公開ステータスページを提供します。インストールに必要な Compose ファイルは 10 行です。実際に重要なのは、どこで実行するかと、テストでアラートが実際に送信されることを確認したかです。到達可能であることを一度も検証していない監視は、何もないより悪い結果になります。監視しているつもりでも、何も検知できないためです。
監視対象に及ばない場所でモニターを実行する
この判断が全体の成否を左右するため、最初に説明します。Uptime Kuma は、監視対象と同じホストで実行しないでください。 モニターを監視対象のサーバー上で動かすと、検知したい事象、つまりそのサーバーの停止やメモリ不足が発生した際に、モニターも停止します。その結果、アラートは一切届きません。停止したモニターから何も通知されない状態は、「すべて正常です」という状態と区別できません。サーバーが稼働している場合にも、別の問題があります。localhost を監視するモニターはワークロードと CPU を共有するため、負荷が急増すると自身のチェックがタイムアウトし、実際にはユーザーへのサービス提供が正常でも、対象を down と判定する誤警報が発生します。
そのため、Uptime Kuma は監視対象とは 別の VPS で実行してください。できれば、プロバイダーまたはリージョンも分けます。ユーザーと同じ方法で、つまりホスト名を使ってパブリックインターネット経由でサービスへ接続させます。安価なインスタンスで十分です。1 台の小規模な監視用 VPS で、すべてのサーバーを監視できます。この分離は、ホストしている負荷の高いアプリケーションで特に重要です。たとえば PhotoPrism や Immich の写真ライブラリ は、新しく取り込んだデータのインデックス作成中に数時間 CPU を占有することがあります。同じハードウェア上で動くモニターは、単に処理が忙しいだけのサービスを down と誤判定します。Kuma 自体の停止も検知するには、別の場所から cron で push heartbeat を送信してください。
前提条件とリソース規模
- Docker 独自の apt リポジトリから Docker Engine と Compose v2 plugin をインストールした、まっさらな Ubuntu 24.04 VPS。遅れている
docker.iodistro package は使用しません。 - 256 MB RAM で少数の monitor を実行できます。数十個の monitor と reverse proxy を運用する場合は、512 MB から 1 GB が余裕のある構成です。チェックの合間は CPU 使用率がほぼアイドル状態になります。
- TLS と公開 status page が必要な場合だけ、domain と DNS
Arecord(例:status.example.comが VPS を指す設定)。private instance では DNS を省略し、VPN または SSH tunnel を使用できます。 - アラートの送信先への outbound network。メールプロバイダーには SMTP、Telegram と Discord には HTTPS を使用します。
Compose ファイル
/srv/uptime-kuma/compose.yaml に次の内容を記述します。
services:
uptime-kuma:
image: louislam/uptime-kuma:2
container_name: uptime-kuma
restart: unless-stopped
ports:
- "127.0.0.1:3001:3001"
volumes:
- kuma-data:/app/data
volumes:
kuma-data:起動して、初回起動時の動作を確認します。
sudo mkdir -p /srv/uptime-kuma
# save the file above as /srv/uptime-kuma/compose.yaml, then:
cd /srv/uptime-kuma && sudo docker compose up -d
sudo docker compose logs -f uptime-kuma正常に起動すると、Listening on 3001 がログに出力され、その後は静かになります。このファイルには、意図的に指定している点が3つあります。
127.0.0.1:3001:3001 であり、3001:3001 ではありません。 Docker は、ufw がパケットを確認する前に DNAT ルールでポートを公開します。そのため、単純な 3001:3001 では、ufw のルールに関係なくダッシュボードがパブリックインターネットに公開されます。フィルタリングできるのは、Docker 自身の DOCKER-USER チェーンに追加したルールだけです。loopback にバインドすれば非公開に保て、外部に公開されるのは reverse proxy だけになります。また、3001 に到達できるのはホスト自身だけになります。reverse proxy を使わない非公開インスタンスには、下記の SSH トンネルを使用します。自分でホストする WireGuard VPN 経由で到達する場合は、127.0.0.1 ではなく、サーバーの WireGuard アドレス(例: 10.8.0.1:3001:3001)でポートを公開する必要があります。
/app/data に named volume を指定します。 Uptime Kuma が保持するすべてのデータ、SQLite データベース、監視設定、通知設定、ステータスページのロゴは、ここに保存されます。これを失うと、空の管理画面から設定をやり直すことになります。バックアップが必要なのはこれだけです。
イメージは major tag の :2 に固定します。 これは現在の安定系列です。コピーする前に Docker Hub で最新の major を確認してください。プロジェクトが非推奨としている latest のような、変動する tag は使用しないでください。このイメージで major version を更新すると、データベースの migration が実行されます。通常の pull で偶然実行するのではなく、新しいバックアップを用意したうえで、意図的に実行する必要があります。
注意点が1つあります。/app/data は、POSIX file lock に対応したファイルシステム上に配置する必要があります。ローカルの Docker volume なら問題ありません。NFS 上では SQLite データベースが破損し、SQLITE_BUSY と database disk image is malformed が発生するため、ネットワーク共有は使用しないでください。
初回起動: admin アカウントを作成する
https://status.example.com のプロキシ経由でインスタンスにアクセスするか、SSH トンネルを使用します。ssh -L 3001:127.0.0.1:3001 user@your-vps を実行して http://localhost:3001 を開きます。新規の v2 インストールでは、最初の画面で使用するデータベースを選択します。SQLite を選択してください。すべてのデータが /app/data ボリュームに保存され、以下のバックアップおよびトラブルシューティング手順もこれを前提としています。次に、管理者のユーザー名とパスワードを設定するフォームが表示されます。デフォルトのログイン情報はありません。実際に使用する強力なパスワードを設定してください。このダッシュボードには、監視対象のすべての内部アドレスとトークンが表示されます。後でパスワードを忘れた場合は、ブラウザーではなくホストからリセットします。
sudo docker compose exec uptime-kuma npm run reset-password通知チャネルを先に追加してテストする
モニターを追加する前にアラートを設定します。各モニターの作成時にチャネルを割り当てられます。Settings then Notifications then Setup Notification を開き、各チャネルの Test ボタンでメッセージが届くことを確認します。テストしていない通知は、設定が何も表示せずに失敗する原因として2番目に多いものです。
Email (SMTP)。 host、port、暗号化方式、username、password、From、To を入力します。一般的な組み合わせは、Secure を TLS/SSL に設定した 465、または STARTTLS を使用する 587 です。サーバーによっては 25 でも STARTTLS を利用できます。プロバイダーのドキュメントに記載された port とモードを使用してください。Gmail と、2要素認証を使用する多くのプロバイダーでは、app password を生成する必要があります。通常のアカウントパスワードを使用すると Error: Invalid login: 535-5.7.8 Username and Password not accepted が返されます。
Telegram。 @BotFather にメッセージを送り、/newbot を送信して、bot token をコピーします。chat ID を取得するには、新しい bot に一度メッセージを送り、https://api.telegram.org/bot<token>/getUpdates を開きます。JSON から chat.id を確認してください。先にメッセージを送っていない bot の getUpdates は空で、送信先もありません。
Discord。 チャネルで Edit Channel then Integrations then Webhooks then New Webhook を開き、URL をコピーして、Discord 通知として貼り付けます。
Generic webhook。 Slack incoming webhook、カスタムエンドポイント、ホームオートメーションの hook など、それ以外の用途には Webhook タイプを使用します。指定した URL に JSON payload を POST します。組み込みの Apprise 統合では、リストにある90前後のその他のサービスの大半を利用できます。障害発生時にサードパーティを介してスマートフォンへ通知したくない場合は、組み込みの ntfy タイプを選択し、自分で運用する ntfy サーバーを指定します。これにより、自分でエンドツーエンドに管理するチャネルを通じて handset に通知できます。
監視を追加する(種類ごとに設定)
Add New Monitor をクリックして種類を選び、Friendly Name、Check Interval(60 seconds が妥当です)、Retries(「down」と判定するまでの連続失敗回数。1 回のパケットロスで通知されないよう、2 または 3 にします)、通知条件を設定します。使用する種類は次のとおりです。
- HTTP(s). 完全な URL を指定します。200-299 がデフォルトの許容ステータスコードで、これを受け取ると稼働中と判定します。
301または401が正常な応答の場合は、Accepted Status Codes で範囲を広げます。Web サイトや API の基本的な監視に使用します。 - HTTP(s) - Keyword. 同じリクエストを実行しますが、本文に指定した文字列が存在することも「up」の条件になります。Invert を指定した場合は、文字列が存在しないことが条件です。単純な HTTP 監視では正常と判定される、
200 OKを返しながら「Error establishing a database connection」と表示するサイトも検出できます。また、Jellyfin 上で動作する Halcyon の動画ストア用スキンのように、別のバックエンドと通信するブラウザフロントエンドにも適しています。ページの外枠は200を正常に返していても、背後のメディアサーバーに到達できない場合を検出できます。 - TCP Port. HTTP 以外のサービスに対して、ホストとポートへの TCP 接続だけを確認します。22 の SSH、5432 の Postgres、25 の SMTP サーバー、ゲームサーバーなどに使用します。
- Ping. ICMP echo を使用して、到達性と遅延を低コストで確認します。ただし、多くのネットワークやクラウドファイアウォールは ICMP を破棄します。そのため、赤い ping 監視は「ホストが停止している」場合と「プロバイダーが ping をブロックしている」場合のどちらも示す可能性があります。TCP 監視で確認してください。
- DNS. 指定した resolver に対して A、AAAA、MX、TXT などのレコードを解決します。応答内容も検証できるため、レジストラや DNS の障害を早期に検出できます。
- Push. 内部から外部へ送信して確認する監視です。次で説明します。
プッシュ(ハートビート)モニターで cron ジョブを監視する
上記の各モニターは、外部からサービスにアクセスして確認します。プッシュモニターは逆です。Uptime Kuma が待機し、ジョブ自身が「実行した」と通知します。バックアップや cron を監視する方法として、これが唯一確実です。HTTP チェックで確認できるのは URL が応答することだけですが、ジョブの完了を知っているのはジョブ自身だけです。
タイプ Push のモニターを作成します。Uptime Kuma が次のような一意の URL を生成します。
https://status.example.com/api/push/j8Xa2Kd9Qe?status=up&msg=OK&ping=Heartbeat Interval を、ジョブの実行間隔に少し余裕を加えた値に設定します。次に、スクリプトの末尾へ 1 行追加します。これにより、成功時だけ通知されます。
#!/usr/bin/env bash
set -euo pipefail
# ... your backup or job runs here; set -e aborts on any failure ...
curl -fsS --retry 3 "https://status.example.com/api/push/j8Xa2Kd9Qe?status=up&msg=backup+ok&ping="ジョブが失敗すると、set -e が curl の前で終了するため、通知は実行されません。サーバーが停止している場合も、通知は実行されません。どちらの場合もハートビートが停止します。間隔にリトライ時間を加えた期間を過ぎると、Uptime Kuma はモニターを停止に変更し、通知します。このプッシュトークンは Secret として扱ってください。トークンを知っている人は、正常なハートビートを偽装できます。
公開ステータスページを作成する
ステータスページは、顧客向けの表示です。ダッシュボードを公開せずに、稼働中のサービスと直近の履歴を示します。Status Pages then New Status Page に移動し、名前と slug(/status/main のような公開パス)を指定します。使用する monitor を「Websites」や「APIs」などのグループにドラッグし、ロゴと短い説明を追加して、Save をクリックします。ページ専用のドメインに割り当てて、status.example.com から直接表示することもできます。
注意点は2つあります。ステータスページには、公開しても問題ない monitor だけを追加してください。サービスの存在と稼働状況が分かるためです。また、ダッシュボードはログインの背後に残りますが、ステータスページは意図的に公開され、認証は必要ありません。
TLS を使用するリバースプロキシの背後に配置し、WebSocket に注意する
公開インスタンスでは、loopback にバインドしたコンテナの前段にリバースプロキシを配置し、TLS とホスト名を設定します。特に注意が必要なのは、Uptime Kuma の UI がライブ Socket.IO アプリケーションであるため、プロキシで WebSocket 接続をアップグレードする必要があることです。 これを忘れるとページは読み込まれますが接続できません。ダッシュボードは「Connecting...」のままになり、ライブのハートビートも更新されず、ブラウザーのコンソールには WebSocket connection to 'wss://.../socket.io/...' failed が表示されます。
nginx と certbot をインストールし、loopback ポートへプロキシする vhost を作成します。まずはポート 80 で待ち受けさせ、後から certbot に TLS を追加させます。チャレンジ、更新タイマー、失敗時の動作については、certbot と nginx で Let's Encrypt 証明書を発行するで説明しています。
sudo apt install -y nginx certbot python3-certbot-nginxこれを /etc/nginx/sites-available/status.example.com として保存します。重要なのは2つの WebSocket 行です。
server {
listen 80;
server_name status.example.com;
location / {
proxy_pass http://127.0.0.1:3001;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 3600s;
}
}サイトを有効化して設定をテストし、その後 certbot にブロックを書き換えさせます。certbot は 443 での待ち受け、証明書の配置、HTTP から HTTPS へのリダイレクトを追加します。
sudo ln -s /etc/nginx/sites-available/status.example.com /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx
sudo certbot --nginx -d status.example.comUpgrade と Connection "upgrade" の組み合わせがすべての要点です。proxy_read_timeout 3600s により、nginx が長時間維持されるソケットを切断するのを防ぎます。certbot は、生成する 443 のブロックにもこの2つをコピーします。1つのプロキシの背後で複数のコンテナをすでに運用している場合は、自動 TLS を使用して Traefik 経由でルーティングすることで、コンテナラベルを使って同じ構成にでき、WebSocket のアップグレードもデフォルトで転送されます。
vhost 全体に Basic 認証を設定しないでください。これを設定すると、公開ステータスページと /api/push エンドポイントも利用できなくなります。Uptime Kuma の組み込みログインを使用し、インターネットからアクセス可能な場合は、繰り返し発生するログイン失敗を fail2ban で監視するを追加します。ダッシュボードを公開する必要がない場合は、プロキシを削除して SSH トンネル経由でアクセスします。または、VPN アドレスでポートを公開し、loopback ではなく VPN 経由でアクセスします。
証明書の有効期限監視を正しく設定する
HTTP(s) モニターでは、TLS 証明書の有効期限が切れる前に警告することもできます。Certificate Expiry Notification にチェックを入れると、Uptime Kuma が指定した日数前に警告します。誤検知につながる設定が 2 つあります。IP ではなくホスト名で監視してください。SNI を付けないリクエストでは、サーバーのデフォルト証明書が返され、Hostname/IP does not match certificate's altnames が表示されます。また、有効期限の警告が必要なモニターでは Ignore TLS/SSL Error にチェックを入れないでください。この設定は自己署名の内部ホスト向けです(unable to verify the first certificate、DEPTH_ZERO_SELF_SIGNED_CERT)。ただし、この設定を有効にすると、Uptime Kuma は有効期限を含め、証明書をまったく確認しなくなります。
バックアップ: ディレクトリは 1 つです
すべてが /app/data に保存されるため、バックアップはコンテナを停止した状態で取得したボリュームのコピーです。これにより、SQLite ファイルの整合性が保たれます。
cd /srv/uptime-kuma
sudo docker compose stop
sudo docker run --rm \
-v uptime-kuma_kuma-data:/data \
-v /var/backups/kuma:/backup \
alpine tar czf /backup/kuma-$(date -u +%Y%m%dT%H%M%SZ).tgz -C /data .
sudo docker compose startまず docker volume ls | grep kuma でボリュームの実際の名前を確認します。Compose はプロジェクトディレクトリ名を付加するためです。次に、tarball をサーバーの外部へコピーします。同じ VPS 上に保存したバックアップは、バックアップではなく単なるコピーだからです。復元は逆の手順です。スタックを停止し、空の /app/data ボリュームに展開してから、起動します。
アップグレード
アップグレードはイメージを pull するだけです。
cd /srv/uptime-kuma
sudo docker compose pull
sudo docker compose up -d新しいコンテナは初回起動時にデータベースのマイグレーションを実行します。docker compose logs -f を監視してください。pull の前に、上記のバックアップを必ず取得してください。また、メジャータグの範囲内にとどめます。:1 から :2 への移行ではデータベースがマイグレーションされます。プロジェクトのマイグレーションガイドでは、マイグレーションが中断された場合はバックアップから復元して再試行するよう説明されています。そのため、事前にバックアップを取得し、ガイドとリリースノートを確認してください。
障害パターンと表示される文字列
localhost を対象にした監視で誤って「停止」と判定される。 監視画面が timeout of 48000ms exceeded または connect ETIMEDOUT で赤くなっているのに、ノート PC からはサービスが応答します。Uptime Kuma と同じホストを対象にしている場合、対象サービスではなく、CPU またはメモリの急増によって監視処理が実行できなくなった可能性があります。監視を別の VPS に移し、公開ホスト名を対象にしてください。
connect ECONNREFUSED 127.0.0.1:443(または任意のポート)。そのポートで待ち受けているプロセスがありません。サービスが停止しているか、コンテナ内から localhost を監視しており、その環境では 127.0.0.1 がサーバーではなく コンテナ を指しています。ループバックではなく、公開ホスト名を監視してください。
Invalid login: 535-5.7.8 Username and Password not accepted がメールテストで表示される。SMTP 認証情報が誤っているか、プロバイダーがアプリ専用パスワードを要求しているのに、アカウントのパスワードを入力しています。アプリ専用パスワードを生成し、それを入力してください。
connect ETIMEDOUT または queryA ETIMEDOUT <host> がメールテストで表示される。ポートが誤っているか、プロバイダーが外向き SMTP 接続をブロックしています。Secure/STARTTLS の設定に対して 465 または 587 が一致していることを確認し、ホスト上で nc -vz smtp.example.com 587 を使ってテストしてください。多くのプロバイダーは外向きの 25 をブロックし、一部のプロバイダーは申請するまで submission ポートもブロックします。
self signed certificate または unable to verify the first certificate がメールテストで表示される。SMTP サーバーが、Node が信頼できない証明書を提示しています。設定で無理に回避するのではなく、メールサーバーの証明書を修正してください。
ダッシュボードが「Connecting...」で停止し、コンソールに WebSocket connection ... failed が表示される。 リバースプロキシが WebSocket のアップグレードを処理していません。nginx に Upgrade と Connection "upgrade" のヘッダーを追加するか、Traefik や Caddy のように標準でこれらを転送するプロキシを使用してください。HTML が読み込まれるのは、通常の HTTP GET だからです。アップグレードが必要なのはライブソケットだけです。
証明書有効期限の監視が警告しない、または誤って警告する。 Ignore TLS/SSL Error にチェックが入り、証明書の検証が無効になっている可能性があります。または、監視対象が IP アドレスで、SNI がないために誤った証明書を読み取り、Hostname/IP does not match certificate's altnames を表示している可能性があります。Ignore のチェックを外し、ホスト名で監視してください。
SQLITE_BUSY または database disk image is malformed がログに表示される。 /app/data ボリュームが、適切なファイルロックに対応していないファイルシステム上にあります。通常は NFS が原因です。ローカルの Docker ボリュームに移し、バックアップから復元してください。
FAQ
アップタイム監視はどこで実行すべきですか?
監視対象とは別のサーバー、理想的には別のプロバイダーやリージョンで実行し、ユーザーと同じようにパブリックインターネット経由でホスト名を使ってアクセスしてください。監視ツールが対象と同じサーバー上にあると、サーバーの停止時に監視ツールも停止してしまいます。また、ホストの負荷が高いと、サービスが正常でも「ダウン」と誤判定される可能性があります。小規模なVPSを別途用意することで、これらの問題を回避できます。
Telegramやメールで通知を受け取るにはどうすればよいですか?
Settings の Notifications から通知先を追加し、各監視項目に紐付けてください。Telegramの場合は @BotFather でボットを作成し、https://api.telegram.org/bot<token>/getUpdates から chat.id を取得します。メールの場合は、プロバイダーが二要素認証を採用しているなら、SSLには 465 を、STARTTLSには 587 を使用し、アプリパスワードを設定してください。運用を開始する前に Test を押し、メッセージが確実に届くことを確認してください。
Uptime Kumaでcronジョブやバックアップスクリプトを監視できますか?
はい、Push モニターを使用します。Uptime Kumaが発行するURLをスクリプトの末尾で curl することで、ジョブが成功した時のみハートビートが送信されます。ジョブが失敗したりサーバーがダウンしたりするとハートビートが届かないため、設定した間隔が経過した後に通知が送信されます。外部からのチェックでは内部の状態を把握できないため、スケジュールされたジョブが実際に実行されたかを確認する唯一の確実な方法です。
Uptime KumaとZabbixのどちらを使うべきですか?
Uptime Kumaは、「外部から見て稼働しているか、通知は届いたか」という問いに対して、ほぼリソースを消費せず10分で導入でき、ステータスページも提供します。CPU、メモリ、ディスクの推移や全社的な閾値監視といった詳細なメトリクス収集には向きません。そうした用途には、エージェントベースで高機能な Zabbix監視サーバー が適しており、両方を併用するケースも多くあります。何から導入すべきか迷っている場合は、2026年のセルフホスト推奨リスト を参考に、監視の全体像を確認してください。