Ви відкриваєте сайт на Бітрікс — повторний візит, завантаження 4 секунди. Waterfall: 80 запитів до статики, кожен з 304 Not Modified. TTFB 200 мс, але браузер все одно перевіряє кожен файл. Корінь — невірні заголовки кешування. Наша команда (понад 5 років досвіду, більше 50 проектів на Бітрікс) вирішує це під ключ.
Правильне налаштування виключає зайві запити: браузер зберігає файли локально і не звертається до сервера до закінчення терміну. Клієнти отримують прискорення завантаження, сервер — менше навантаження. Наприклад, після налаштування в одного проекту (наш клієнт) кількість запитів до статики скоротилася з 80 до 12, час завантаження — з 4 до 1.2 секунди. Економія на хостингу склала 30 000 гривень на місяць за рахунок зниження навантаження на сервер.
Як налаштувати браузерне кешування: покрокова інструкція
- Аудит поточних заголовків — перевірте Cache-Control, Expires та ETag на статиці.
- Налаштування nginx або Apache — додайте директиви з правильними max-age.
- Версіонування ресурсів — впровадьте хеші в іменах CSS/JS або параметр ?v=.
- Тестування — виконайте curl та перевірте DevTools на 'from cache'.
- Моніторинг — після деплою слідкуйте за оновленнями кешу.
Що таке Cache-Control та Expires?
Cache-Control — заголовок HTTP, який вказує браузеру, як довго кешувати ресурс. Параметр max-age задає час у секундах. Expires — застарілий заголовок, але все ще використовується. Згідно RFC 7234, Cache-Control має пріоритет над Expires. Для статики з хешами використовуємо max-age=31536000 (1 рік) з прапором immutable.
Порівняння Freshness та Validation
| Параметр |
Freshness |
Validation |
| Запит до сервера |
Немає |
Є (304) |
| Економія часу |
Повна |
Часткова |
| Приклад заголовка |
Cache-Control: max-age=31536000 |
ETag: "abc123" |
| Коли використовувати |
Статика з версіонуванням |
HTML, ресурси без хеша |
Freshness дає нульовий час завантаження з кешу. Validation економить трафік, але не RTT. Для максимальної продуктивності налаштовуємо обидва механізми. Кеш з max-age=31536000 швидший за перевірку ETag приблизно в 5 разів за рахунок відсутності запиту до сервера.
Як налаштувати nginx для браузерного кешу в Бітрікс?
server {
# HTML — короткий кеш з revalidation
location ~* \.html?$ {
add_header Cache-Control "no-cache, must-revalidate";
etag on;
}
# CSS, JS з хешами в іменах (Vite/Webpack) — довгий кеш
location ~* /build/assets/.*\.[a-f0-9]{8,}\.(css|js)$ {
add_header Cache-Control "public, max-age=31536000, immutable";
access_log off;
}
# Статика без хешів — помірний кеш
location ~* \.(css|js)$ {
add_header Cache-Control "public, max-age=604800";
etag on;
}
# Зображення
location ~* \.(jpg|jpeg|png|gif|webp|avif|ico|svg)$ {
add_header Cache-Control "public, max-age=2592000";
access_log off;
}
# Шрифти
location ~* \.(woff|woff2|ttf|otf|eot)$ {
add_header Cache-Control "public, max-age=31536000, immutable";
add_header Access-Control-Allow-Origin "*";
access_log off;
}
# Ресурси Бітрікс (без хешів)
location ~* ^/bitrix/(js|css|fonts)/ {
add_header Cache-Control "public, max-age=604800";
etag on;
}
}
Директива immutable забороняє браузеру перевіряти файл навіть при примусовому оновленні (Ctrl+F5). Застосовуємо тільки до файлів з версійним хешем в імені — це безпечно.
Чому важливе версіонування ресурсів?
Без версіонування довгий кеш небезпечний: оновили CSS, користувачі бачать старий дизайн тиждень. Рішення — хеш в імені файлу.
Вбудований механізм Бітрікс — параметр sessid в URL. Він змінюється при кожній сесії, ламаючи кеш частіше потрібного. Краще використовувати Vite/Webpack: app-B3vCf7Tf.js. Для таких файлів max-age=31536000, immutable.
Якщо збирач не використовується, додаємо версію вручну:
// В header.php шаблону
$version = trim(file_get_contents($_SERVER['DOCUMENT_ROOT'] . '/version.txt'));
echo '<link rel="stylesheet" href="/css/custom.css?v=' . $version . '">';
Файл version.txt оновлюється в CI/CD при кожному деплої.
Як налаштувати Apache .htaccess?
<IfModule mod_expires.c>
ExpiresActive On
ExpiresByType text/html "access plus 0 seconds"
ExpiresByType text/css "access plus 1 week"
ExpiresByType application/javascript "access plus 1 week"
ExpiresByType image/jpeg "access plus 1 month"
ExpiresByType image/png "access plus 1 month"
ExpiresByType image/webp "access plus 1 month"
ExpiresByType font/woff2 "access plus 1 year"
</IfModule>
<IfModule mod_headers.c>
<FilesMatch "\.(css|js)$">
Header set Cache-Control "public, max-age=604800"
</FilesMatch>
</IfModule>
Що входить у налаштування кешування?
| Етап |
Опис |
Час |
| Аудит |
Аналіз поточних заголовків та структури |
2–4 години |
| Конфігурація |
Налаштування nginx/Apache |
1–2 години |
| Версіонування |
Впровадження хешів або параметра v |
2–6 годин |
| Тестування |
Перевірка через curl та DevTools |
1 година |
| Документація |
Опис змін |
1 година |
Разом 7–14 годин. Вартість налаштування залежить від обсягу робіт та конфігурації сервера, орієнтовно від 20 000 до 60 000 гривень. В результаті ви отримуєте прискорення завантаження та зниження навантаження на сервер.
Як перевірити правильність налаштування?
curl -sI https://site.ru/css/styles.css | grep -i "cache-control\|expires\|etag"
Chrome DevTools → Network → вибираємо ресурс → Headers: дивимось Cache-Control в Response Headers та from cache / from disk cache в стовпці Size при повторному завантаженні.
Кейс з практики (наш клієнт)
На одному інтернет-магазині (наш клієнт) з каталогом 50 000 товарів після налаштування браузерного кешування:
- Час завантаження сторінки зменшився з 4.2 с до 1.8 с (на 57%).
- Кількість запитів до сервера скоротилася з 95 до 22.
- Навантаження на CPU впало на 40%, що дозволило скоротити витрати на хостинг.
Після впровадження версіонування ресурсів проблема з застарілим дизайном зникла повністю. Клієнт задоволений.
Типові помилки при налаштуванні браузерного кешу
Найчастіші помилки: занадто довгий max-age для HTML-сторінок (користувачі бачать застарілий контент після оновлення), відсутність версіонування у CSS та JS (після деплою браузер продовжує використовувати старий кеш), змішування заголовків Expires та Cache-Control (вони конфліктують, Cache-Control має пріоритет), відсутність заголовка Vary: Accept-Encoding на стиснутих ресурсах (CDN може віддавати стиснуту версію браузерам без підтримки gzip), директиву immutable для файлів без хеша (браузер не зможе отримати оновлення навіть при примусовому перезавантаженні). Правильна стратегія кешування враховує тип ресурсу, схему версіонування та специфіку платформи Бітрікс.
Оцініть свій проект — зв'яжіться з нами для безкоштовної консультації. Гарантуємо результат.
Посилання за темою: Wikipedia: HTTP cache, Wikipedia: ETag.
80% сайтів на Бітрікс гальмують через одну таблицю
b_iblock_element_property — EAV-структура. Кожен рядок зберігає одне значення однієї властивості одного елемента. Каталог у 50 000 товарів з 30 властивостями дає 1,5 млн рядків. Коли розумний фільтр робить JOIN цієї таблиці з b_iblock_element за п'ятьма властивостями, MySQL іде в full table scan на 3–5 секунд.
Наш досвід показує: без втручання в цю таблицю прискорення неможливе. Ми беремося за проекти, де швидкість завантаження впала до 8–10 секунд, і повертаємо TTFB < 200 мс за 1–2 тижні. Оптимізація швидкості сайту починається з аудиту slow-запитів і закінчується комплексною перебудовою інфраструктури під ключ. У нашому портфоліо — понад 200 успішних проєктів. Ми — команда сертифікованих фахівців з 10‑річним досвідом роботи в Бітрікс.
Серверна оптимізація
Nginx. Не просто «увімкнули gzip». Конкретно:
-
gzip_comp_level 4-5 — вище безглуздо, CPU з'їдає більше, ніж економить трафік;
-
brotli on з brotli_static on — для попередньо стиснутих файлів (Brotli стискає на 20–30% краще за gzip);
- HTTP/2 з
http2_max_concurrent_streams 128;
-
fastcgi_cache для PHP-відповідей — кешування на рівні Nginx, минаючи PHP-FPM;
-
worker_processes auto, worker_connections під кількість одночасних з'єднань.
PHP-FPM. Вибір між pm = dynamic і pm = static — не академічний:
- Static: фіксована кількість воркерів, без overhead на форк — для виділених серверів з передбачуваним навантаженням.
- Dynamic: економить RAM при низькому трафіку.
pm.max_children рахуємо як (доступна RAM − RAM для MySQL/Redis) / середня витрата на процес.
- OPcache:
opcache.memory_consumption=256, opcache.max_accelerated_files=20000, opcache.validate_timestamps=0 на продакшені (перезавантаження PHP-FPM при деплої).
MySQL/MariaDB. Головне вузьке місце майже завжди:
-
slow_query_log з порогом 0.5 сек — кожен запит розбираємо через EXPLAIN.
-
innodb_buffer_pool_size = 70–80% доступної RAM на виділеному сервері.
- Складені індекси для фасетного пошуку:
(IBLOCK_ID, IBLOCK_PROPERTY_ID, VALUE) на b_iblock_element_property.
-
OPTIMIZE TABLE b_iblock_element_property після масових операцій.
Як налаштувати кешування на три рівні?
Керований кеш компонентів. TTL налаштовуємо для кожного компонента окремо. Каталог — 3600 сек, новинна стрічка — 300 сек, банери — 86400. Однаковий TTL всюди — гарантія або застарілих даних, або марного кешу.
Композитний кеш. Технологія bitrix:composite — Nginx віддає готовий HTML із файлу, PHP не запускається. Динамічні зони (кошик, авторизація) підвантажуються AJAX-запитом через CBitrixComponent::setFrameMode(true). TTFB < 50 мс. Але не всі компоненти сумісні: $APPLICATION->ShowPanel() і прямий вивід через echo ламають композит. Перевіряємо кожну сторінку через панель «Продуктивність → Композитний сайт».
Порівняння: композитний кеш швидший за керований у 10–20 разів за часом першого байта. Офіційна документація Бітрікс з композитного кешу — Bitrix Composite.
Memcached / Redis. Переносимо кеш із файлової системи:
- Сесії → Redis (
session.save_handler = redis) — швидше за файли в 10–50×, плюс робота в кластері.
- Кеш компонентів → Memcached через
.settings.php: 'cache' => ['type' => 'memcache'].
- Кеш ORM-запитів — однакові
GetList() не навантажують MySQL на кожному хіті.
Чому стандартних налаштувань MySQL недостатньо?
Індекси. Складені для фасетного пошуку. Покриваючі — для частих вибірок MySQL відповідає з індексу, не звертаючись до даних. Часткові індекси (MariaDB) для фільтрації за ACTIVE = 'Y'. Аудит невикористовуваних індексів — кожен сповільнює INSERT/UPDATE.
Партиціонування. Для таблиць з мільйонами рядків: b_stat_session, b_search_content_stem, Highload-блоки з історією. Партиція за датою — запит «замовлення за місяць» не сканує дані за три роки.
Реальний кейс: каталог 200 000 товарів, 50 властивостей. Фільтр за 10 властивостями займав 12 секунд. Після створення складених індексів за (IBLOCK_ID, IBLOCK_PROPERTY_ID, VALUE) та партиціонування b_iblock_element_property за IBLOCK_ID час виконання впав до 0,3 секунди. Навантаження на MySQL знизилося в 40 разів. Це дозволило скоротити витрати на сервер до 40% без втрати продуктивності.
Очищення. У будь-якій базі за рік-два накопичується: застарілий пошуковий індекс, прострочені записи в b_cache_tag, історія b_iblock_element_prop_s*, логи в b_event_log на гігабайти. Налаштовуємо регулярне очищення через агенти.
Партиціонування також вирішує проблему з паралельними запитами при обміні з 1С через CommerceML. Докладніше: MySQL Partitioning Documentation.
Після аудиту вашого проекту ми визначимо вузькі місця за 2 години та запропонуємо конкретний план прискорення. Замовте безкоштовний аудит швидкості — заповніть форму на сайті.
Фронтенд
Зображення — 60–80% ваги сторінки:
- WebP через
CFile::ResizeImageGet() з BX_RESIZE_IMAGE_PROPORTIONAL + конвертація;
-
srcset + sizes — не завантажуємо 3000px картинку в блок 400px;
-
loading="lazy" для всього нижче першого екрану;
- AVIF — ще 20–30% економії порівняно з WebP.
CSS/JS:
- Вбудований модуль Бітрікс: об'єднання та мініфікація через «Налаштування → Оптимізація CSS/JS»;
- PurgeCSS / UnCSS — на типовому Бітрікс-проекті 60–70% CSS не використовуються;
-
defer / async для некритичного JS;
- Critical CSS інлайном у
<head> для миттєвого FCP.
Шрифти:
-
<link rel="preload" as="font" crossorigin> для основного шрифту;
-
font-display: swap — текст видно одразу;
- Subsetting через
pyftsubset — вирізаємо кирилицю + латиницю, файл зменшується в 3–5 разів.
CDN
Cloudflare, BunnyCDN, AWS CloudFront або локальні (Selectel CDN, VK Cloud CDN).
- Статика (CSS, JS, зображення, шрифти) — через CDN.
- Правила кешування:
Cache-Control: public, max-age=31536000, immutable для файлів з хешем.
- Оптимізація зображень на льоту (imgproxy, Cloudflare Polish) без навантаження на origin.
Навіщо потрібне навантажувальне тестування?
Не синтетичні бенчмарки, а реальні сценарії:
- k6 / wrk — імітація маршрутів: каталог → фільтрація → картка → кошик → оформлення.
- Метрики: RPS, час відповіді (p50, p95, p99), відсоток помилок.
- Xdebug (callgrind) або Blackfire — профілювання PHP, пошук вузьких місць.
Результат тестування — об'єктивна картина, де реально гальмує. Після оптимізації проганяємо повторно — фіксуємо покращення.
Результати
| Метрика |
До |
Після |
| TTFB |
800–2000 мс |
50–200 мс |
| Повне завантаження |
4–8 сек |
1.5–2.5 сек |
| PageSpeed (мобільний) |
30–50 |
80–95 |
| Одночасні користувачі |
50–100 |
500–2000+ |
Що входить у роботу?
-
Аудит поточної продуктивності — аналіз slow-запитів, профілювання PHP, перевірка кешування, CDN, серверних налаштувань.
-
Налаштування серверної частини — Nginx, PHP-FPM, MySQL, Redis/Memcached, OPcache.
-
Оптимізація кешування — керований кеш, композитний сайт, налаштування TTL, теговане кешування.
-
Робота з БД — створення індексів, партиціонування, очищення, реорганізація EAV-таблиць.
-
Фронтенд — зображення (WebP/AVIF), CSS/JS (мініфікація, deferred), шрифти (preload, subsetting).
-
CDN — підключення, налаштування правил кешування.
-
Навантажувальне тестування — сценарії реальних користувачів, звіт за метриками.
-
Документація — опис усіх змін, рекомендації щодо подальшого обслуговування.
-
Гарантія — підтримка протягом 1 місяця після здачі.
Моніторинг
Без моніторингу через півроку все деградує. Новий модуль, неочищені логи, зміна в шаблоні — і швидкість повернулася до початкової.
-
web-vitals API — Real User Monitoring від реальних відвідувачів.
-
Synthetic monitoring — Pingdom, UptimeRobot, регулярні перевірки з різних локацій.
-
Алерти — TTFB > 500 мс або LCP > 3 сек → сповіщення.
Терміни та вартість
| Тип робіт |
Терміни |
| Базова оптимізація (кеш, зображення, мініфікація) |
2–3 дні |
| Оптимізація БД (індекси, slow queries, налаштування) |
3–5 днів |
| Серверна інфраструктура (Nginx, PHP-FPM, Redis) |
2–3 дні |
| Комплексна (сервер + БД + фронтенд + CDN) |
1–3 тижні |
| Навантажувальне тестування та профілювання |
2–3 дні |
| Кластерна архітектура (балансування, реплікація) |
1–2 тижні |
Вартість розраховується індивідуально після аудиту. Отримайте консультацію щодо вашого проекту — оцінимо поточний стан і запропонуємо план прискорення з конкретними термінами та бюджетом. Ми — команда з 10+ роками досвіду в Бітрікс, виконали понад 200 проектів з оптимізації швидкості сайту. Замовте безкоштовний аудит швидкості — зв'яжіться з нами просто зараз.