CloudFlare + nginx, или экономим при помощи «кофеварки»
Добрый день, уважаемый %username%, жадный читатель и борец за справедливость в интернетах!
Все мы помним (гугл точно помнит!), что была такая статья CloudFlare + nginx = кешируем всё на бесплатном плане. В которой рассматривались основные принципы экономии на тарифах и серверах, путем всеядного кеширование на стороне CloudFlare файлов до 512Мб.
В данном материале мы поиграем с кодами ответов нашего сервера, чтобы съекономить еще больше золота чтобы построить зиккурат и не переходить на «enterprise plan» которые нам «offer» похожий результат в своих «offers».
На бесплатном тарифе TTL составляет 2 часа. Это то, что у них написано в бесплатном тарифном плане. Если же копнуть глубже, то получаем:
- 200 301 120m;
- 302 303 20m;
- 403 1m;
- 404 5m;
- any 0s;
Более развернуто: редиректы кешируются по 20 минут, ошибки авторизации на минуту и классические 404 по 5 минут. Прочие коды не кешируются.
Это означает, что если у вас классный динамический сайт который, к примеру, предоставляет API для каких-нибудь операций и т.д. и т.п. и сие у вас завернуто через CF, так как генерит и файлы и картинки и много траффика, а динамике больно… то если кто-то понимает как у вас генерируются ответы (голый счетчик или в base64 или свой base или хеши, но последние подобрать труднее), то он (человек с темной стороны комнаты без освещения) может обмануть других пользователей ложным ответом, а именно — 404.
К примеру:
- Простой сервис, который дергает EXIF из фоток, которые были залиты. Пример ссылки
http://example.com/api/image/exif/1.txt
— что означает выдать EXIF как TXT из фотки с id=1.
Предположим, что у вас там 1336 фоток. Сие значит, что 1, 2…1336ая выдатут 200й ответ, который будет закеширован на стороне cloudflare.
Вот наша эмуляция (nginx):
location ~* "^/api/image/exif/(.*?)\.txt$" {
default_type text/plain;
set $testimageid $1;
##backend
if ($testimageid ~ 1337){
return 404 "Image $testimageid not found";
}
##backend
return 200 "EXIF for $testimageid image";
}
И так далее…
Пока не дойдем до фото с айди 1337, которого еще на сервере нет. Что сделает наша динамика? Логично, что она выдаст некий текст про ошибку и код 404.
Который следом будет закеширован. И все последующие запросы к этому URL выдадут ответ из кеша CF на следующие 5 минут.
Критично ли это? И да и нет. Зависит того, сколько юзеров вы сделаете несчастными и сколько съекономленных на CDN (благодаря мне) миллионов вы потеряете.
Что же делать? Смотрим оффициальный материал и понимаем, что надо менять код… код ответа сервера в случае 404.
Но не все так просто. Нельзя_просто_так_взять_и_сменить_код_ответа.jpg, так как каждый код несет какую-то смысловую нагрузку, которая будет интерпретирована или на нее просто забьют!
Вот для этого и был придуман код, который никакой смысловой нагрузки не несет, это код 418, который описан в rfc2324.
Меняем код нашей эмуляции (и очищаем кеш для этой ссылки в панели CF):
location ~* "^/api/image/exif/(.*?)\.txt$" {
default_type text/plain;
set $testimageid $1;
##backend
if ($testimageid ~ 1337){
return 418 "Image $testimageid not found";
}
##backend
return 200 "EXIF for $testimageid image";
}
И получаем следующую картину:
Сие знаменует факт, что до тех пор, пока картинки нет, CF не кеширует ответ от нашего сервера, передавая клиентам каждый раз свежий ответ с ошибкой 418 [от нашего сервера]. Следом, как картинка появляется на сервере, и наша динамика отдает ответ 200, CF кеширует этот ответ на 2 часа.
Код 418 относится к 4хх группе кодов. И даже, если у конечного пользователя нет определения этого кода в браузере (или в самописном софте), то там есть как минимум (должна быть!) проверка на 4хх как на скриншотах этой статью (firefox, красненький квадратик).
Вот так вот просто можно можно сообщить об ошибке (4хх) и попросить cloudflare не кешировать данный ответ при политике, когда мы все кешируем. Сие уберегает от ложных 404 ответов от сервера, когда кто-то запрашивал будущий материал до момента публикации.
Да прибудет с вами сила!
З.Ы. set $testimageid $1;
используется потому, что nginx не может сравнивать $1 в if выражении (но может оперировать $1 в конфиге или в контенте), для этого надо вводить переменную. Щербатые котлы картинки выравнены между собой и сжаты в png-8, перфекционисты на диалапе могут улыбнуться!