Docker и DevOps 11 мин чтения 2026-10-17

Автоматический мониторинг скорости интернета и канала VDS: развертывание Speedtest Tracker в Docker Compose с графиками пинга и алертами в Telegram

Практическое руководство по развертыванию Speedtest Tracker в Docker Compose на VDS: регулярный замер пропускной способности сети, графики пинга и джиттера, выбор эталонных серверов Ookla и алерты в Telegram.

Алексей Иванов Проверено инженерами SysKit.ru

При аренде виртуального сервера (VDS) хостинг-провайдеры указывают предельную пропускную способность сетевого интерфейса: обычно «до 100 Мбит/с» или «порт 1 Гбит/с». Однако физический сетевой адаптер гипервизора разделяется между десятками изолированных виртуальных машин. В часы пиковых нагрузок из-за эффекта «шумных соседей» (noisy neighbors) и перегрузки межоператорских стыков реальная скорость передачи данных может существенно снижаться, а задержка (RTT) и джиттер — возрастать, что напрямую отражается на времени отклика сайтов и скорости синхронизации бэкапов.

Разовый ручной запуск консольных тестов фиксирует лишь состояние канала в конкретную секунду. Для систематического контроля качества сетевого подключения необходим автономный инструмент мониторинга. Оптимальным выбором является Speedtest Tracker (разработчик Alex Justesen) — открытое self-hosted веб-приложение, использующее официальный бинарный движок Ookla Speedtest CLI, формирующее графики сетевых параметров и отправляющее алерты в Telegram при отклонении метрик от установленного соглашения об уровне обслуживания (SLA). Документация проекта доступна на docs.speedtest-tracker.dev.

1. Зачем VDS регулярный замер скорости и как провайдеры лукавят с SLA

В регламентах обслуживания большинства провайдеров пропускная способность заявляется по модели Best Effort («наилучшая возможная попытка»). На фактические показатели канала влияют объективные факторы:

  • Вечерняя деградация пиринга: в периоды пикового потребления трафика (19:00–23:00) магистральные каналы дата-центров испытывают повышенную нагрузку, из-за чего пропускная способность до удаленных автономных систем (AS) временно снижается.
  • Политики управления полосой (Traffic Shaping): на ряде тарифов при превышении установленных объемов суммарного трафика в месяц ширина канала программно ограничивается до базовых значений.
  • Асимметрия каналов: входящая скорость скачивания (Download) и исходящая скорость отдачи (Upload), критически важная для серверов веб-приложений и баз данных, могут заметно отличаться из-за конфигурации сетевых маршрутов провайдера.
  • Сетевой джиттер и потеря пакетов (Packet Loss): даже на широком канале потеря доли процента пакетов приводит к деградации алгоритмов контроля перегрузок TCP (BBR, Cubic), увеличивая время установления соединений.

Перед запуском тестов рекомендуется определить вышестоящую автономную систему (AS) и сетевой шлюз сервера с помощью инструментов Узнать мой IP-адрес онлайн и Проверка хостинга и дата-центра сайта.

💡 Совет инженера по объему тестового трафика

При замере скорости на порту 1 Гбит/с многопоточный синтетический тест Ookla за 15–20 секунд прокачивает в обе стороны порядка 1–2 ГБ сетевых данных. Запуск тестов каждые 10–15 минут создаст существенную фоновую нагрузку и израсходует до 3–5 ТБ трафика за месяц. Оптимальная периодичность замеров для VDS — каждые 4–6 часов (или контрольные замеры в ключевые периоды суток).

2. Архитектура Speedtest Tracker: движок на Laravel, связка с Ookla CLI и хранилище SQLite

Архитектура Speedtest Tracker (актуальная стабильная ветка v1.15.x) построена на модульном стеке компонентов:

  1. Официальный бинарный клиент Ookla Speedtest CLI: в отличие от сторонних библиотек на Python (таких как speedtest-cli), выполняющих замеры через HTTP-запросы в один поток и упирающихся в мощность одного ядра CPU уже на скоростях 200–300 Мбит/с, нативный бинарник Ookla поддерживает многопоточный сокетный обмен данными и вычисляет задержку под нагрузкой (Loaded Ping / Bufferbloat).
  2. Бэкенд на Laravel и Filament: интерфейс панели построен на базе Laravel и реактивного компонента Livewire, обновляющего метрики на дашборде через периодические асинхронные HTTP-запросы.
  3. Хранилище SQLite по умолчанию: метрики, журнал инцидентов и системные настройки сохраняются в локальном файле /config/database.sqlite. Для мониторинга отдельного сервера этого полностью достаточно: база не требует выделенного процесса СУБД и потребляет минимум оперативной памяти.
  4. Контейнеризация от LinuxServer.io: официальный образ linuxserver/speedtest-tracker поддерживает платформы x86-64 (amd64) и ARM64, управляется супервизором s6-overlay и поддерживает сопоставление прав пользователей через переменные PUID и PGID.
Инструмент тестирования Точность замера канала История и графики Потребление RAM Автоматизация и алерты
Speedtest Tracker (Ookla CLI) Высокая (официальный многопоточный сокетный алгоритм Ookla) Да (интерактивный веб-дашборд) ~100–180 МБ Telegram, Discord, Webhook, расписание cron
Python speedtest-cli Низкая (упирается в 1 поток CPU на 250+ Мбит/с, возможны искажения) Нет (только вывод в stdout) ~30 МБ (в момент теста) Требует самописных скриптов в bash/cron
iPerf3 Синтетическая (прямой TCP/UDP тест между узлами с iPerf3-сервером) Нет (консольные утилиты) ~15 МБ Требует наличия второго выделенного сервера iPerf

3. Развертывание Speedtest Tracker в Docker Compose на VDS

Для развертывания сервиса создадим выделенный каталог в файловой системе сервера (например, /opt/speedtest-tracker). Каталог для хранения конфигурации и базы данных SQLite должен принадлежать пользователю, под UID которого будет работать процесс внутри контейнера (обычно UID 1000).

# Создаем рабочую директорию проекта и каталог для данных
sudo mkdir -p /opt/speedtest-tracker/data
cd /opt/speedtest-tracker

# Назначаем права пользователя UID 1000 на каталог данных
sudo chown -R 1000:1000 /opt/speedtest-tracker/data

Перед составлением манифеста обязательно сгенерируем ключ шифрования приложения APP_KEY. Начиная с версии v0.20 и во всех последующих релизах v1.x проект отказался от неявной автоматической генерации ключа при старте: документация разработчика требует явно передавать сгенерированный 32-байтный base64-ключ в переменных окружения.

# Генерируем обязательный 32-байтный ключ шифрования в формате Laravel
echo "base64:$(openssl rand -base64 32)"

Скопируйте вывод команды (строку вида base64:AbCdEf12345...=) для подстановки в переменную APP_KEY.

Создадим конфигурационный манифест docker-compose.yml. Обратите особое внимание на директиву публикации портов: мы привязываем контейнер строго к локальному адресу 127.0.0.1:8080:80.

⚠️ Важное предупреждение по безопасности сетевых портов

Никогда не указывайте в ports строку "8080:80" или "80:80" без явного указания IP-адреса хоста! Из-за архитектурных особенностей подсистемы iptables Docker публикует порты напрямую через цепочку PREROUTING в обход стандартного фаервола UFW. Подробнее о механизме этой уязвимости и способах ее устранения читайте в нашем разборе Docker обходит UFW на Linux: закрытие внутренних портов контейнеров. Привязка к 127.0.0.1 гарантирует, что веб-панель будет доступна только через локальный обратный прокси.

Создадим файл docker-compose.yml со следующим содержимым:

services:
  speedtest-tracker:
    image: lscr.io/linuxserver/speedtest-tracker:latest
    container_name: speedtest-tracker
    restart: unless-stopped
    ports:
      # Привязываем порт строго к локальной петле loopback хоста
      - "127.0.0.1:8080:80"
    environment:
      - PUID=1000
      - PGID=1000
      - TZ=Europe/Moscow
      # Обязательный ключ шифрования (сгенерирован через openssl)
      - APP_KEY=base64:ВАШ_СГЕНЕРИРОВАННЫЙ_КЛЮЧ=
      - APP_URL=https://speedtest.example.com
      - DB_CONNECTION=sqlite
      # Рекомендуемое расписание (каждые 4 часа), по умолчанию переменная пустая
      - SPEEDTEST_SCHEDULE=0 */4 * * *
      # Автоматическое удаление замеров старше 90 дней для экономии места
      - PRUNE_RESULTS_OLDER_THAN=90
      - DISPLAY_TIMEZONE=Europe/Moscow
    volumes:
      - ./data:/config
    # Лимиты ресурсов: deploy.resources — спецификация Compose v2, mem_limit — fallback для Compose v1
    deploy:
      resources:
        limits:
          cpus: "1.50"
          memory: 512M
        reservations:
          memory: 128M
    mem_limit: 512m

Запускаем сервис в фоновом режиме и контролируем журнал первого старта:

# Запуск контейнера в фоне
docker compose up -d

# Просмотр логов инициализации и применения миграций SQLite
docker compose logs -f speedtest-tracker

При первом запуске скрипт инициализации применит структуру таблиц в SQLite и создаст стандартную учетную запись администратора согласно документации образа:

  • Логин (Email): admin@example.com
  • Пароль по умолчанию: password

💡 Совет инженера

Сразу после первого входа в веб-панель перейдите в профиль администратора (Settings → Profile) и немедленно смените стандартный пароль и адрес электронной почты на надежные. Для создания стойких паролей используйте инструмент Генератор сложных паролей онлайн.

4. Настройка расписания cron, выбор эталонных серверов и запуск первого теста

По умолчанию официальный клиент Ookla выбирает сервер тестирования динамически на основе наименьшей задержки (RTT). Однако в режиме долговременного мониторинга автоматический выбор узла снижает сопоставимость данных: в один запуск тест пойдет через сервер одного провайдера, в следующий — через другой узел с иной топологией каналов. На графиках появятся скачки, обусловленные не качеством вашего VDS, а спецификой конкретного удаленного хоста.

Для получения воспроизводимой исторической картины рекомендуется зафиксировать идентификаторы проверенных целевых серверов. Получить список доступных узлов можно официальной консольной командой приложения:

# Официальная artisan-команда Speedtest Tracker для вывода списка ближайших серверов
docker exec -it speedtest-tracker php artisan app:ookla-list-servers

Команда выведет список доступных серверов с их уникальными номерами (ID), наименованиями операторов связи и географическими локациями. Также прямой опрос узлов можно выполнить через низкоуровневый бинарник: docker exec -it speedtest-tracker speedtest --servers.

Выберите 2–3 стабильных узла ключевых магистральных операторов региона. В панели управления перейдите в подраздел Settings → Speedtest:

  • Speedtest Schedule: в официальном образе переменная SPEEDTEST_SCHEDULE изначально не заполнена (автоматические тесты отключены). Рекомендуется задать расписание в cron-формате, например 0 */4 * * * (запуск каждые 4 часа) или 0 3,9,15,21 * * *.
  • Speedtest Servers: укажите числовые идентификаторы выбранных узлов через запятую (например, 2113,3682). Сервис будет поочередно использовать именно эти фиксированные точки.
  • Thresholds (Пороговые значения SLA): настройте минимальные ожидаемые параметры пропускной способности. Например, для тарифа со скоростью 300–500 Мбит/с можно задать предупреждение при падении Download ниже 200 Мбит/с или росте пинга выше 40 мс.

Для проверки конфигурации нажмите кнопку «Queue Speedtest» в правом верхнем углу дашборда. Фоновый воркер запустит процесс замера, и в течение минуты в интерфейсе появятся графики скорости, джиттера и пинга под нагрузкой.

5. Требования к VDS для сетевого мониторинга и выбор надежного провайдера

Контейнер Speedtest Tracker в режиме ожидания потребляет всего 100–180 МБ оперативной памяти. Однако синтетический сетевой бенчмарк предъявляет специфические требования к аппаратным ресурсам ноды:

  • Производительность CPU на ядро: обработка многопоточного трафика на скорости около 1 Гбит/с создает кратковременную пиковую нагрузку на процессор. На старых процессорах с низкой базовой частотой узким местом может стать производительность виртуального ядра (CPU throttle), а не сам сетевой интерфейс. Для точных замеров предпочтительны современные процессоры с частотой от 3.0 ГГц.
  • Прозрачные условия тарификации трафика: важно заранее изучить условия договора хостинга — предоставляет ли провайдер честный нелимитированный канал или применяет ограничения после определенного порога переданных терабайт.
  • Дисковая подсистема NVMe: журналирование SQLite требует минимального времени отклика I/O, чтобы исключить задержки при параллельной записи результатов.

Для развертывания сетевых сервисов и стабильного мониторинга подходят проверенные облачные провайдеры с прозрачной сетевой инфраструктурой:

Рекомендуемые VDS-провайдеры

Отказоустойчивые сервера с быстрыми NVMe и каналом до 1 Гбит/с

Выбор редакции
⚡

Timeweb Cloud — Быстрые NVMe VDS

Высокочастотные процессоры 3.3+ ГГц для быстрой отдачи веб-страниц, NVMe-диски и надежный сетевой канал 1 Гбит/с.

Конфигурация
1 vCPU 3.3 ГГц • 1 ГБ RAM • 15 ГБ NVMe • Трафик без лимита
Премиум Tier III
🔷

Selectel — Надежные облачные серверы

Отказоустойчивая инфраструктура в сертифицированных дата-центрах Tier III, гарантированные ресурсы vCPU и удобное управление сетью.

Конфигурация
2 vCPU • 2 ГБ RAM • 30 ГБ NVMe • Дата-центры Tier III
Простота и стабильность
🟠

Beget — Простота для веб-разработчиков

Мгновенное развертывание Nginx и сайтов в 1 клик, интуитивная панель управления сервером, бесплатные автоматические бэкапы и отзывчивая поддержка 24/7.

Конфигурация
1 vCPU • 1 ГБ RAM • 15 ГБ NVMe • Бесплатные бэкапы

6. Настройка Telegram-бота для мгновенных алертов о деградации канала

Автоматический сбор метрик эффективен тогда, когда администратор получает мгновенное уведомление об инциденте без необходимости вручную проверять графики в браузере. Speedtest Tracker поддерживает отправку оповещений через почту, Discord, Webhook и мессенджер Telegram согласно официальному руководству по настройке уведомлений.

Для интеграции Telegram-оповещений выполните следующие шаги:

  1. Откройте бота @BotFather в Telegram и выполните команду /newbot. Задайте имя и юзернейм нового бота, после чего сохраните полученный токен доступа (HTTP API Token).
  2. Узнайте свой персональный ID пользователя или ID рабочей группы с помощью сервисного бота @userinfobot.
  3. В панели управления Speedtest Tracker откройте раздел Settings → Notifications.
  4. В блоке Telegram активируйте переключатель и укажите:
    • Bot Token: токен созданного бота;
    • Chat ID: ваш числовой идентификатор чата.
  5. В секции Notification Events выберите необходимые события:
    • Speedtest Completed — отправка отчета после каждого замера (лучше оставить отключенным при регулярном тестировании, чтобы избежать избыточных сообщений);
    • Speedtest Threshold Breached — рекомендуется включить (уведомление отправляется при падении скорости или скачке пинга ниже заданного порога SLA);
    • Speedtest Failed — рекомендуется включить (оповещение о сетевой аварии, когда тест не удалось выполнить из-за сбоя DNS или недоступности серверов).
  6. Нажмите кнопку «Test Notification» для отправки контрольного сообщения и проверки доставки.

7. Безопасная публикация через Nginx Reverse Proxy с авто-SSL и HTTP Basic Auth

Поскольку порт контейнера изолирован на локальном интерфейсе 127.0.0.1:8080, настроим обратный прокси Nginx на хосте с TLS-шифрованием Let's Encrypt и дополнительной базовой аутентификацией (HTTP Basic Auth).

Дашборд Speedtest Tracker построен на базе Laravel Filament и библиотеки Livewire, которая периодически опрашивает бэкенд через асинхронные HTTP-запросы. Чтобы веб-сервер стабильно поддерживал постоянные HTTP/1.1 соединения без разрывов при длительном выполнении теста, настроим стандартные прокси-заголовки.

Шаг 1: Создаем первичную HTTP-конфигурацию /etc/nginx/sites-available/speedtest.conf для валидации доменного имени:

server {
    listen 80;
    server_name speedtest.example.com;

    location / {
        proxy_pass http://127.0.0.1:8080;
        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;
    }
}

Активируем конфигурацию и проверяем корректность директив:

sudo ln -s /etc/nginx/sites-available/speedtest.conf /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx

Шаг 2: Выпускаем бесплатный TLS-сертификат Let's Encrypt с автоматическим перенаправлением на защищенный протокол HTTPS:

# Запуск certbot с плагином nginx и флагом принудительного редиректа
sudo certbot --nginx -d speedtest.example.com --redirect

Шаг 3: Создаем файл паролей для директивы auth_basic, чтобы полностью закрыть панель от автоматизированных сканеров и ботов:

# Устанавливаем apache2-utils при необходимости
sudo apt update && sudo apt install -y apache2-utils

# Создаем файл учетных записей для доступа к панели
sudo htpasswd -c /etc/nginx/.speedtest_htpasswd sysadmin

Итоговая боевая конфигурация виртуального хоста в /etc/nginx/sites-available/speedtest.conf с современным синтаксисом Nginx (директива http2 on;):

server {
    listen 80;
    server_name speedtest.example.com;
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl;
    http2 on;
    server_name speedtest.example.com;

    ssl_certificate /etc/letsencrypt/live/speedtest.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/speedtest.example.com/privkey.pem;
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers HIGH:!aNULL:!MD5;

    # Базовая HTTP-авторизация на уровне веб-сервера
    auth_basic "Speedtest Tracker Protected Area";
    auth_basic_user_file /etc/nginx/.speedtest_htpasswd;

    location / {
        proxy_pass http://127.0.0.1:8080;
        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;

        # Поддержка постоянных соединений HTTP/1.1 для Livewire
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";

        proxy_connect_timeout 60s;
        proxy_read_timeout 120s;
        proxy_send_timeout 120s;
    }
}

Применяем обновленные настройки:

sudo nginx -t && sudo systemctl reload nginx

Проверить корректность цепочки сертификатов и протоколов безопасности TLS можно с помощью инструмента Проверка SSL-сертификата онлайн. Для генерации других конфигураций Nginx с защитными заголовками воспользуйтесь нашим генератором Конфигуратор Nginx Reverse Proxy.

Также обязательно проверьте открытые порты сервера через Онлайн сканер портов, чтобы убедиться, что внутренний порт 8080 закрыт от внешнего мира, а доступны только стандартные порты 80 и 443.

8. Диагностика, ротация истории тестов и защита диска от переполнения

При регулярном мониторинге на протяжении нескольких месяцев база данных накапливает тысячи записей. Чтобы файл SQLite не разрастался неограниченно, в приложении предусмотрен механизм ротации.

💡 Автоматическая очистка устаревших замеров через Laravel Prunable

Модель результатов Result реализует стандартный трейт Illuminate\Database\Eloquent\Prunable. Встроенный планировщик задач Laravel автоматически выполняет команду model:prune раз в сутки, если переменная PRUNE_RESULTS_OLDER_THAN больше нуля (значение 0 отключает ротацию).

Для принудительного запуска очистки устаревших записей по настроенному порогу и создания резервной копии базы выполните:

# Ручной запуск штатной команды ротации Prunable-моделей в контейнере
docker exec -it speedtest-tracker php artisan model:prune

# Создание консистентного снапшота базы данных SQLite через встроенную утилиту
sqlite3 /opt/speedtest-tracker/data/database.sqlite ".backup '/opt/speedtest-tracker/data/backup_$(date +%F).sqlite'"

9. Чек-лист проверки и ввода в эксплуатацию

📋 Чек-лист готовности сетевого мониторинга

  • Сгенерирован и прописан обязательный ключ шифрования APP_KEY.
  • Порт контейнера привязан строго к петле 127.0.0.1:8080, прямой доступ из интернета заблокирован.
  • Стандартный пароль учетной записи admin@example.com заменен на надежный в профиле пользователя.
  • Серверы Ookla определены через php artisan app:ookla-list-servers и зафиксированы в конфигурации.
  • Настроены пороговые значения скорости и пинга (SLA Thresholds).
  • Telegram-бот проверен тестовым оповещением (Test Notification).
  • Настроен Nginx reverse proxy с HTTPS (http2 on;) и базовой аутентификацией auth_basic.

Готовы развернуть независимый сетевой мониторинг на своем VDS?

Выберите надежный облачный сервер с проверенным гигабитным портом, NVMe-накопителями и стабильным пирингом у ведущих провайдеров, чтобы контролировать качество связи круглосуточно.

Вопросы и ответы (FAQ)

Популярные вопросы вебмастеров и сисадминов по данной теме

Влияет ли частый запуск Speedtest на лимит сетевого трафика VDS?
Да. При тестировании гигабитного канала один полный цикл замера (Download + Upload) прокачивает от 1 до 2.5 ГБ сетевых данных. Если запускать тест каждые 15 минут, за месяц набежит более 4–6 ТБ служебного трафика. На тарифах с жестким помесячным лимитом это может привести к перерасходу или принудительному снижению скорости провайдером. Рекомендуемый интервал мониторинга — один замер каждые 3–6 часов.
Почему результаты замера в Docker-контейнере иногда ниже, чем при тестировании в браузере?
На замер скорости в контейнере влияют производительность CPU и сетевой драйвер. Браузерные тесты выполняются на мощных пользовательских ПК, тогда как Ookla CLI на VDS утилизирует виртуальные ядра сервера. При тестировании скорости 1 Гбит/с многопоточный сокетный обмен создает высокую нагрузку на CPU: если процессору не хватает частоты, тест упрется в процессорное время. Также убедитесь, что в Docker не используется userspace-прокси.
Как зафиксировать конкретный сервер Ookla и избежать тестирования через перегруженные узлы?
Выполните официальную artisan-команду docker exec -it speedtest-tracker php artisan app:ookla-list-servers внутри контейнера, чтобы получить список доступных узлов с их уникальными номерами ID. Выберите 2–3 стабильных сервера крупных операторов и пропишите их ID через запятую в веб-интерфейсе панели (Settings -> Speedtest -> Speedtest Servers). Это исключит случайные скачки результатов.
Безопасно ли оставлять веб-интерфейс Speedtest Tracker открытым в публичный интернет?
Оставлять открытым порт контейнера напрямую в интернет небезопасно. Рекомендуется привязать порт к 127.0.0.1:8080:80, проксировать запросы через внешний Nginx с обязательным шифрованием Let's Encrypt и настроить дополнительную базовую авторизацию auth_basic на уровне веб-сервера. Это закроет доступ ботам и сканерам уязвимостей.

Читайте также в блоге SysKit

Смежные руководства и полезные технические статьи