Универсальный подход для CMS и статических витрин · скрипт warm-cache.sh
#!/bin/bash
# Universal HTTP cache warmer (sitemap-driven).
# Usage:
# SITE=https://example.com ./warm-cache.sh
# nohup env SITE=https://example.com WAIT=1 ./warm-cache.sh >> warm.log 2>&1 &
#
# Optional: copy config.example.env to config.env and edit.
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
CONFIG_FILE="${CONFIG_FILE:-$SCRIPT_DIR/config.env}"
WORKDIR="${WORKDIR:-$SCRIPT_DIR/data}"
WAIT="${WAIT:-1}"
USER_AGENT="${USER_AGENT:-Mozilla/5.0 (compatible; CacheWarm/1.0; +https://example.com/bot)}"
WGET_TIMEOUT="${WGET_TIMEOUT:-90}"
SITEMAP_URL="${SITEMAP_URL:-}"
CONNECT_TIMEOUT="${CONNECT_TIMEOUT:-30}"
SITEMAP_MAX_TIME="${SITEMAP_MAX_TIME:-600}"
LOG_FILE="${LOG_FILE:-$SCRIPT_DIR/warm.log}"
if [[ -f "$CONFIG_FILE" ]]; then
# shellcheck source=/dev/null
source "$CONFIG_FILE"
fi
: "${SITE:?Set SITE=https://your-domain.tld or create config.env from config.example.env}"
SITE="${SITE%/}"
SITEMAP_URL="${SITEMAP_URL:-$SITE/sitemap.xml}"
mkdir -p "$WORKDIR"
cd "$WORKDIR"
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" | tee -a "$LOG_FILE"
}
extract_loc() {
grep -o '<loc>[^<]*' | sed 's/<loc>//'
}
collect_from_sitemap() {
local index_url="$1"
local tmp_index="$WORKDIR/sitemap_index.txt"
log "Fetch sitemap index: $index_url"
curl -fsS --connect-timeout "$CONNECT_TIMEOUT" --max-time 120 "$index_url" | extract_loc > "$tmp_index"
if [[ ! -s "$tmp_index" ]]; then
log "ERROR: empty sitemap index ($index_url)"
exit 1
fi
: > urls.txt
while IFS= read -r sm; do
[[ -z "$sm" ]] && continue
if [[ "$sm" == *.xml ]]; then
log " nested sitemap: $sm"
curl -fsS --connect-timeout "$CONNECT_TIMEOUT" --max-time "$SITEMAP_MAX_TIME" "$sm" | extract_loc >> urls.txt
else
echo "$sm" >> urls.txt
fi
done < "$tmp_index"
sort -u urls.txt -o urls.txt
}
warm_urls() {
local total
total=$(wc -l < urls.txt)
local eta_h
eta_h=$(awk -v n="$total" -v w="$WAIT" 'BEGIN{printf "%d", n*w/3600}')
log "URLs to warm: $total (~${eta_h}h at ${WAIT}s per request)"
log "Target: $SITE | UA: $USER_AGENT"
wget \
--input-file=urls.txt \
--no-cookies \
--delete-after \
--timeout="$WGET_TIMEOUT" \
--tries=2 \
--wait="$WAIT" \
--random-wait \
--user-agent="$USER_AGENT" \
--no-verbose \
2>&1 | while IFS= read -r line; do log "wget: $line"; done
}
main() {
log "=== cache warm start ==="
if [[ -s urls.txt ]]; then
log "Skip sitemap collect (urls.txt exists: $(wc -l < urls.txt) lines)"
else
log "Collect URLs from sitemap"
collect_from_sitemap "$SITEMAP_URL"
fi
if [[ ! -s urls.txt ]]; then
log "ERROR: urls.txt is empty"
exit 1
fi
log "Start wget warm"
warm_urls
log "=== cache warm done ==="
}
main "$@"
Зачем это нужно
Первый запрос к странице почти всегда самый медленный: сервер собирает HTML, ходит в БД, собирает шаблон. Повторные запросы отдаются из кэша — быстрее в разы.
Прогрев кэша — заранее обойти важные URL так, как это делает поисковый робот или гость без cookies. После прогрева:
- ниже время ответа сервера (TTFB);
- меньше пиковой нагрузки в часы трафика;
- спокойнее диагностика в Вебмастере и аналогах.
Как это работает
- Скачивается
sitemap.xml(или указанный вами индекс). - Из sitemap собирается список URL (поддерживаются вложенные sitemap-файлы).
wgetпо очереди запрашивает каждый URL с паузой, без cookies, без сохранения файлов на диск (--delete-after).
Скрипт не привязан к конкретной CMS: подойдёт для 1С-Битрикс (композит + memcached), WordPress, Laravel, OpenCart и любого сайта с публичным sitemap.
Где запускать
| Место | Плюсы | Минусы |
|---|---|---|
| На самом сервере | Быстро, не грузит канал, стабильная связь | Дополнительная нагрузка на CPU/RAM/диск |
| С другого VPS | Не нагружает диск целевого сервера | Нужен нормальный доступ к сайту; легко «положить» сайт без лимитов |
Рекомендуется запускать на сервере сайта в nohup и с паузой между запросами.
Быстрый старт
cd ~/cache-warm cp config.example.env config.env # отредактируйте SITE и WAIT в config.env chmod +x warm-cache.sh nohup ./warm-cache.sh >> warm.log 2>&1 & tail -f warm.log
Или без файла конфигурации:
SITE=https://example.com WAIT=1 nohup ./warm-cache.sh >> warm.log 2>&1 &
Параметры
| Переменная | По умолчанию | Описание |
|---|---|---|
SITE | — | Базовый URL сайта (обязательно) |
SITEMAP_URL | $SITE/sitemap.xml | URL корневого sitemap |
WAIT | 1 | Пауза между запросами (секунды, целое число) |
USER_AGENT | CacheWarm/1.0 | User-Agent для запросов |
WORKDIR | ./data | Каталог для urls.txt и служебных файлов |
Особенности по платформам
- 1С-Битрикс: включите композитный кэш и memcached; для прогрева используйте UA поискового бота,
--no-cookiesуже в скрипте. - WordPress: прогревайте после плагинов кэша (WP Super Cache, W3 Total Cache и т.д.); sitemap часто от Yoast/Rank Math.
- Любой фреймворк: убедитесь, что
/sitemap.xmlдоступен и не закрыт basic auth.
Безопасная нагрузка
- Не ставьте
WAIT=0на продакшене — параллельный шквал запросов забьёт PHP-FPM/Apache. - Для каталога на 100k+ URL при
WAIT=1прогрев займёт сутки и больше — это нормально. - Повторный запуск не качает sitemap заново, если уже есть
data/urls.txt. - Остановка:
pkill -f 'warm-cache.sh'илиpkill -f 'wget.*urls.txt'.
Проверка результата
wc -l ~/cache-warm/data/urls.txt tail -20 ~/cache-warm/warm.log curl -sI -H "User-Agent: YourBot" https://example.com/ | grep -i cache
В Битрикс: админка → Производительность → Композитный сайт — должны появляться записи о сгенерированных страницах.
Зависимости
На сервере нужны: bash, curl, wget, grep, sed, awk.
CentOS/RHEL: yum install -y curl wget · Debian/Ubuntu: apt install -y curl wget
