Подробный гайд: Пошаговое руководство по созданию мониторинга 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 содержит чувствительную информацию. Никогда не открывайте его публично.
- Ограничьте доступ по 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. Тестирование
- Откройте
http://your-server/apache-dashboard.html - Откройте DevTools -> Network -> убедитесь, что
/server-status?autoвозвращает200 - Проверьте консоль на ошибки
- Сгенерируйте нагрузку:
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.
Мы делимся этой технической информацией, чтобы помочь вам в решении задач — используйте её с пониманием. Статья носит рекомендательный характер, поэтому, пожалуйста, применяйте описанные методы осмотрительно.