Как быстро восстановить сайты, если нет бэкапов

от автора

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

Пришлось в авральном режиме поднимать хотя бы HTML-версию. Рассказываю, как вытащить сайт из веб-архивов, когда копий нет нигде, — и за несколько часов вернуть его в строй.

Предыстория

Есть ощущение, что как в фильме «Пункт назначения», судьба методично создает цепочку событий, готовя капкан, из которого не выбраться. 

Сразу оговорюсь: инфраструктура, на которой работали сайты, мне не принадлежала — я лишь арендовал серверы. Что-то в этой схеме меня смущало с самого начала: слишком многое зависело от факторов, на которые я не мог повлиять. Как оказалось, не напрасно.

Бэкапы хранились в трех местах: на рабочем компьютере, на домашнем компьютере и в облачном хранилище, которым пользуется работодатель. Примерно за месяц до отключения сайтов на облачном хранилище кончилось место. Оплачивать дополнительное пространство не было возможности из-за ограничений от иностранных партнеров, поэтому под нож пошли ненужные файлы. В том числе и бэкапы. Скорее всего, их удалили случайно, так как мне никто не сообщил. 

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

Думаю, вы уже догадались, что произошло дальше… у меня умер жесткий диск на рабочем компьютере. Может, за день, может, в тот же день. А потом пропал доступ к серверу. Винить, по сути, некого — так совпало, что все защитные копии исчезли одна за другой как раз к моменту аварии. 

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

Для конфиденциальности буду использовать в тексте случайные домены, не называя реально пострадавший сайт.

План спасения

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

Можно вытащить HTML-версию страниц из веб-архивов. Выкачать все данные и оживить формы заявок. На первое время это решит проблему. После можно спокойно вытащить информацию со страниц, положить в базу данных, а HTML превратить в шаблоны. 

Есть два крупных архива, которые делают максимально полные копии: Wayback Machine и Common Crawl. Попробовал оба варианта — и вот что у меня получилось. 

Internet Archive и Wayback Machine 

Internet Archive (Архив интернета) — это глобальная некоммерческая цифровая библиотека, которая хранит почти все интернет-сайты (включая старые и новые версии) как культурное наследие. 

Wayback Machine — это ключевой проект Internet Archive, его задача — сохранять все интернет-страницы и предоставлять удобный интерфейс для просмотра копий страниц. Через  веб-приложение https://web.archive.org/ можно посмотреть большинство сайтов, в том числе уже несуществующих. Увидеть не только последнюю версию, но и как они выглядели раньше. Например, вот как выглядел сайт FirstVDS в далеком 2006 году или Яндекс в 1998-м

Старый дизайн Яндекса, который сохранил Wayback Machine

Старый дизайн Яндекса, который сохранил Wayback Machine

Не все сайты можно найти в базе. Могут отсутствовать даже крупные ресурсы, которые были исключены из индекса. Либо администрация связалась с Wayback Machine и прямо попросила не индексировать, либо был прописан запрет на сканирование в файле robots.txt. Если вы прописали в robots.txt запрет на индексацию, восстановить сайт через Wayback Machine не получится. 

Дубликаты страниц система делает с помощью автоматических ботов (краулеров), которые обходят все ссылки в интернете и загружают в базу копии. Каждый заход краулер выкачивает не все ресурсы. В один заход может скопировать CSS-файл, в другой — HTML-код страницы, в третий и последующие заберет картинки. Когда ресурс попадает в базу, это называют захватом (capture) или снимком. Во время захвата бот сохраняет не только полученные данные, но и метаописание: 

  1. статус ответа сервера (200, 301, 404 и т. д.); 

  2. временную метку;

  3. тип контента (MiME-type);

  4. уникальный идентификатор (Capture Index). В дальнейшем с его помощью связывает разрозненные части сайта. 

Сайт может попасть в архив двумя способами: внешние ссылки и прямой запрос на добавление. Не стоит думать, что по запросу сайт сразу будет добавлен в базу. Чтобы база не засорялась бесполезными сайтами, бот идёт индексировать не сразу. Сайт встает в очередь. Надёжнее другой путь — побольше внешних ссылок. Чем их больше, тем чаще краулеры archive.org будут посещать сайт и тем больше версий будет сохранено. 

Получить копию страницы можно через веб-интерфейс на сайте archive.org либо запросом к специлизированному API. 

Важный момент: каждый ресурс (HTML-страница, изображение, CSS, JS) захватывается в разное время. Одна страница могла быть снята в 2022 году, а связанные с ней картинки или стили — в 2020-м или 2024-м. При попытке прямо выкачать сайт через веб-интерфейс возникнет ряд проблем:

  • Разрозненный контент. Страницы могут ссылаться на отсутствующие или устаревшие версии ресурсов либо на страницы, которые еще не были добавлены в базу архива. 

  • Замусоривание HTML-кода. Wayback добавляет свои обёртки, тулбары, переписывает все ссылки на web.archive.org/web/…. В результате сайт выглядит сломанным или перегруженным лишним кодом. Уйдет много сил, чтобы привести сайт к нужному виду.

  • Нестабильность. Основной интерфейс и связанные инструменты часто дают таймауты или падают в ошибку при массовом скачивании. Это элементарная защита от парсеров, чтобы система работала стабильно.

Восстанавливать сайт лучше через специализированный API, которое сейчас рассмотрим. 

Что такое CDX API?

CDX (Capture Index) — это база всех сохраненных снимков страниц. По сути, большая таблица, где каждая строка описывает один захват (capture). Строки хранят метаописание и ссылку на данные.

CDX API — это HTTP-интерфейс для поиска по базе снимков. Принимает GET-запросы, в ответ шлет данные в JSON или обычный текст (plain text) — в зависимости от выбора пользователя. В ответ приходит не полное содержимое файлов, а метаданные. Так сервер разгружается и API не падает под нагрузкой. С его помощью легко получить чистый список уникальных URL с самыми свежими снимками и затем скачать именно их.

Пример запроса к API:

curl.exe "http://web.archive.org/cdx/search/cdx?url=sitename.com/*&output=text&fl=timestamp,original&filter=statuscode:200&collapse=urlkey&limit=2000"
Пример ответа CDX API

Пример ответа CDX API

Несколько полезных параметров, которые пригодятся при обращении к API:

  • output=text или output=json — вернуть в тексте или JSON-формате 

  • fl=timestamp,original — вернуть только перечисленные поля

  • filter=statuscode:200 — вернуть страницы со статусом ответа сервера 200 

  • collapse=urlkey — убрать дубликаты, оставив самый свежий вариант каждой страницы. limit=2000 — ограничить количество страниц в ответе 

  • from и to — вернуть данные полученные в диапазоне дат (формат YYYYMMDD)

Когда получены конкретные ссылки и временные метки, можно запрашивать копии страниц. Шаблон вызова:

curl "http://web.archive.org/web/<timespamp>id_/<full_page_url>"

Вместо <timestamp> подставляем временную метку из ответа API. Вместо <full_page_url> — адрес из той же строчки, что и временная метка. Пример:

curl "http://web.archive.org/web/20220125010113id_/http://sitename.com/user"

Сервер вернет чистую копию страницы сайта:

Пример ответа с копией страницы

Пример ответа с копией страницы

Wayback Machine Downloader

Есть утилита для быстрого и комфортного восстановления копии сайта — wayback_machine_downloader. Устанавливается как пакет Python: 

pip install wayback_machine_downloader.

Скачать качественный бэкап сайта можно одной командой:

wayback_machine_downloader https://yoursite.com
Процесс скачивания копии сайта с веб-архива

Процесс скачивания копии сайта с веб-архива

Если утилита сработала, 90% работы выполнено. Программа найдет все страницы, которые краулеры веб-архива когда-либо скопировали. Автоматически выберет наиболее свежую версию, избегая дубликатов. Сохранит копию в папку websites/domain_name. 

Но самое приятное — почистит от всего лишнего, что добавил архив. Например, приведет в порядок ссылки. Когда боты сохраняют копию твоих страниц и файлов, все ссылки переделываются с прямых на ссылки вида web.archive.org. Это нужно для целостности данных. Иначе на сайте Wayback копия страницы может отображаться некорректно. 

На простых сайтах обычно не возникает проблем, кроме проблем с ЧПУ (человекоподобными URL). Система не знает, как именно работает ваш сайт. Когда она натыкается на человекоподобный URL, сохраняет страницу как папку с индексным файлом. Для адреса domain.ru/some_path будет создана папка some_path, внутри нее появится файл index.html, содержащий страницу. 

Выкачав сайт с ЧПУ-адресами, нужно пройтись по каждой папке и в index.html прописать правильный путь к файлу со стилями. Можно сделать массовой заменой в том же Visual Studio Code, указав путь к CSS-файлу от корня сайта. 

Утилита отказалась выкачивать сайт

Утилита отказалась выкачивать сайт

У меня утилита отказалась работать и выдала ошибку 400 Bad Request. Возможно, проблема в ограничениях сети. Не удивлюсь, если трафик не прошел фильтры моего домашнего провайдера. Может, сервер Wayback был перегружен. Разбираться в причинах нет времени, каждый час простоя сайта грозит падением позиций по SEO. Если сайт долго недоступен, поисковая сеть может понизить его в выдаче. А это — потеря трафика и прямые убытки. 

Google прислал уведомление, когда сайт упал

Google прислал уведомление, когда сайт упал

Чтобы не терять время, набросал небольшой bash-скрипт для упрощения ручного скачивания, который сейчас разберем. 

Ручное восстановление из веб-архива

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

curl "http://web.archive.org/cdx/search/cdx?url=sitename.com/*&output=text&fl=timestamp,original&filter=statuscode:200&collapse=urlkey&limit=2000" > urls_clean.txt

Запрос сохранит данные в файл urls_clean.txt.

Параметр collapse=urlkey, как писал раньше, важен, чтобы получить только уникальные ссылки. Иначе придется руками чистить партянку адресов, отбирая свежие версии. 

Небольшой bash-скрипт, который автоматически сформирует ссылки для скачивания и вытащит копию сайта. 

#!/bin/bashwhile read timestamp url; do    # Формируем ссылку на архив    archive_url="https://web.archive.org/web/${timestamp}id_/${url}"       # Определяем локальный путь файла    filepath=$(echo "$url" | sed 's|https\?://[^/]*/||')    [ -z "$filepath" ] && filepath="index.html"    [[ "$filepath" != *"."* ]] && filepath="${filepath%/}/index.html"       mkdir -p "$(dirname "site/$filepath")"       # Скачиваем если файл ещё не существует    if [ ! -f "site/$filepath" ]; then        echo "Downloading: $url"        curl -s -L --max-time 30 -o "site/$filepath" "$archive_url"        sleep 1  # пауза чтобы не забанили    fidone < urls_clean.txt

Скрипт сохраняем в файл download.sh рядом с urls_clean.txt. Нужно сделать файл исполняемым и запустить:

chmod +x download.sh./download.sh
Нашлись даже файлы шрифтов

Нашлись даже файлы шрифтов

Внутри HTML-файлов некоторые ссылки могут быть замусорены префиксом https://web.archive.org/web/. Если запустить сайт в таком виде, все ссылки будут вести на веб-архив. Почистить ссылки можно одной командов в Bash:

find "$OUTPUT_DIR" -name "*.html" -exec sed -i \   's|https://web.archive.org/web/[0-9]*[a-z_]*/||g' {} +

Проверка и оживление восстановленной версии

Для быстрой проверки использую HTTP-сервер Python:

python -m http.server 8080

Сайт будет доступен по адресу http://localhost:8080. Минус — сервер не обрабатывает PHP. Посмотреть получится только HTML-файлы. Если на машине установлен PHP, можно запустить его сервер и тогда все будет работать четко:

php -S localhost:8080

Либо через Docker (запускать из папки с копией сайта):

docker run -p 9999:80 -v .:/var/www/html php:apache

Есть смысл проверить ссылки. Если архив отдал не все, лучше об этом знать заранее. Быстрее всего сделать это с помощью linkchecker:

pip install linkchecker

Запуск:

linkchecker http://localhost:9999 --check-extern --no-warnings

Если найдены битые ссылки, откройте HTML-файл проблемной страницы, посмотрите в коде, какой именно ресурс (картинка, CSS, JS) отсутствует, и скопируйте его относительный путь. Затем идем на веб-архив, открываем найденные страницы. Из URL сохраняем временную метку и полный путь к страницы. Эти данные сохраняем в текстовый файл и снова запускаем скрипт скачивания, чтобы он скачал все нужные данные. 

Следующим этапом создал на скорую руку файл order.php, настроил проброс заявки в CRM и дубликат на электронную почту. Прошелся по всем формам заявок и заменил action на новый файл. 

HTML-версия сайта готова. Впереди большая работа по воссозданию сайта. Нужно заново сделать базу данных и положить в нее весь динамический контент. Из HTML-файлов вычистить все лишнее, превратив их в шаблоны. Но главное — сайт снова открывается, клиенты могут получать информацию.

Восстановление через Common Crawl 

Common Crawl — это другой некоммерческий проект, который собирает собственный архив интернета. Их цель — предоставить открытый, доступный для анализа датасет для крупномасштабных исследований и разработок, особенно в области LLM. Это накладывает свой отпечаток, собранные данные отдаются в виде частей WARC-файла. Своеобразного архива, который нужно парсить. Потребуются навыки программирования. 

Есть еще одно ключевое отличие от Wayback Machine — краулеры не собирают статические файлы вроде картинок или стилей CSS. После восстановления у вас будет голый HTML. Поэтому Common Crawl — не равнозначная альтернатива. Скорее, это способ минимизировать затраты на устранение инцидента. Тексты и HTML, который можно переработать в шаблон, уже неплохое подспорье. 

Чтобы выкачать информацию, нужна утилита cdx_toolkit. Установка:

pip install 

Посмотрим, есть ли вообще хоть что-то в за последние 100 краулов:

cdxt --crawl 100 size 'example.com/*'

Краулы — это своеобразное разбиение базы Common Crawl. Каждый краул — это информация за один месяц краулинга, содержит около 2,5-3,5 миллиарда веб-страниц. Указав crawl в 100, ограничил поиск примерно восемью годами.

Спустя пять минут, программа вернула число 17840. Это не байты и не количество страниц. Это оценочное число строк в базе данных. Каждая строка — это полный HTTP-ответ, включая дубли. В любом случае, если число больше нуля, значит, можно пробовать получать данные. 

Посмотреть, какие вообще страницы есть в базе:

cdxt --crawl 100 --filter '=status:200' iter 'example.com/*' > all_pages.jsonl

Получить данные:

cdxt --crawl 100 --filter '=status:200' warc 'example.com/*'

От числа краулов напрямую зависит, сколько времени займёт запрос. Например, запрос с crawl равным 10 выполнялся всего 1 минуту 34 секунды. Со значением 50 время увеличилось до 10 минут. Сотня привела не только к кратному увеличению, но и большому количеству ошибок. Соединение периодически отваливалось. 

На выходе получится архив TEST-000001.extracted.warc.gz, где 000001 — это порядковый номер запроса. Если снова запустить утилиту и выкачать данные, счетчик инкрементируется (увеличится на единицу). 

Внутри один файл с таким же названием TEST-000001.extracted.warc. Это база данных со всеми страницами, которые собрал Common Crawl за указанное количество краулов. 

WARC — стандартный формат архивации веб-страниц (ISO 28500). Придуман в Internet Archive (archive.org), сейчас используется повсеместно — Common Crawl, Wayback Machine. 

Внутри WARC-файла — последовательность записей. Каждая запись содержит заголовок с метаданными и тело:

WARC/1.0WARC-Type: responseWARC-Target-URI: https://example.com/aboutWARC-Date: 2024-03-15T10:23:41ZContent-Length: 4821HTTP/1.1 200 OKContent-Type: text/html...<html>...</html>

Для парсинга есть Python-библиотека warcio, она умеет читать такие файлы и отдавать записи по одной. Устанавливается через pip:

pip install warcio

Исходный код скрипта, который разберет архив на отдельные файлы и сложит их в указанную папку:

import sys          import re          from pathlib import Path                        from urllib.parse import urlparse              # читает записи из WARC-файла по однойfrom warcio.archiveiterator import ArchiveIterator  # папка по умолчанию, если -o не указанout_dir = Path("./site")  # все аргументы командной строки, кроме имени самого скриптаargs = sys.argv[1:]  if "-o" in args:    # находим позицию флага -o    i = args.index("-o")              # следующий аргумент после -o — это путь к папке    out_dir = Path(args[i + 1])      # убираем "-o" и путь из списка, остаются только WARC-файлы    args = args[:i] + args[i + 2:]  # создаём папку назначения (и все родительские, если нужно)out_dir.mkdir(parents=True, exist_ok=True)  # перебираем все переданные WARC-файлыfor warc_path in args:      # открываем файл в бинарном режиме    with open(warc_path, "rb") as f:          # перебираем записи внутри WARC (их там много разных типов)        for record in ArchiveIterator(f):              # нас интересуют только HTTP-ответы сервера,            if record.rec_type != "response":                  # остальные типы (warcinfo, request, metadata) — пропускаем                continue                                    # пропускаем 301, 404, 500 и т.д.            if record.http_headers.get_statuscode() != "200":                  continue            # URL страницы, которую краулер скачал            url = record.rec_headers.get_header("WARC-Target-URI", "")              # разбиваем URL: parsed.netloc = "example.com", parsed.path = "/about"            parsed = urlparse(url)              # убираем trailing slash; корень "/" → "/index.html"            path = parsed.path.rstrip("/") or "/index.html"              # если у пути нет расширения (например /about/team),            if not Path(path).suffix:                      # добавляем /index.html — иначе создастся файл без расширения                path += "/index.html"                  # разбиваем путь на части и заменяем символы, запрещённые в именах файлов Windows, на "_"            parts = [re.sub(r'[<>:"|?*\\]', "_", p) for p in path.split("/") if p not in ("", ".", "..")]            # собираем итоговый путь: ./site/example.com/about/index.html            # если parts пустой (что-то пошло не так) — кладём index.html прямо в папку домена            local = out_dir / parsed.netloc / Path(*parts) if parts else out_dir / parsed.netloc / "index.html"                       # создаём все промежуточные папки, если их нет, и сохраняем файл                    local.parent.mkdir(parents=True, exist_ok=True)              # читаем тело ответа и пишем в файл            local.write_bytes(record.content_stream().read())              # выводим путь к сохраненному файлу            print(local)
python warc_extract.py TEST-000000.extracted.warc.gz -o recovery

Возможно, возникнет вопрос, как быть, если сайт динамический. Зависит от реализации. Краулер делает снимок того, что возвращает веб-сервер. Если у страниц разный URL (даже отличающиеся только хэшем), высоки шансы получить большую часть контента. 

Приложения, построенные по технологии SPA (Single Page Application), бот либо отбросит полностью, либо сохранит как одну страницу. В этом и заключается их суть — уйти от традиционной многостраничной архитектуры в пользу загрузки данных без перезагрузок и внутренних переходов.

Заключение

Потерять сайт без бэкапов — не приговор. Шанс есть: если ресурс достаточно старый и проиндексированный, копия почти наверняка сохранилась в одном из веб-архивов. Это не полноценный бэкап, но рабочая основа, с которой можно поднять сайт за несколько часов и спокойно восстанавливать остальное.

Если выбирать между двумя архивами, порядок такой:

Wayback Machine — первый вариант. Даёт самую точную копию со стилями, картинками и шрифтами, а через CDX API и Wayback Machine Downloader выкачивается почти без ручной работы.

Common Crawl — запасной аэродром. Имеет смысл, только если из веб-архива вы по какой-то причине исключены: на руках окажется голый HTML без статики, который придётся парсить самому.

Способ через кеш поисковиков можно вычеркнуть: Google его полностью отключил, а Яндекс отдаёт страницы без картинок и стилей.

Но вся эта история — про то, как дорого обходится экономия на бэкапах. Восстановление из архива работает, и всё же это аварийный костыль: часть данных вы потеряете, а на возню уйдут сутки. Держите минимум три независимые копии в разных местах и проверяйте, что они действительно создаются.

Автор текста — Евгений Хорошилов


НЛО прилетело и оставило здесь промокод для читателей нашего блога:
-15% на заказ нового VDS — HABRFIRSTVDS.

Положение об акции

ссылка на оригинал статьи https://habr.com/ru/articles/1050832/