Как перенести сотни доменов на Cloudflare и не отдать кому-то Global API Key
Спойлер: через веб-интерфейс это 6–8 часов кликов, через чистый API — упираешься в ограничения scoped-токенов, а Global API Key нельзя с чистой совестью хранить на чужом сервере.
Рассказываю, как мы собрали два инструмента под одну задачу — и почему именно два, а не SaaS.
Привет. Делаем с командой инфраструктуру на Cloudflare под 301.ru, и за последний год руками прошли через все три варианта добавления доменов в Cloudflare в больших количествах. Всё, что ниже — не гипотетика, а то, куда реально упёрлись и чем лечили.
Боль, с которой всё началось
Представьте: заводим новый Cloudflare-аккаунт под проект, на него нужно подцепить 200–500 доменов. Через веб-интерфейс это выглядит так:
- «Add site» → ввод домена → Continue
- Выбор плана (Free) → Continue
- Сканирование DNS → Continue
- Копирование назначенных nameservers → идём в регистратор → меняем NS
- Возврат в Cloudflare → Check nameservers
Пять экранов на один домен. Умножаем на 300 — получаем примерно 1500 кликов и весь рабочий день в глухом интерфейсе, где половина времени уходит на ожидание. Это та точка, в которой нормальный разработчик говорит «окей, пойду в API».
Подход №1: чистый API и boilerplate на Python
Первое, что делаешь — идёшь на api.cloudflare.com, берёшь API Token, пишешь скрипт. Выглядит всё просто: POST /zones c {"name": "example.com", "account": {"id": "..."}}. На десятке доменов работает, на сотне начинаются нюансы:
- Rate limits. У Cloudflare API глобальный лимит — 1200 запросов за 5 минут на user. На пачках это ловится не сразу, а ближе к середине, и нужен корректный backoff с уважением Retry-After.
- Domain parsing. Реальные списки редко приходят чистыми — там субдомены, www, URL с путями, смешанные IDN и Punycode. Нужен нормальный парсер, который достанет eTLD+1.
- Идемпотентность. Нажал Ctrl+C на 340-м домене из 500 — как продолжить без повторов и без пропусков?
- Многоаккаунтность. Если у тебя 4 аккаунта под разные пулы — каждый прогон нужно перенастраивать.
Всё это решается, но это проект на неделю, а не «часик вечером». И главное — этот скрипт живёт у тебя в консоли, не у клиента/коллеги, который тоже хочет заливать домены.
Подход №2: сделать SaaS — и тут вылезает настоящая проблема
Логичная мысль: раз боль массовая, сделаем веб-сервис. Юзер вводит API-ключ, заливает список доменов, жмёт кнопку — получает результат. Сотни часов экономии на всех.
И тут ты упираешься в архитектурную стену, о которую разбивается половина потенциальных CF-сервисов.
API Token не умеет создавать зоны в рамках только своего scope. Токены в Cloudflare привязаны к списку уже существующих зон. Чтобы создать новую — нужен permission Zone:Edit на уровне аккаунта, не на уровне отдельных зон. А токен с таким permission фактически равен доступу ко всему пулу доменов клиента — он может их создавать, удалять, перевыпускать DNS-записи, менять SSL-настройки. По степени власти это недалеко от Global API Key.
Global API Key — это root-доступ ко всему аккаунту: домены, DNS, Workers, KV, R2, billing, members. Один ключ на всё. Удобно для автоматизации — но смертельно для того, кто собирается этот ключ хранить у себя.
Представьте сервис, которому пользователи отдают свои Global API Keys. Что ты получаешь вместе с базой этих ключей:
- Фактическое владение инфраструктурой всех клиентов. Утечка базы = катастрофа для каждого из них.
- Compliance. Хранение чувствительных credentials → SOC 2, пентесты, страхование.
- Юридическую ответственность. Если через скомпрометированный ключ кто-то заддосит клиента или уведёт трафик — отвечать будешь ты.
- Полное несоответствие философии 301.st, где мы специально не храним ни трафик клиентов, ни их конфиги — всё работает на их собственных Cloudflare-аккаунтах через их токены.
Мы посидели с этим 15 минут и сказали «нет, спасибо».
Подход №3: вынести автоматизацию на клиент
Архитектурный вывод оказался простой: если ключ настолько мощный, что его нельзя передавать никому — пусть он и не передаётся. Автоматизация выполняется на устройстве пользователя, ключ живёт там же, мы в принципе не видим ни ключа, ни того, какие домены добавляются.
Так появились два инструмента. Один — расширение браузера, второй — десктоп для Windows. Разные рантаймы под разные сценарии, общая логика: API-запросы идут напрямую client → Cloudflare, через наши серверы не проходит ничего.
Cloudflare Tools — расширение браузера
wpps.ru/products/cloudflare-tools — Chrome / Firefox / Edge.
Когда подходит: работаешь в браузере, нужна мобильность между машинами, разовые пачки по несколько десятков — несколько сотен доменов. Живёт в боковой панели (Side Panel API), не открывается отдельным окном.
Что внутри:
- Парсер доменов. Вставляешь что угодно — список из Excel, кусок лога, письмо с URL, экспорт из регистратора. Выделяет валидные домены, нормализует до eTLD+1, показывает preflight-превью: что будет создано, что пропущено как дубликат, что невалидно. Это до вызова API.
- Хранение ключа. AES-256-GCM со случайным 256-битным ключом. Сам ключ живёт только в session storage браузера и уничтожается при закрытии. Изолировано в storage расширения — сайты и другие расширения не имеют доступа.
- Устойчивость. Прогресс операции сохраняется в IndexedDB. Закрыл браузер на 300-м домене из 500 — открываешь обратно, жмёшь Resume, продолжаешь с 301-го. Pause/resume/cancel работают на любой фазе.
- Rate-limit handling. Cloudflare возвращает 429 с заголовком Retry-After — расширение читает его и выдерживает нужную паузу, не упарывая экспоненциальный backoff вслепую.
- Сопутствующие операции. На том же интерфейсе — массовый purge cache (everything для выбранных зон) и массовое удаление зон с постраничным выбором.
CFTools для Windows — десктоп
wpps.ru/products/cloudflare-tools-win — Microsoft Store.
Когда подходит: десятки аккаунтов, работаешь постоянно, нужно чтобы приложение жило в системе и не требовало открывать браузер. Плюс Windows Credential Manager как место хранения — это другой threat model, чем session storage.
Отличия от расширения:
- Persistent-хранилище ключа. Windows Credential Manager, DPAPI под капотом. Не уничтожается при перезапуске.
- Мульти-аккаунт. Вводишь Global API Key один раз, переключаешься между аккаунтами в один клик без повторного логина. Для тех, у кого отдельные CF-аккаунты под каждый проект/бренд — экономия часа в неделю просто на переключении.
- Парсер с IDN/Punycode. Русские, немецкие, китайские домены — нормализует корректно в обе стороны.
- Светлая/тёмная тема по системным настройкам.
Что выбрать
СценарийИнструментРазовая пачка, работа с нескольких машинРасширениеПостоянная работа с десятками аккаунтовWindowsНе доверяешь persistent-хранилищу, хочешь чтобы ключ умирал с сессиейРасширениеРаботаешь без интернета в браузере, всё через трейWindowsНужно и то и тоОба, ключ один, поведение разное
Выводы
Массовое добавление доменов в Cloudflare — это не столько про «написать скрипт», сколько про доверие к ключу. API Token упирается в scope, Global API Key нельзя отдавать наружу — и правильное архитектурное решение лежит не в сторону SaaS, а в сторону клиентского софта, где ключ вообще не покидает устройство.
Оба инструмента бесплатные, без телеметрии и аккаунтов. Если у вас своя боль с Cloudflare API — напишите в комментариях, возможно следующий инструмент мы соберём под неё.
Делаем в 301.ru — команда из трех человек, остальное на Cloudflare Workers.