Подробный гайд: Пошаговое руководство по созданию мониторинга Apache2 на чистом HTML, JavaScript

Пошаговое руководство по созданию мониторинга Apache2 на чистом HTML и JavaScript. Получайте метрики сервера в реальном времени без сторонних сервисов.

2026.06.01                  


Подробный гайд: Пошаговое руководство по созданию мониторинга Apache2 на чистом HTML, JavaScriptПодробный гайд: Пошаговое руководство по созданию мониторинга Apache2 на чистом HTML, JavaScript

Важное уточнение:

Чистый HTML не умеет получать данные в реальном времени.

Поэтому мы используем:

  • Встроенный модуль Apache mod_status (отдаёт статистику сервера в машиночитаемом виде)
  • JavaScript fetch для получения данных и обновления HTML
  • Минимальный CSS для визуализации
  • Опционально: PHP-скрипт для метрик ОС (CPU, RAM, диск)

Всё будет работать на одном сервере без сторонних зависимостей.


Шаг 1. Включение mod_status в Apache

1. Откройте конфигурационный файл статуса:
   # Debian/Ubuntu
   sudo nano /etc/apache2/mods-enabled/status.conf
   # RHEL/CentOS/AlmaLinux
   sudo nano /etc/httpd/conf.d/status.conf

2. Приведите секцию к следующему виду:
   <Location "/server-status">
       SetHandler server-status
       Require ip 127.0.0.1 ::1
       # Раскомментируйте строку ниже, если нужен доступ с вашего IP в локальной сети:
       # Require ip 192.168.1.0/24
   </Location>
   ExtendedStatus On

3. Перезапустите Apache:
   sudo systemctl restart apache2   # или httpd

4. Проверьте работоспособность:
   curl http://localhost/server-status?auto

Вы должны увидеть список строк вида BusyWorkers: 3.


Шаг 2. Создаём дашборд (HTML + CSS + JS в одном файле)

Создайте файл /var/www/html/apache-dashboard.html:

<!DOCTYPE html>
<html lang="ru">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Apache2 Server Dashboard</title>
  <style>
    :root {
      --bg: #0f172a; --card: #1e293b; --text: #e2e8f0; --accent: #38bdf8;
      --success: #22c55e; --warn: #f59e0b; --danger: #ef4444;
    }
    * { box-sizing: border-box; margin: 0; padding: 0; }
    body { font-family: system-ui, -apple-system, sans-serif; background: var(--bg); color: var(--text); padding: 2rem; }
    h1 { text-align: center; margin-bottom: 2rem; font-weight: 600; }
    .grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 1rem; max-width: 1200px; margin: 0 auto; }
    .card { background: var(--card); border-radius: 12px; padding: 1.2rem; box-shadow: 0 4px 6px -1px rgba(0,0,0,0.3); }
    .card h3 { font-size: 0.85rem; text-transform: uppercase; letter-spacing: 0.05em; color: #94a3b8; margin-bottom: 0.5rem; }
    .value { font-size: 1.8rem; font-weight: 700; transition: color 0.3s; }
    .status-ok { color: var(--success); }
    .status-warn { color: var(--warn); }
    .status-err { color: var(--danger); }
    .loader { text-align: center; padding: 4rem; font-size: 1.1rem; color: #64748b; }
    .error { background: #3f1e1e; color: #fecaca; padding: 1rem; border-radius: 8px; margin: 1rem auto; max-width: 600px; display: none; }
    footer { text-align: center; margin-top: 3rem; color: #475569; font-size: 0.85rem; }
  </style>
</head>
<body>
  <h1>Apache2 Server Dashboard</h1>
  <div id="error" class="error"></div>
  <div id="loader" class="loader">Загрузка данных...</div>

  <div class="grid" id="dashboard" style="display:none;">
    <div class="card"><h3>Busy Workers</h3><div id="busy" class="value">-</div></div>
    <div class="card"><h3>Idle Workers</h3><div id="idle" class="value">-</div></div>
    <div class="card"><h3>Запросов/сек</h3><div id="rps" class="value">-</div></div>
    <div class="card"><h3>Трафик/сек</h3><div id="bps" class="value">-</div></div>
    <div class="card"><h3>Всего запросов</h3><div id="total" class="value">-</div></div>
    <div class="card"><h3>Uptime</h3><div id="uptime" class="value">-</div></div>
    <div class="card"><h3>CPU Load (Apache)</h3><div id="cpu" class="value">-</div></div>
    <div class="card"><h3>Активные соединения</h3><div id="conns" class="value">-</div></div>
  </div>

  <footer>Обновление каждые 5 сек | Данные: /server-status?auto</footer>

  <script>
    const API_URL = '/server-status?auto';
    const INTERVAL = 5000;
    let timer;

    function formatBytes(bytes) {
      if (bytes < 1024) return bytes + ' B';
      if (bytes < 1048576) return (bytes/1024).toFixed(1) + ' KB';
      return (bytes/1048576).toFixed(1) + ' MB';
    }

    function formatUptime(sec) {
      const d = Math.floor(sec / 86400);
      const h = Math.floor((sec % 86400) / 3600);
      const m = Math.floor((sec % 3600) / 60);
      return `${d}д ${h}ч ${m}м`;
    }

    async function fetchApacheStatus() {
      try {
        const res = await fetch(API_URL);
        if (!res.ok) throw new Error(`HTTP ${res.status}`);
        const text = await res.text();
        const data = {};
        text.split('\n').forEach(line => {
          const [key, ...val] = line.split(': ');
          if (key && val.length) data[key.trim()] = val.join(': ').trim();
        });

        document.getElementById('busy').textContent = data.BusyWorkers || '0';
        document.getElementById('idle').textContent = data.IdleWorkers || '0';
        document.getElementById('rps').textContent = (parseFloat(data.ReqPerSec) || 0).toFixed(2);
        document.getElementById('bps').textContent = formatBytes((parseFloat(data.BytesPerSec) || 0) * 1024);
        document.getElementById('total').textContent = new Intl.NumberFormat().format(data.TotalAccesses || 0);
        document.getElementById('uptime').textContent = formatUptime(parseInt(data.Uptime) || 0);
        document.getElementById('cpu').textContent = (parseFloat(data.CPULoad) || 0).toFixed(1) + '%';
        document.getElementById('conns').textContent = data.ConnsTotal || '0';

        // Цветовая индикация нагрузки
        const busy = parseInt(data.BusyWorkers) || 0;
        const busyEl = document.getElementById('busy');
        busyEl.className = 'value ' + (busy > 100 ? 'status-err' : busy > 50 ? 'status-warn' : 'status-ok');

        document.getElementById('loader').style.display = 'none';
        document.getElementById('dashboard').style.display = 'grid';
        document.getElementById('error').style.display = 'none';
      } catch (err) {
        document.getElementById('loader').style.display = 'none';
        const errEl = document.getElementById('error');
        errEl.textContent = `Ошибка получения данных: ${err.message}. Проверьте настройки mod_status.`;
        errEl.style.display = 'block';
        clearInterval(timer);
      }
    }

    document.addEventListener('DOMContentLoaded', () => {
      fetchApacheStatus();
      timer = setInterval(fetchApacheStatus, INTERVAL);
    });

    window.addEventListener('beforeunload', () => clearInterval(timer));
  </script>
</body>
</html>

Шаг 3. Настройка безопасности (обязательно)

/server-status содержит чувствительную информацию. Никогда не открывайте его публично.

  1. Ограничьте доступ по IP (уже сделано в конфиге выше). Укажите только ваш IP или подсеть.
2. Используйте HTTPS:
   sudo a2enmod ssl
   sudo certbot --apache -d ваш-домен.ru

3. Опционально: защита паролем:
   sudo htpasswd -c /etc/apache2/.htpasswd admin

Добавьте в <Location "/server-status">:
   AuthType Basic
   AuthName "Restricted"
   AuthUserFile /etc/apache2/.htpasswd
   Require valid-user
4. В продакшене отключите ExtendedStatus On, если не используете детальный мониторинг (экономит ~5% CPU).

Шаг 4. (Опционально) Метрики ОС: CPU, RAM, Диск

mod_status не отдаёт системные метрики.

Если нужен полный дашборд сервера, создайте лёгкий API на PHP:

Файл: /var/www/html/api/server-info.php

<?php
header('Content-Type: application/json');
$load = sys_getloadavg()[0];
$mem = shell_exec("free -m | awk '/Mem:/ {printf \"%.0f/%.0f\", $3, $2}'");
$disk = shell_exec("df -h / | awk 'NR==2 {printf \"%s/%s\", $3, $2}'");
echo json_encode(['cpu_load' => $load, 'mem' => $mem, 'disk' => $disk]);
?>

В JS добавьте:

// внутри fetchApacheStatus(), после получения данных Apache
fetch('/api/server-info.php')
  .then(r => r.json())
  .then(os => {
    // Добавьте соответствующие элементы в HTML с id="cpu-sys", id="mem", id="disk"
    document.getElementById('cpu-sys').textContent = os.cpu_load;
    document.getElementById('mem').textContent = os.mem;
    document.getElementById('disk').textContent = os.disk;
  });

Шаг 5. Тестирование

  1. Откройте http://your-server/apache-dashboard.html
  2. Откройте DevTools -> Network -> убедитесь, что /server-status?auto возвращает 200
  3. Проверьте консоль на ошибки
  4. Сгенерируйте нагрузку: ab -n 1000 -c 10 http://your-server/ и наблюдайте за изменением метрик в реальном времени

Что можно улучшить дальше

Функция Как реализовать
Графики истории Подключить Chart.js, сохранять данные в localStorage или лёгкую БД
Оповещения JS-уведомления при BusyWorkers > 80% или CPU Load > 4
Аутентификация .htaccess + AuthType Basic (см. выше)
Мобильная версия Уже адаптивно, можно добавить PWA manifest
Альтернатива Prometheus + Node Exporter + Grafana (промышленный стандарт)

Готово.

Дашборд работает без фреймворков, потребляет минимум ресурсов и полностью контролируется вами. Если нужно добавить конкретные метрики, настроить авторизацию или завернуть в Docker — напишите, подготовлю точные инструкции под вашу ОС и версию Apache.


Мы делимся этой технической информацией, чтобы помочь вам в решении задач — используйте её с пониманием. Статья носит рекомендательный характер, поэтому, пожалуйста, применяйте описанные методы осмотрительно.


Комментарии

Загрузка...
Если комментарии не загружаются, можете попробовать отключить блокировщик рекламы для этого сайта