
Сайты перестали работать: серверы, на которых всё лежало, разом пропали из сети — без предупреждений и без шанса скачать бэкапы. А самих бэкапов у меня к тому моменту не осталось ни одного — по иронии судьбы я потерял их все буквально за пару недель до аварии.
Пришлось в авральном режиме поднимать хотя бы 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 и прямо попросила не индексировать, либо был прописан запрет на сканирование в файле robots.txt. Если вы прописали в robots.txt запрет на индексацию, восстановить сайт через Wayback Machine не получится.
Дубликаты страниц система делает с помощью автоматических ботов (краулеров), которые обходят все ссылки в интернете и загружают в базу копии. Каждый заход краулер выкачивает не все ресурсы. В один заход может скопировать CSS-файл, в другой — HTML-код страницы, в третий и последующие заберет картинки. Когда ресурс попадает в базу, это называют захватом (capture) или снимком. Во время захвата бот сохраняет не только полученные данные, но и метаописание:
статус ответа сервера (200, 301, 404 и т. д.);
временную метку;
тип контента (MiME-type);
уникальный идентификатор (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"

Несколько полезных параметров, которые пригодятся при обращении к API:
output=textилиoutput=json— вернуть в тексте или JSON-форматеfl=timestamp,original— вернуть только перечисленные поляfilter=statuscode:200— вернуть страницы со статусом ответа сервера 200collapse=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. Если сайт долго недоступен, поисковая сеть может понизить его в выдаче. А это — потеря трафика и прямые убытки.

Чтобы не терять время, набросал небольшой 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/bash while 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 # пауза чтобы не забанили fi done < 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.0 WARC-Type: response WARC-Target-URI: https://example.com/about WARC-Date: 2024-03-15T10:23:41Z Content-Length: 4821 HTTP/1.1 200 OK Content-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.
