Самостоятельный хостинг Uptime Kuma и Beszel на VPS с Docker Compose
Разверните Uptime Kuma для мониторинга внешней доступности и Beszel для метрик сервера на одном VPS. Настройка Docker Compose с уведомлениями, алертами, страницами статуса и усилением безопасности.
Приложение задеплоено. Пользователи регистрируются. Но ты понятия не имеешь, упадёт ли оно в 3 часа ночи или диск заполнится, пока ты спишь.
Это руководство разворачивает два инструмента мониторинга на одном VPS через Docker Compose:
- Uptime Kuma (84k+ звёзд на GitHub) мониторит внешнюю доступность: HTTP-эндпоинты, TCP-порты, DNS-записи, SSL-сертификаты.
- Beszel (~20k звёзд) мониторит внутреннее состояние сервера: CPU, RAM, диск, сеть и статистику Docker по контейнерам.
Вместе они потребляют около 150–180 МБ RAM. Стек Prometheus + Grafana + node_exporter для тех же задач требует 800+ МБ.
Предварительные требования: VPS на Debian 12 или Ubuntu 24.04 с установленными Docker и Docker Compose. Reverse proxy (Caddy или Nginx) для TLS. Доменное имя с DNS, направленным на сервер. В руководстве используется Caddy для примеров reverse proxy. Docker в продакшене на VPS: что ломается и как это починить
В чём разница между Uptime Kuma и Beszel?
Uptime Kuma мониторит внешнюю доступность. Он показывает, доступны ли твои сайты, API и сервисы извне. Beszel мониторит внутреннее состояние сервера: загрузку CPU, RAM, дисковое пространство, пропускную способность сети и статистику Docker по контейнерам. Веб-сервер может показывать низкую загрузку CPU и достаточно свободной памяти, но при этом быть полностью недоступным из-за некорректно настроенного файрвола или просроченного TLS-сертификата. Нужны оба инструмента.
| Функция | Uptime Kuma | Beszel |
|---|---|---|
| Что мониторит | HTTP, TCP, DNS, ping, истечение SSL, push/heartbeat | CPU, RAM, диск, сеть, температура, Docker-контейнеры |
| Архитектура | Один контейнер, веб-интерфейс | Hub + agent (один agent на каждый сервер) |
| База данных | SQLite (по умолчанию) или MariaDB | PocketBase (встроенный SQLite) |
| Каналы уведомлений | 90+ (email, Telegram, Discord, Slack, webhooks и др.) | Email (SMTP через PocketBase) |
| Страницы статуса | Да, публичные с пользовательским доменом | Нет |
| Потребление RAM | ~80–120 МБ | Hub: ~10–50 МБ, Agent: ~25 МБ |
| Звёзды GitHub | 84k+ | ~20k |
Ни один из инструментов не заменяет другой. Uptime Kuma ловит внешние сбои. Beszel обнаруживает исчерпание ресурсов до того, как оно вызовет внешние сбои.
Сколько RAM потребляет стек мониторинга?
Uptime Kuma v2.x использует примерно 80–120 МБ RAM в зависимости от количества мониторов. Hub Beszel добавляет 10–50 МБ, каждый agent использует около 25 МБ. Комбинированный стек спокойно работает на VPS с 1 ГБ RAM, потребляя около 150–180 МБ. Для сравнения, Prometheus + Grafana + node_exporter вместе требуют 800+ МБ только в простое.
| Стек | RAM в простое | Время настройки | Подходит для |
|---|---|---|---|
| Uptime Kuma + Beszel | ~150–180 МБ | 30 минут | Небольшие и средние self-hosted установки |
| Prometheus + Grafana + node_exporter | ~800 МБ+ | 2–4 часа | Крупная инфраструктура с кастомными запросами |
| Netdata | ~300–400 МБ | 15 минут | Метрики в реальном времени, один сервер |
Как установить Uptime Kuma через Docker Compose?
Uptime Kuma работает как один контейнер, отдавая веб-интерфейс на порту 3001. Compose-файл ниже фиксирует мажорный тег 2, привязывается только к localhost, задаёт лимиты ресурсов и добавляет health check.
Создай директорию проекта:
mkdir -p /opt/uptime-kuma && cd /opt/uptime-kuma
Создай Compose-файл:
# /opt/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:
- ./data:/app/data
environment:
- TZ=Europe/Berlin
deploy:
resources:
limits:
memory: 256m
cpus: "0.5"
healthcheck:
test: ["CMD", "node", "/app/extra/healthcheck.js"]
interval: 30s
timeout: 10s
retries: 3
start_period: 15s
Привязка 127.0.0.1:3001:3001 гарантирует, что контейнер слушает только на localhost. Без префикса 127.0.0.1 Docker публикует порт на всех интерфейсах, обходя файрвол. Docker обходит UFW: 4 проверенных решения для вашего VPS
Запусти контейнер:
docker compose up -d
[+] Running 1/1
✔ Container uptime-kuma Started
docker compose ps
NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS
uptime-kuma louislam/uptime-kuma:2 "/usr/bin/dumb-init …" uptime-kuma 10 seconds ago Up 9 seconds (healthy) 127.0.0.1:3001->3001/tcp
Статус (healthy) означает, что встроенный health check пройден. Если видишь (starting), подожди 15 секунд, пока завершится start_period.
Reverse proxy с Caddy
Добавь запись в Caddyfile:
# /etc/caddy/Caddyfile (append)
status.example.com {
reverse_proxy localhost:3001
}
Перезагрузи Caddy:
systemctl reload caddy
Caddy автоматически получит TLS-сертификат от Let's Encrypt. Открой https://status.example.com в браузере. Uptime Kuma предложит создать учётную запись администратора при первом входе.
Включи 2FA сразу
После создания учётной записи администратора перейди в Settings > Security > Two-Factor Authentication и включи. Дашборд Uptime Kuma даёт доступ на чтение ко всей топологии инфраструктуры. Любой, кто скомпрометирует логин, увидит каждый отслеживаемый эндпоинт. Настрой 2FA до добавления мониторов.
Как настроить Beszel для мониторинга VPS?
Beszel использует архитектуру hub-agent. Hub — это веб-дашборд, который хранит данные и отображает метрики. Agent запускается на каждом сервере, который нужно мониторить, и передаёт метрики в hub. Когда оба работают на одном VPS, они общаются через Unix-сокет, а не по сети.
Создай директорию проекта:
mkdir -p /opt/beszel && cd /opt/beszel
Создай Compose-файл:
# /opt/beszel/compose.yaml
services:
beszel-hub:
image: henrygd/beszel:0.18
container_name: beszel-hub
restart: unless-stopped
ports:
- "127.0.0.1:8090:8090"
environment:
- APP_URL=https://beszel.example.com
volumes:
- ./beszel_data:/beszel_data
- ./beszel_socket:/beszel_socket
deploy:
resources:
limits:
memory: 128m
cpus: "0.25"
beszel-agent:
image: henrygd/beszel-agent:0.18
container_name: beszel-agent
restart: unless-stopped
network_mode: host
volumes:
- ./beszel_agent_data:/var/lib/beszel-agent
- ./beszel_socket:/beszel_socket
- /var/run/docker.sock:/var/run/docker.sock:ro
environment:
- LISTEN=/beszel_socket/beszel.sock
- KEY=${BESZEL_KEY}
deploy:
resources:
limits:
memory: 64m
cpus: "0.15"
Об этой конфигурации:
- Образ hub зафиксирован на
0.18, который включает исправление CVE-2026-27734 (v0.18.4). Фиксация на минорную версию предотвращает неожиданные ломающие изменения, но позволяет получать патчи. - Agent использует
network_mode: hostдля чтения статистики сетевых интерфейсов хоста. Это необходимо для точного мониторинга пропускной способности. - Agent и hub делят том
beszel_socketдля коммуникации через Unix-сокет. Это избавляет от необходимости открывать порт 45876 в сети, когда оба работают на одном сервере. - Docker-сокет монтируется в режиме только для чтения (
:ro). Подробнее — в разделе безопасности ниже.
Безопасность Docker-сокета
Монтирование /var/run/docker.sock даёт agent'у доступ к Docker API. Даже с :ro это фактически root-доступ, потому что Docker API может создавать привилегированные контейнеры, читать переменные окружения любого контейнера и получать доступ к томам. Усиление безопасности Docker: Rootless-режим, Seccomp, AppArmor на VPS
Beszel нужен сокет для сбора статистики CPU, памяти и сети по контейнерам. Если мониторинг контейнеров не нужен, полностью убери монтирование Docker-сокета.
CVE-2026-27734 (исправлена в v0.18.4) продемонстрировала этот риск: аутентифицированный пользователь Beszel мог обходить Docker API через несанитизированные ID контейнеров, добираясь до произвольных эндпоинтов вроде /version или /containers/json. Исправление санитизирует все пользовательские входные данные перед построением URL Docker API. Убедись, что используешь v0.18.4 или новее. Тег 0.18 в Compose-файле выше резолвится в v0.18.4 (последний патч на март 2026).
Генерация ключа agent'а
Сначала запусти hub:
cd /opt/beszel
docker compose up -d beszel-hub
Открой hub по адресу https://beszel.example.com (после настройки reverse proxy, следующий раздел). Создай учётную запись администратора. Перейди в Add System в дашборде. Hub покажет публичный ключ. Скопируй его.
Создай .env файл для agent'а:
# /opt/beszel/.env
BESZEL_KEY="ssh-ed25519 AAAA... (paste the key from the hub UI)"
chmod 600 /opt/beszel/.env
Теперь запусти agent:
docker compose up -d beszel-agent
В интерфейсе hub добавь систему, указав путь к сокету /beszel_socket/beszel.sock. Через несколько секунд появятся метрики CPU, RAM, диска и Docker-контейнеров.
Reverse proxy для Beszel
Добавь в Caddyfile:
# /etc/caddy/Caddyfile (append)
beszel.example.com {
reverse_proxy localhost:8090
}
systemctl reload caddy
Как настроить уведомления в Uptime Kuma?
Uptime Kuma поддерживает более 90 каналов уведомлений. Три самых популярных для self-hosted установок — email (SMTP), Telegram и Discord.
SMTP email-уведомления
Перейди в Settings > Notifications > Setup Notification. Выбери Email (SMTP) как тип.
| Поле | Значение |
|---|---|
| Hostname | Твой SMTP-сервер (например, smtp.example.com) |
| Port | 587 (STARTTLS) или 465 (имплицитный TLS) |
| Security | STARTTLS или TLS |
| Username | Имя пользователя SMTP |
| Password | Пароль SMTP |
| From Email | monitoring@example.com |
| To Email | you@example.com |
Нажми Test для отправки тестового уведомления перед сохранением. Uptime Kuma отправит тест немедленно. Если не получилось, проверь учётные данные SMTP и правила файрвола (исходящий порт 587 должен быть открыт).
Уведомления через Telegram-бота
- Напиши @BotFather в Telegram и создай нового бота командой
/newbot. - Скопируй токен бота (формат:
123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11). - Начни чат со своим ботом и отправь любое сообщение.
- Получи chat ID: открой
https://api.telegram.org/bot<YOUR_TOKEN>/getUpdatesв браузере. Полеchat.idв ответе — это твой chat ID. - В Uptime Kuma добавь уведомление Telegram. Вставь токен бота и chat ID. Нажми Test.
Уведомления через Discord webhook
- В своём Discord-сервере перейди в Server Settings > Integrations > Webhooks > New Webhook.
- Назови его (например, «Uptime Kuma»), выбери канал и скопируй URL вебхука.
- В Uptime Kuma добавь уведомление Discord и вставь URL вебхука. Нажми Test.
Установи уведомление по умолчанию для всех новых мониторов, отметив Default Enabled. Так каждый создаваемый монитор унаследует канал уведомлений без ручной настройки.
Какие типы мониторов Uptime Kuma настроить?
Uptime Kuma поддерживает множество типов мониторов. Вот четыре самых полезных для self-hosted стека:
- HTTP(s) — проверяет URL, опционально ищет ключевое слово в теле ответа. Используй для веб-приложений, API и дашбордов. Задай ключевое слово — строку, которая появляется только когда приложение работает (например, имя приложения в HTML-заголовке).
- TCP — подключается к хост:порт. Используй для баз данных (PostgreSQL на 5432), почтовых серверов (SMTP на 587) или любого сервиса без HTTP-эндпоинта.
- DNS — резолвит имя хоста и проверяет, совпадает ли результат с ожидаемым IP. Обнаруживает DNS-перехват или ошибки в записях.
- Push / Heartbeat — Uptime Kuma генерирует URL. Твой cron-таск или скрипт бэкапа вызывает его при успехе. Если URL не вызван в течение интервала, Uptime Kuma поднимает алерт. Это единственный способ мониторить скрипты без слушающего порта.
Пример Push-монитора для cron-задач
Создай Push-монитор в Uptime Kuma. Установи интервал heartbeat равным частоте cron плюс льготный период. Скопируй push URL.
Добавь вызов curl в конец скрипта бэкапа:
#!/bin/bash
# /opt/scripts/backup.sh
pg_dump mydb | gzip > /backups/mydb-$(date +%F).sql.gz
# Signal success to Uptime Kuma
curl -fsS -o /dev/null "https://status.example.com/api/push/abc123?status=up&msg=backup-ok"
Если скрипт упадёт до строки curl, или cron не запустится, Uptime Kuma пометит монитор как down после истечения интервала.
Как настроить алерты Beszel для CPU и диска?
Алерты Beszel уведомляют, когда метрики сервера превышают порог. Нажми на значок колокольчика рядом с системой в дашборде для настройки алертов.
Рекомендуемые пороги для небольшого VPS (2–4 vCPU, 4–8 ГБ RAM):
| Метрика | Предупреждение | Критический | Почему |
|---|---|---|---|
| CPU | > 70% в течение 5 мин | > 90% в течение 2 мин | Устойчивая высокая загрузка CPU означает зависшие процессы или недостаточный размер инстанса |
| RAM | > 80% в течение 5 мин | > 90% в течение 2 мин | Linux начинает активно свопить выше 85%, убивая производительность |
| Диск | > 80% | > 90% | Docker-образы, логи и базы данных растут незаметно. При 100% сервисы падают |
| Полоса пропускания | > 80% лимита тарифа | > 95% | Предотвращает дополнительные расходы или троттлинг |
Эти пороги намеренно ниже корпоративных стандартов. На небольшом VPS запас меньше. Скачок с 70% до 100% CPU занимает секунды, а не минуты.
Настройка SMTP для алертов Beszel
Beszel использует PocketBase как бэкенд. SMTP настраивается через панель администрирования PocketBase:
- Перейди на
https://beszel.example.com/_/(URL администрирования PocketBase, обрати внимание на подчёркивание). - Войди с учётными данными администратора, созданными при установке.
- Перейди в Settings > Mail settings.
- Включи Use SMTP mail server.
- Введи SMTP-хост, порт, имя пользователя и пароль.
- Укажи адрес отправителя.
- Нажми Save и Send test email.
Как создать публичную страницу статуса в Uptime Kuma?
Uptime Kuma может отдавать публичные страницы статуса, показывающие доступность сервисов. Они полезны для информирования пользователей о работоспособности без раскрытия дашборда мониторинга.
- Перейди в Status Pages в левой боковой панели.
- Нажми New Status Page. Выбери имя и slug (например,
status). - Добавь группы (например, «Веб-сервисы», «API», «Инфраструктура»).
- Перетащи мониторы в каждую группу.
- Опубликуй страницу. Она доступна по адресу
https://status.example.com/status/<slug>.
Кастомный домен для страницы статуса
Если хочешь, чтобы https://status.example.com показывал страницу статуса напрямую, установи её как страницу по умолчанию в настройках Uptime Kuma. Корневой путь тогда показывает публичную страницу, а дашборд остаётся на /dashboard.
Страницы статуса не требуют аутентификации. Не добавляй мониторы в группу страницы статуса, если раскрытие существования эндпоинта является проблемой безопасности.
Управление инцидентами
Когда сервис падает, Uptime Kuma автоматически показывает его как деградированный на странице статуса. Можно также создавать инциденты вручную:
- Перейди в Status Pages, выбери свою страницу, нажми Create Incident.
- Напиши заголовок и описание (например, «Обслуживание базы данных, ориентировочно 15 минут»).
- Установи стиль на info, warning, danger или primary.
- Опубликуй. Баннер инцидента появится вверху публичной страницы статуса.
Разреши инцидент по завершении. Uptime Kuma хранит историю прошлых инцидентов, чтобы пользователи могли видеть операционную историю.
Как мониторить свой стек мониторинга снаружи?
Если VPS упадёт, Uptime Kuma и Beszel упадут вместе с ним. Ты узнаешь о сбое одновременно с пользователями. Решение: внешний watchdog, который мониторит инстанс Uptime Kuma с другой локации.
Вариант 1: UptimeRobot (бесплатный тариф)
- Создай бесплатный аккаунт на UptimeRobot.
- Добавь новый монитор: тип HTTP(s), URL
https://status.example.com/api/status-page/heartbeat/<slug>. - Установи интервал проверки 5 минут.
- Настрой уведомления через email или Telegram.
Эндпоинт /api/status-page/heartbeat/<slug> возвращает JSON со статусом. UptimeRobot проверяет его и алертит, если инстанс Uptime Kuma станет недоступен.
Вариант 2: Healthchecks.io (бесплатный тариф)
Healthchecks.io работает по модели push. Создай check, скопируй URL пинга и добавь cron-задачу на VPS:
# /etc/cron.d/monitoring-heartbeat
*/5 * * * * root curl -fsS --retry 3 -o /dev/null https://hc-ping.com/your-uuid-here
Если cron-пинг перестанет приходить (потому что сервер лежит), Healthchecks.io отправит алерт. Это покрывает сценарий, когда весь VPS становится недоступным.
Вариант 3: мониторить со второго VPS
Если у тебя несколько серверов, установи Uptime Kuma на другом VPS и пусть каждый инстанс мониторит другой. Это самый надёжный подход, потому что ты контролируешь оба эндпоинта и нет зависимости от бесплатного сервиса третьей стороны.
Усиление безопасности
Правила файрвола
Если запускаешь agent Beszel в standalone-режиме на удалённом сервере (без метода Unix-сокета), он слушает на порту 45876. Только hub должен иметь доступ к этому порту:
ufw allow from <hub-ip-address> to any port 45876 proto tcp comment "Beszel agent"
ufw status numbered
Status: active
To Action From
-- ------ ----
[ 1] 22/tcp ALLOW IN Anywhere
[ 2] 80/tcp ALLOW IN Anywhere
[ 3] 443/tcp ALLOW IN Anywhere
[ 4] 45876/tcp ALLOW IN <hub-ip-address>
Не открывай порт 45876 для всего мира. Agent отдаёт системные метрики без аутентификации на этом порту. Он полагается на SSH-ключ hub'а для верификации, но ограничение на сетевом уровне добавляет эшелонированную защиту.
Для настройки с одним VPS из этого руководства порт 45876 вообще не нужен, потому что hub и agent общаются через Unix-сокет.
Uptime Kuma: отключение парольной аутентификации для API
Если обращаешься к Uptime Kuma только через веб-интерфейс, отключи доступ к API через Settings > Security > API Key. Меньше открытых эндпоинтов — меньше надо патчить.
Скрытие версий
Uptime Kuma и Beszel по умолчанию показывают информацию о версии в своём веб-интерфейсе. Reverse proxy не должен усугублять ситуацию. В Caddyfile Caddy уже по умолчанию не отправляет заголовки Server. Если используешь Nginx:
server_tokens off;
Раскрытие версий помогает атакующим целиться в известные уязвимости. Держи информацию минимальной.
Как бэкапить данные Uptime Kuma и Beszel?
Оба инструмента используют базы данных на основе SQLite. Файлы SQLite нельзя безопасно копировать во время записи. Используй правильные методы бэкапа.
Бэкап Uptime Kuma
Uptime Kuma хранит всё в /app/data (примонтировано как ./data в Compose-файле). Встроенный бэкап экспортирует JSON-файл:
- Перейди в Settings > Backup.
- Нажми Export. Сохрани JSON-файл за пределами сервера.
Для автоматических бэкапов ненадолго останови контейнер или используй онлайн-бэкап SQLite:
sqlite3 /opt/uptime-kuma/data/kuma.db ".backup '/opt/backups/kuma-$(date +%F).db'"
Бэкап Beszel
Beszel использует PocketBase. Сделай бэкап директории данных:
sqlite3 /opt/beszel/beszel_data/data.db ".backup '/opt/backups/beszel-$(date +%F).db'"
Храни бэкапы за пределами сервера. Стек мониторинга, который теряет историю при отказе диска, ничего не мониторит. Резервное копирование и восстановление томов Docker на VPS
Как безопасно обновить Uptime Kuma и Beszel?
Фиксируй минорную версию, не latest. Это предотвращает ломающие изменения без твоего ведома.
# Update Uptime Kuma
cd /opt/uptime-kuma
docker compose pull
docker compose up -d
[+] Pulling 1/1
✔ uptime-kuma Pulled
[+] Running 1/1
✔ Container uptime-kuma Started
docker compose ps
Проверь, что столбец STATUS показывает (healthy). Если новая версия вызывает проблемы, зафиксируй предыдущую версию в compose.yaml и пересоздай:
# In compose.yaml, change the image tag to the previous version:
# image: louislam/uptime-kuma:2.2.1
docker compose up -d
Тот же процесс применяется к Beszel. Всегда делай бэкап перед обновлением.
Стратегия фиксации образов
Тег louislam/uptime-kuma:2 следит за последним релизом 2.x. Это удобно, но означает, что docker compose pull может перескочить с 2.2.1 на 2.3.0 без предупреждения. Для продакшна фиксируй конкретную минорную версию:
image: louislam/uptime-kuma:2.2
Проверяй release notes перед pull'ом. Uptime Kuma публикует релизы на GitHub. Beszel делает то же на своей странице релизов.
Подпишись на уведомления о релизах обоих репозиториев (Watch > Custom > Releases на GitHub), чтобы знать, когда выходят патчи безопасности.
Лимиты ресурсов, healthcheck-проверки и политики перезапуска в Docker Compose
Устранение неполадок
Uptime Kuma показывает (unhealthy) в docker compose ps:
docker compose logs uptime-kuma --tail 50
Частые причины: повреждённая база SQLite (восстанови из бэкапа), конфликт портов (другой сервис на 3001) или нехватка памяти (увеличь лимит ресурсов).
Agent Beszel не подключается к hub:
docker compose logs beszel-agent --tail 50
Проверь, что KEY в .env совпадает с ключом, показанным в диалоге Add System hub'а. Если используешь Unix-сокеты, убедись, что путь общего тома совпадает на обоих сервисах.
Beszel не показывает статистику Docker-контейнеров:
Не примонтирован Docker-сокет или неверный путь к нему. Проверь:
ls -la /var/run/docker.sock
srw-rw---- 1 root docker 0 Mar 20 10:00 /var/run/docker.sock
Сокет должен существовать, и контейнер должен иметь доступ на чтение. Монтирование :ro в Compose-файле обеспечивает это.
Уведомления не приходят:
Для SMTP: проверь, не блокирует ли хостинг-провайдер исходящий порт 587 (или 465). Некоторые провайдеры блокируют исходящий SMTP по умолчанию. Проверь:
nc -zv smtp.example.com 587
Connection to smtp.example.com 587 port [tcp/submission] succeeded!
Для Telegram: проверь токен бота и chat ID. Chat ID должен быть числом, а не именем пользователя бота.
Высокое потребление памяти:
Количество мониторов имеет значение. Uptime Kuma v2.x потребляет около 100 МБ в простое. Каждый HTTP-монитор добавляет состояние соединения. Если при лимите 256 МБ мониторов больше 100, увеличь лимит или распредели между инстансами.
Проверь фактическое потребление:
docker stats --no-stream uptime-kuma beszel-hub beszel-agent
CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
abc123 uptime-kuma 0.15% 99MiB / 256MiB 38.67% 1.2kB / 2kB 0B / 0B 8
def456 beszel-hub 0.08% 10MiB / 128MiB 7.81% 1kB / 1.5kB 0B / 745kB 8
ghi789 beszel-agent 0.05% 22MiB / 64MiB 34.38% 0B / 0B 0B / 0B 5
Готовы попробовать?
Разверните стек мониторинга на VPS от Virtua Cloud. →