Будем расширять границы контента. Ща покажу магию, знать это мастхэв. Мотай на ус, если не индус знал, пригодится.
У нас в компании достаточно банальная инфраструктура, в которую входит балансировщик и несколько нод на которых крутится nodejs приложение с 3000м портом, короче говоря апиха.
В какой-то момент мне необходимо добавить еще одну ноду с новой версией nodejs приложения.
Назовем её🎉
Городим в nginx на b1 такой велосипед:
Тестировщики подставляют заголовок
В location есть директива
В раздел map можно добавить еще кучу нод, которые не будут участвовать в обслуживании клиентов, но ты в любой момент сможешь на них попасть с помощью заголовка.
Если у тебя не апиха, а веб приложение, можешь воспользоваться плагином ModHeader, есть для фокса и хрома. В нём можно легко подставить все необходимые заголовки и попастьв жопу пальцем туда куда тебе нужно, или не нужно.
Конфигурация nginx это как стихи писать, есть какие-то базовые слова и правила, но в большинстве случаев 90% функционала вообще не используется. Потому что, документацию никто не читает и люди делают так, как научились или подсмотрели на stackoverflow. Вот такие пироги.
tags: #nginx
—
🟢 Подпишись: @bashdays
У нас в компании достаточно банальная инфраструктура, в которую входит балансировщик и несколько нод на которых крутится nodejs приложение с 3000м портом, короче говоря апиха.
bashdays-b1:443К примеру от клиентов идут POST запросы к апихе, запросы попадают на сервер b1, затем nginx распределяет запросы по нодам w1-w4 и отдает в ответ json. Примитивная балансировка нагрузки, но достаточно стабильная.
-> bashdays-w1:3000
-> bashdays-w2:3000
-> bashdays-w3:3000
-> bashdays-w4:3000
В какой-то момент мне необходимо добавить еще одну ноду с новой версией nodejs приложения.
Назовем её
bashdays-w5. Эта нода не должна обслуживать клиентов, но должна отдавать данные тестировщикам, чтобы те могли потыкать и протестировать в условиях продакшена. Ну а ты как думал? Тестируем на проде, можем себе позволить ))) Городим в nginx на b1 такой велосипед:
map $http_x_backend $backend {
bashdays-w5 192.168.0.5:3000; # w5
default backend;
}
upstream backend {
server 192.168.0.1:3000; # w1
server 192.168.0.2:3000; # w2
server 192.168.0.3:3000; # w3
server 192.168.0.4:3000; # w4
}
location / {
add_header X-Upstream $upstream_addr;
proxy_pass http://$backend;
}
Объясняю что происходит, клиенты идут на b1 и попадают по умолчанию в upstream backend, где прописаны ноды w1-w4.Тестировщики подставляют заголовок
X-Backend: bashdays-w5 в своих запросах и попадают на w5. То есть для обычных пользователей ничего не изменилось, но QA теперь с помощью заголовка X-Backend: bashdays-w5 могут попасть на новую ноду и затыкать ее хоть до усрачки.В location есть директива
add_header X-Upstream, она выведет в ответе nginx на какую ноду ты попал, удобно для дебага.В раздел map можно добавить еще кучу нод, которые не будут участвовать в обслуживании клиентов, но ты в любой момент сможешь на них попасть с помощью заголовка.
Если у тебя не апиха, а веб приложение, можешь воспользоваться плагином ModHeader, есть для фокса и хрома. В нём можно легко подставить все необходимые заголовки и попасть
Конфигурация nginx это как стихи писать, есть какие-то базовые слова и правила, но в большинстве случаев 90% функционала вообще не используется. Потому что, документацию никто не читает и люди делают так, как научились или подсмотрели на stackoverflow. Вот такие пироги.
tags: #nginx
—
Please open Telegram to view this post
VIEW IN TELEGRAM
👍80
Сегодня мы будем делать с вами свой nginx plus (тот который платный), а именно реализуем плюшку «Active health checks».
Это когда у тебя к примеру 10 апстримов и если один из них дохнет, то какой-нибудь богатый клиент получит 502 ошибку, обозлится и ничего не купит. А должен автоматически попасть на другой, более живой апстрим и потратить денежку.
Само собой будем применять инновационные технологии и немного возьмем из фреймворка «гавно и палки». Ну а как ты хотел? Бест практик! На халяву и уксус сладкий, как говорится. Короче все элементарно. Погнали.
Ставим ванильный nginx и делаем так:
хуй корень / и попадает в nginx апстрим backend, а апстрим сконфигурирован на сокет backend.sock от haproxy.
Далее запрос клиента пролетает по сокету, как фанера над загнивающим парижем и попадает в блок haproxy «backend» где у меня описаны все бэкенд-сервера (w1, w2, w3, w4).
Если по какой-то причине к примеру сервер w2 отдаст концы, haproxy это задетектит (timeout check 5s) и закинет запрос клиента на рабочий инстанс, тем самым клиент получит статус 200. А 200 ==заебись хорошо! 🗒
Ну а потом когда w2 очухается, то haproxy снова заберет его в свои сети и будет использовать на всю катушку, как провинившуюся падшую женщину.
Вот так это и работает. Вот так вот и живем. Балансировка нагрузки + roundrobin + active health checks
У haproxy еще есть встроенный визуальный мониторинг, но об этом я расскажу тебе в одной из следующих статей.
tags: #nginx
—
🟢 Подпишись: @bashdays
Это когда у тебя к примеру 10 апстримов и если один из них дохнет, то какой-нибудь богатый клиент получит 502 ошибку, обозлится и ничего не купит. А должен автоматически попасть на другой, более живой апстрим и потратить денежку.
Само собой будем применять инновационные технологии и немного возьмем из фреймворка «гавно и палки». Ну а как ты хотел? Бест практик! На халяву и уксус сладкий, как говорится. Короче все элементарно. Погнали.
Ставим ванильный nginx и делаем так:
upstream backend {
server unix:/var/run/haproxy/backend.sock;
}
location / {
proxy_pass http://backend;
}
Ставим рядом haproxy, и конфигурируем блоки frontend и backend таким образом:defaultsЧто это за хрень, щас объясню. Смотри. Клиент идет на
retries 3
timeout check 5s
frontend bashdays-backend
bind /var/run/haproxy/backend.sock user nginx mode 600
mode tcp
default_backend bashdays-backend
option tcplog
backend bashdays-backend
balance roundrobin
option tcplog
server bashdays-w1 192.168.0.1:80 check
server bashdays-w2 192.168.0.2:80 check
server bashdays-w3 192.168.0.3:80 check
server bashdays-w4 192.168.0.4:80 check
Далее запрос клиента пролетает по сокету, как фанера над загнивающим парижем и попадает в блок haproxy «backend» где у меня описаны все бэкенд-сервера (w1, w2, w3, w4).
Если по какой-то причине к примеру сервер w2 отдаст концы, haproxy это задетектит (timeout check 5s) и закинет запрос клиента на рабочий инстанс, тем самым клиент получит статус 200. А 200 ==
Ну а потом когда w2 очухается, то haproxy снова заберет его в свои сети и будет использовать на всю катушку, как провинившуюся падшую женщину.
Вот так это и работает. Вот так вот и живем. Балансировка нагрузки + roundrobin + active health checks
У haproxy еще есть встроенный визуальный мониторинг, но об этом я расскажу тебе в одной из следующих статей.
tags: #nginx
—
Please open Telegram to view this post
VIEW IN TELEGRAM
👍73
Ну вот и пятница на носу. Хотя какая разница какой день недели, если ты работаешь 24/7. Чем займёмся сегодня? Давай чём-нибудь простым и интересным.
Порой необходимо определить количество ядер на сервере. Понятно, ты можешь вызвать top/htop и визуально глянуть цифру.
Но мыж с тобой не пальцем деланные, нам надо всё по уму, как тру программисты. Чтобы можно было это в скрипт засунуть и далее плясать от полученного результата.💃
Для подсчета количества ядер, есть несколько способов:
Для чего нам знать количество ядер? Вопрос хороший, каждый для себя сам решает. Всё зависит от задач.
К примеру заскейлил ты тачку в Selectel, через их веб панельку, но nginx продолжает работать на старом конфиге. После этого очень желательно сразу переопределить в
Если Nginx выполняет работу нагружающую процессор (например SSL или gzipping), то оптимально установить эту директиву в значение, равное количеству ядер процессора.
Также, директива worker_processes, умноженная на worker_connections из секции event, даст максимально возможное количество клиентов.
Конечно же справедливо всё это ансиблом (ansible) или террой (terraform) раскатать, но это дополнительный геморрой, который никому не нужен. По крайней мере, когда это нужно было еще вчера и нет возможности писать лапшу из плейбуков.
Проще уж из скрипта узнать количество ядер, все посчитать и тем же sed’ом зареврайтить нужный тебе конфиг. Вешаешь его на крон, а оно следит за твоими ядрами и в нужный момент делает всё автоматически, хоть там каждую минуту горизонтально-вертикальным масштабированием занимайся.
Прототип без ифов, так, для наглядности:
😮💨
Ну а я желаю тебе хороших предстоящих выходных и береги себя! Мож чо на выходные еще закину интересного почитать.
tags: #linux #nginx
—
🟢 Подпишись: @bashdays
Порой необходимо определить количество ядер на сервере. Понятно, ты можешь вызвать top/htop и визуально глянуть цифру.
Но мыж с тобой не пальцем деланные, нам надо всё по уму, как тру программисты. Чтобы можно было это в скрипт засунуть и далее плясать от полученного результата.
Для подсчета количества ядер, есть несколько способов:
1. grep -wc '^processor' /proc/cpuinfoЭто не единственные способы заполучить желаемое, но самые релевантные. Кстати
2. getconf _NPROCESSORS_ONLN
3. nproc --all
getconf актуален и для макаводов (osx).Для чего нам знать количество ядер? Вопрос хороший, каждый для себя сам решает. Всё зависит от задач.
К примеру заскейлил ты тачку в Selectel, через их веб панельку, но nginx продолжает работать на старом конфиге. После этого очень желательно сразу переопределить в
nginx.conf параметр worker_processes. Если Nginx выполняет работу нагружающую процессор (например SSL или gzipping), то оптимально установить эту директиву в значение, равное количеству ядер процессора.
Также, директива worker_processes, умноженная на worker_connections из секции event, даст максимально возможное количество клиентов.
Конечно же справедливо всё это ансиблом (ansible) или террой (terraform) раскатать, но это дополнительный геморрой, который никому не нужен. По крайней мере, когда это нужно было еще вчера и нет возможности писать лапшу из плейбуков.
Проще уж из скрипта узнать количество ядер, все посчитать и тем же sed’ом зареврайтить нужный тебе конфиг. Вешаешь его на крон, а оно следит за твоими ядрами и в нужный момент делает всё автоматически, хоть там каждую минуту горизонтально-вертикальным масштабированием занимайся.
Прототип без ифов, так, для наглядности:
#!/bin/bashБери на вооружение, пригодится.
CPU_CORES=$(grep -wc '^processor' /proc/cpuinfo)
sed -i "s/worker_processes.*/worker_processes $CPU_CORES;/" /etc/nginx/nginx.conf
systemctl reload nginx
Ну а я желаю тебе хороших предстоящих выходных и береги себя! Мож чо на выходные еще закину интересного почитать.
tags: #linux #nginx
—
Please open Telegram to view this post
VIEW IN TELEGRAM
👍95
Привет. Как оказалось, не все знают что nginx позволяет нативно писать логи в json формате. Вообще в продакшене это бест-практика. Для этого в конфиг nginx.conf нужно добавить такой блок:
Получаем максимальную информацию о клиенте в json формате, которую пробиваем средствами nginx. И теперь все это можно легко скармливать всяким эластикам и т.п. без парсинга и гроков. Так сказать — избавляемся от костылей.
Но хранить логи в файлах, такое себе. Поэтому мастхэв запихать логи непременно в system journal.
Забиваем пару строк в nginx.conf и всё логирование будет перенаправлено в system journal.
А можно комбинировать, писать одновременно логи в файл в дефолтном шаблоне nginx’а и параллельно писать в system journal в json. Я иногда такое проворачиваю для дебага, где в логах требуется вывести лишь время, айпишник и ури-ури. Типа такого:
Но конечно если есть Kibana, дела с отладкой в разы становятся лучше. Ну а чтобы посмотреть логи в system journal, воспользуйся такой командой: journalctl -f
Сегодня если руки дойдут, обсудим судо-мудо или другие линукс кишочки. Давай, хорошей тебе пятницы, увидимся!
tags: #nginx
—
💩 @bashdays
log_format nginx_json escape=json '{"time_local":"$time_local", "cloud_ip":"$http_x_real_ip", "ip":"$http_cf_connecting_ip", "connection":"$connection", "request_completion":"$request_completion", "status":"$status", "rtime":"$request_time", "rlenght":"$request_length", "content_type":"$content_type", "content_length":"$content_length", "bytes_sent":"$bytes_sent", "body_bytes_sent":"$body_bytes_sent", "raddr":"$remote_addr", "ruser":"$remote_user","upstream_addr":"$upstream_addr", "upstr_resp_time":"$upstream_response_time", "upstr_cache_status":"$upstream_cache_status", "upst_status":"$upstream_status", "gzip_ratio":"$gzip_ratio", "http_x_forwarded_for":"$http_x_forwarded_for", "proxy":"$proxy_host:$proxy_port", "proxy_int_body_length":"$proxy_internal_body_length", "server_proto":"$server_protocol", "rmethod":"$request_method", "uri":"$uri", "args":"$args", "http_referer":"$http_referer", "uag":"$http_user_agent"}';
access_log /var/log/nginx/access.log nginx_json;
error_log /var/log/nginx/error.log;Получаем максимальную информацию о клиенте в json формате, которую пробиваем средствами nginx. И теперь все это можно легко скармливать всяким эластикам и т.п. без парсинга и гроков. Так сказать — избавляемся от костылей.
Но хранить логи в файлах, такое себе. Поэтому мастхэв запихать логи непременно в system journal.
Забиваем пару строк в nginx.conf и всё логирование будет перенаправлено в system journal.
error_log syslog:server=unix:/dev/log;
access_log syslog:server=unix:/dev/log nginx_json;
А можно комбинировать, писать одновременно логи в файл в дефолтном шаблоне nginx’а и параллельно писать в system journal в json. Я иногда такое проворачиваю для дебага, где в логах требуется вывести лишь время, айпишник и ури-ури. Типа такого:
log_format nginx_json ...
log_format nginx_default ...
access_log /var/log/nginx/access_json.log nginx_json;
access_log /var/log/nginx/access_default.log nginx_default;
Но конечно если есть Kibana, дела с отладкой в разы становятся лучше. Ну а чтобы посмотреть логи в system journal, воспользуйся такой командой: journalctl -f
Сегодня если руки дойдут, обсудим судо-мудо или другие линукс кишочки. Давай, хорошей тебе пятницы, увидимся!
tags: #nginx
—
Please open Telegram to view this post
VIEW IN TELEGRAM
👍154
Поднимал тут у себя огородик с wg-easy, всё ок. Но из коробки, морда для создания ключей работает по протоколу http. Вроде ничего страшного, но не серьезно. Ну и настраивать
Пока искал готовое решение (кстати нашел нативный мануал от wg-easy), набрел на интересную штуку. Называется Nginx Proxy Manager.
Короче это морда для nginx, чтобы не руками конфиг задрачивать, а мышкой галочки натыкивать + из коробки нативная интеграция с letsencrypt.
Возможно у нас в чатике где-то это уже и пролетало, но я не видал.
Поднимается за минуту через docker-compose, без лишних велосипедов и костылей. Дружит с sqlite и mysql. Есть система распределения прав, каждый юзер может редактировать свои локейшены и хосты. Поддерживает малину и arm архитектуры. Ну и естественно есть гибкий Access List и Basic Auth.
Киллер-фича: Можно генерить wildcard ssl, выбираешь из большого выпадающего списка к примеру cloudflare и оно тебе DNS Challenge делает. Это прям порадовало.
Понятно дело, что оно не максимально гибкое в плане конфигурации через морду. Но для этого есть дырка, чтобы вставлять свои куски конфига в текстовом формате. А так базового функционала прям за глаза.
В общем рекомендую как для локальной разработки, так и для каких-то своих сервисов вроде bitwarden и т.п.
Картинки у них на сайте посмотрите, не буду сюда запихивать.
🌐 https://nginxproxymanager.com/
tags: #nginx #services
—
💩 @bashdays
nginx + acme.sh тоже капец лень.Пока искал готовое решение (кстати нашел нативный мануал от wg-easy), набрел на интересную штуку. Называется Nginx Proxy Manager.
Короче это морда для nginx, чтобы не руками конфиг задрачивать, а мышкой галочки натыкивать + из коробки нативная интеграция с letsencrypt.
Возможно у нас в чатике где-то это уже и пролетало, но я не видал.
Поднимается за минуту через docker-compose, без лишних велосипедов и костылей. Дружит с sqlite и mysql. Есть система распределения прав, каждый юзер может редактировать свои локейшены и хосты. Поддерживает малину и arm архитектуры. Ну и естественно есть гибкий Access List и Basic Auth.
Киллер-фича: Можно генерить wildcard ssl, выбираешь из большого выпадающего списка к примеру cloudflare и оно тебе DNS Challenge делает. Это прям порадовало.
Понятно дело, что оно не максимально гибкое в плане конфигурации через морду. Но для этого есть дырка, чтобы вставлять свои куски конфига в текстовом формате. А так базового функционала прям за глаза.
В общем рекомендую как для локальной разработки, так и для каких-то своих сервисов вроде bitwarden и т.п.
Картинки у них на сайте посмотрите, не буду сюда запихивать.
tags: #nginx #services
—
Please open Telegram to view this post
VIEW IN TELEGRAM
Привет, тут на днях в нашем чатике пролетала софтина которая делает этакий ханипот на 22 порту. И все кто ломится по ssh просто вязнут в этом болоте.
Но сегодня не про это. Сегодня про злоумышленников, которые методом тыка пытаются найти и украсть бэкап. Зачастую бэкапы хранятся в папках проекта, либо вообще в корне пылятся годами.
Как это бывает: переезжаешь на другой сервер, перетащил проект в zip архиве, распаковал, а сам zip не удалил. И теперь любой кто узнает имя архива, сможет его скачать, со всеми паролями и явками. Ну либо как в распространенных движках, есть всем известная папка, где могут находиться эти бэкапы.
Вообще руками имена файлов никто не подбирает, для этого есть специальный софт, который просто брутфорсит по словарю всевозможные локейшены и если получает статус 200, то скачивает всё, что плохо лежит.
Как с этим бороться? Ничего не бэкапить в папки проекта, удалять промежуточные файлы если что-то переносил, настраивать политики nginx чтобы 403 отдавал и т.п.
Но есть способ сделать простой ханипот. Злоумышленник якобы находит бэкап, получает статус 200 и начинает его скачивать. Естественно это не бэкап, а специально подготовленный файл большого размера. Причем такой файл отдается специально с пониженной скоростью и санкциями.
Повторюсь, маловероятно, что злоумышленник это человек. В основном сбором бигдаты занимается автоматизированный софт. Устанавливается на уже скомпрометированные машины, с которых осуществляется сканирование каталогов на наличие плохо лежащих файлов.
Давай настроем такой ханипот на примере nginx
Добавляем в nginx конфиги:
Указываем список на что будем триггериться. Ограничиваем скорость, ограничиваем число потоков, запрещаем докачку.
Создаем файл затычку размером 1гиг, этого вполне хватит. Но можешь конечно сделать и больше.
Вот и всё. Теперь если кто-то попытается вытянуть у тебя бэкап к примеру mysql.tar.gz, то будет страдать. Идея думаю тебе понятна, вокруг нее можно городить вообще сумасшедшие схемы. Но опять же это всего лишь концепт, из которого можно сделать что-то большое и нужное.
Я одно время применял этот способ в случае, когда коллеги просят выдать бэкап базы. Обычно я даю прямую ссылку на скачивание. Но бывают ситуации, когда разработчики ведут себя как зажравшиеся ЧСВешные мудаки. И на такой случай у меня для них была специальная ссылка для скачивания бэкапа.
Ничего особенного, но с сюрпризом, бэкап никогда не скачается. Тащить 10 гигабайт со скоростью dial-up ну такое себе. А когда те начинали орать как свинья из avp, мой ответ был простой - проблема на твоей стороне. У меня видишь все работает и показываю скриншот с нормальной скоростью.
Но таким быть фу, заподлостроением пусть школьники занимаются. Мы с вами взрослые и ответственные ребята. Правда? )
Ладно, рад всех видеть. Всем хорошей рабочей недели!
tags: #nginx #networks
—
💩 @bashdays
Но сегодня не про это. Сегодня про злоумышленников, которые методом тыка пытаются найти и украсть бэкап. Зачастую бэкапы хранятся в папках проекта, либо вообще в корне пылятся годами.
Как это бывает: переезжаешь на другой сервер, перетащил проект в zip архиве, распаковал, а сам zip не удалил. И теперь любой кто узнает имя архива, сможет его скачать, со всеми паролями и явками. Ну либо как в распространенных движках, есть всем известная папка, где могут находиться эти бэкапы.
Вообще руками имена файлов никто не подбирает, для этого есть специальный софт, который просто брутфорсит по словарю всевозможные локейшены и если получает статус 200, то скачивает всё, что плохо лежит.
Как с этим бороться? Ничего не бэкапить в папки проекта, удалять промежуточные файлы если что-то переносил, настраивать политики nginx чтобы 403 отдавал и т.п.
Но есть способ сделать простой ханипот. Злоумышленник якобы находит бэкап, получает статус 200 и начинает его скачивать. Естественно это не бэкап, а специально подготовленный файл большого размера. Причем такой файл отдается специально с пониженной скоростью и санкциями.
Повторюсь, маловероятно, что злоумышленник это человек. В основном сбором бигдаты занимается автоматизированный софт. Устанавливается на уже скомпрометированные машины, с которых осуществляется сканирование каталогов на наличие плохо лежащих файлов.
Давай настроем такой ханипот на примере nginx
Добавляем в nginx конфиги:
location ~* "^/(new|old|bkup|tmp|temp|upload|ftp|sql|file|www|drupal|joomla|wordpress|x|user|admin|a|b|r|rezerv|arch|arx|111|archive|auth|backup|clients|com|dat|dump|engine|files|home|html|index|master|media|my|mysql|old|site|sql|website|wordpress)\.tar.gz$" {
access_log /var/log/nginx/honeypot.log;
default_type application/zip;
root /var/www/bashdayz/files/backup;
rewrite ^(.*)$ /backup break;
max_ranges 0;
limit_rate 4k;
limit_conn addr 1;
}
# а это в секцию http
limit_conn_zone $binary_remote_addr zone=addr:10m;Указываем список на что будем триггериться. Ограничиваем скорость, ограничиваем число потоков, запрещаем докачку.
Создаем файл затычку размером 1гиг, этого вполне хватит. Но можешь конечно сделать и больше.
dd if=/dev/zero of=/var/www/bashdayz/files/backup bs=1G count=1
Вот и всё. Теперь если кто-то попытается вытянуть у тебя бэкап к примеру mysql.tar.gz, то будет страдать. Идея думаю тебе понятна, вокруг нее можно городить вообще сумасшедшие схемы. Но опять же это всего лишь концепт, из которого можно сделать что-то большое и нужное.
Я одно время применял этот способ в случае, когда коллеги просят выдать бэкап базы. Обычно я даю прямую ссылку на скачивание. Но бывают ситуации, когда разработчики ведут себя как зажравшиеся ЧСВешные мудаки. И на такой случай у меня для них была специальная ссылка для скачивания бэкапа.
Ничего особенного, но с сюрпризом, бэкап никогда не скачается. Тащить 10 гигабайт со скоростью dial-up ну такое себе. А когда те начинали орать как свинья из avp, мой ответ был простой - проблема на твоей стороне. У меня видишь все работает и показываю скриншот с нормальной скоростью.
Но таким быть фу, заподлостроением пусть школьники занимаются. Мы с вами взрослые и ответственные ребята. Правда? )
Ладно, рад всех видеть. Всем хорошей рабочей недели!
tags: #nginx #networks
—
Please open Telegram to view this post
VIEW IN TELEGRAM
Event loop из семи залуп.
✔️ Сегодня запускаем bash скрипт из nginx по локейшену.
Идея такая, при открытии урла в браузере
А зачем это нужно? Элементарно — чтобы запустить Bash скрипт!
Но никогда так не делай.
Чтобы подобное реализовать, тебе понадобится
Я возьму
Ставим врапер:
Закидываем скрипт в
В конфиге nginx городим локейшен:
Заранее убедись что сокет
Открываем
Но это еще не все. В папке
Для
Я этот код не проверял, он всяко не работает, на коленке накидал, но думаю главное тут суть.
Кстати через php наверное тоже можно башник дернуть, там сокет так же подкинуть и через «хуй-пизда-лопата» запустить скрипт.
Вообще промышлять таким - фу! Если ты кому-то расскажешь, то тебя выгонят ссаными тряпками. Всё чисто ради экспериментов. Изучай!
tags: #linux #nginx #bash
@ВАSНDАYS | BАSHDАYS.CОM
Идея такая, при открытии урла в браузере
https://bashdays.com/bashdays.sh запускается bash скрипт, который лежит на сервере в папке /tmp/bashdays.sh.А зачем это нужно? Элементарно — чтобы запустить Bash скрипт!
Но никогда так не делай.
Чтобы подобное реализовать, тебе понадобится
fcgiwrap либо lua. Из обычного nginx, который в коробке, это сделать невозможно. Политика безопасности, вся хуйня.Я возьму
fcgiwrap, не хочу компилить модуль lua. Если у тебя есть lua, можешь через него подобное реализовать. Примеры ниже.Ставим врапер:
apt install fcgiwrap
Закидываем скрипт в
/tmp/bashdays.sh#!/bin/bash
echo "Content-type: text/html"
echo ""
echo "<h1>Hello Bashdays</h1>"
echo "<p>This is a test bash script.</p>"
echo "hello bashdays" > file.txt
В конфиге nginx городим локейшен:
location /bashdays.sh {
fastcgi_pass unix:/var/run/fcgiwrap.socket;
fastcgi_param SCRIPT_FILENAME /tmp/bashdays.sh;
include fastcgi_params;
}Заранее убедись что сокет
fcgiwrap создался и лежит в нужном месте. На этом собственно всё. Да, надо сделать еще nginx reload.Открываем
https://bashdays.com/bashdays.sh и лицезрим «Hello Bashdays This is a test bash script.».Но это еще не все. В папке
/tmp появился файл file.txt. Как видишь все получилось. Дальше включай фантазию и твори.Для
lua это будет выглядеть как-то так:
location /bashdays.sh {
content_by_lua_block {
os.execute("/tmp/bashdays.sh")
}
}
Я этот код не проверял, он всяко не работает, на коленке накидал, но думаю главное тут суть.
Кстати через php наверное тоже можно башник дернуть, там сокет так же подкинуть и через «хуй-пизда-лопата» запустить скрипт.
Вообще промышлять таким - фу! Если ты кому-то расскажешь, то тебя выгонят ссаными тряпками. Всё чисто ради экспериментов. Изучай!
tags: #linux #nginx #bash
@ВАSНDАYS | BАSHDАYS.CОM
Please open Telegram to view this post
VIEW IN TELEGRAM
Здрасти мои хорошие!
Рассмотрим ситуацию — злодеи устроили нагрузочное тестирование и натравили на твой ламповый стартап какой-нибудь «яндекс-танк».
ㅤ
😲 Подключить DDosGuard или Кратор!
Эт я пеню, ценник на такие услуги — моё почтение, да и по функционалу там очень даже всё урезано. А cloudflare по регламенту компании запрещен. Замкнутый круг.
Ну так что делать то?
Да блядь nginx затюнить и отбить всю эту хуйню-муйню. Понятно дело оно особо при дидосах не спасет, но со сканерами и «танками» заебись справится.
В nginx есть параметр
Поехали настраивать.
Создаем файл
Для рейта есть такая табличка:
тестируем так:
И смотрим нет ли ошибок 503 Слишком дохуя запросов и корректно ли отрабатывает лимит.
🅰️ 🅰️
Сука! А как рассчитать эту 20m памяти? Щаа…
Пардон, хуйню сморозил, давай на котиках:
То есть, зона
А откуда взялось 128?
Как я написал выше nginx хранит каждого уникального клиента (ключ
Есть такая табличка:
Да, еще можно настроить
Например:
Клиенту разрешается до 400 мгновенных запросов, а затем он попадает в ограничение 200r/s.
Теперь по мапингам и гео хуйне.
В первом блоке про гео:
1. Все пользователи получат
2. Те, кто с
Во втором блоке про мапинг:
1. Если
2. Если
Короче делаем что-то вроде белого списка и кто в него не входит — идёт нахуй! Надеюсь понятно объяснил.
Теперь чтобы вся эта поебота заработала, нужно прописать в нужный локейшен:
Ну а чтобы отдавать нужный статус при достижении лимита, делаем:
Возвращаем 429 Слишком дохуя запросов, вместо стандартного 503.
Бездумно это настраивать не советую, могут пострадать обычные пользователи, а вот если всё вдумчиво сделать — спасешь свой стартап от злых писек.
➡️ Ну и сыпь в комменты свои варианты!
tags: #nginx #devops #security
—
🔔 @bashdays➡️ @gitgate
Рассмотрим ситуацию — злодеи устроили нагрузочное тестирование и натравили на твой ламповый стартап какой-нибудь «яндекс-танк».
ㅤ
Эт я пеню, ценник на такие услуги — моё почтение, да и по функционалу там очень даже всё урезано. А cloudflare по регламенту компании запрещен. Замкнутый круг.
Ну так что делать то?
Да блядь nginx затюнить и отбить всю эту хуйню-муйню. Понятно дело оно особо при дидосах не спасет, но со сканерами и «танками» заебись справится.
В nginx есть параметр
limit_req_zone, он то нам и пригодится. Этот параметр ограничивает количество одновременных запросов с одного айпишника.Поехали настраивать.
Создаем файл
/etc/nginx/conf.d/assholes.confgeo $limited {
default 1;
192.168.1.1 0; # Этот IP не лимитируется
10.0.0.0/24 0; # 10.0.0.0/24 тоже без ограничений
}
map $limited $limit {
1 $binary_remote_addr;
0 "";
}
limit_req_zone $limit zone=bashdays:20m rate=200r/s; limit_req_zone - ключ для отслеживания запросов.$binary_remote_addr - системная переменная nginx, внутри хранит ip адрес клиента.zone=bashdays:20m - произвольное имя зоны, 20m это объём памяти в мегабайтах для хранения данных. В этой зоне хранятся данные о количестве запросов от каждого уникального клиента.rate=200r/s - ограничение равное 200 запросов в секунды с одного ip клиента. Для рейта есть такая табличка:
Сценарий rate burst
-------------------------------------------
API с высокой нагрузкой 100r/s 200
Средний веб-сайт 50r/s 100
Анти-DDoS защита 10r/s 20
CDN или кеширующий прокси 500r/s 1000
тестируем так:
ab -n 1000 -c 50 http://bashdays.ru/
wrk -t4 -c100 -d10s http://bashdays.ru/
И смотрим нет ли ошибок 503 Слишком дохуя запросов и корректно ли отрабатывает лимит.
Сука! А как рассчитать эту 20m памяти? Щаа…
Максимальное количество клиентов = размер зоны в байтах / размерзаписинаклиента
Пардон, хуйню сморозил, давай на котиках:
Пример расчёта для 20m (20 мегабайт = 20 × 1024 × 1024 = 20 971 520 байт):
20 971 520 / 128 = 163 840
То есть, зона
20m может хранить лимиты примерно для 163 тысяч уникальных клиентов одновременно.А откуда взялось 128?
Как я написал выше nginx хранит каждого уникального клиента (ключ
$binary_remote_addr или другое значение) в зоне, используя примерно 128 байт на запись.Есть такая табличка:
< 20 000 = 4m
~80 000 = 10m
~160 000 = 20m
500 000+ = 64m
Да, еще можно настроить
burst для резких пиков. burst позволяет временно превышать rate, прежде чем включится жёсткий лимит.Например:
limit_req zone=bashdays burst=400 nodelay;
Клиенту разрешается до 400 мгновенных запросов, а затем он попадает в ограничение 200r/s.
nodelay означает, что первые 400 запросов проходят сразу, а потом начинается строгий лимит.Теперь по мапингам и гео хуйне.
В первом блоке про гео:
1. Все пользователи получат
$limited = 1 (по умолчанию).2. Те, кто с
192.168.1.1 или из 10.0.0.0/24, получат $limited = 0 и не будут ограничены.Во втором блоке про мапинг:
1. Если
$limited = 1, то $limit = $binary_remote_addr (IP-адрес клиента).2. Если
$limited = 0, то $limit = "", и клиент не попадает в limit_req_zone.
Короче делаем что-то вроде белого списка и кто в него не входит — идёт нахуй! Надеюсь понятно объяснил.
Теперь чтобы вся эта поебота заработала, нужно прописать в нужный локейшен:
location / {
limit_req zone=bashdays burst=10 nodelay;
try_files $uri $uri/ /index.php?$args;
} Про burst и nodelay выше уже рассказывал.
Ну а чтобы отдавать нужный статус при достижении лимита, делаем:
location / {
limit_req_status 429;
limit_req zone=bashdays burst=10 nodelay;
try_files $uri $uri/ /index.php?$args;
}Возвращаем 429 Слишком дохуя запросов, вместо стандартного 503.
Бездумно это настраивать не советую, могут пострадать обычные пользователи, а вот если всё вдумчиво сделать — спасешь свой стартап от злых писек.
tags: #nginx #devops #security
—
Please open Telegram to view this post
VIEW IN TELEGRAM
Очередные грабли на которые в LF многие наступили.
ㅤ
Есть nginx с такой конфигурацией:
И есть приложение:
Плюс к нему Dockerfile:
Собираем и запускаем контейнер:
Идем в браузере на
Важно! Уже по этой ошибке можно сделать какие-то выводы, эт не стандартная ошибка от nginx, а значит запрос отлично доходит до приложения. Но где-то внутри приложения теряется. Тренируй насмотренность, у nginx ошибки обычно по центру выводятся, а тут align вправо.
Еще как вариант, можешь остановить контейнер и еще раз в браузере тыкнуться, если получишь 502 Плохой шлюх, то значит что nginx нормально всё у тебя передает запросы на Flask. Но где-то внутри Flask происходит какое-то гавнище.
А что случилось? Всёж верно? Локейшен в nginx прописан, прокси-пасс тоже присутствует, где ответ от приложения?
Все дело в слэшах!
В конце порта 5000 ставим слэш и проверяем. Хуяк и оно начинает работать!
Что вообще происходит?
Когда мы делаем локейшен без последнего слэша в прокси-пассе, nginx проксирует запросы на приложение без изменения пути.
То есть приложение
А когда мы добавляем слэш, nginx добавляет путь после
Короче опять заумно расписал, давай снова на котиках!
➡️ Без слэша запрос
➡️ С слэшем запрос
В общем с конечным слэшем nginx «удаляет» часть пути
Вот и вся наука. Грабли прям жизненные и порой доставляют проблемы с многочасовым дебагом.
Так что держи это в голове, если с виду вроде все правильно, но не работает, пиздани в конце слэш, типа метод тыка.
Вечерком еще чтива подвезу, случайно набрал интеграций, теперь отдуваюсь.
tags: #nginx #devops #linuxfactory
—
🔔 @bashdays➡️ @gitgate
ㅤ
Есть nginx с такой конфигурацией:
server {
listen 80;
server_name _;
location /app {
proxy_pass http://localhost:5000;
}
}И есть приложение:
from flask import
Flask app = Flask(__name__)
@app.route('/')
def hello():
return 'Привет, Linux Factory!'
if __name__ == '__main__':
app.run(host='0.0.0.0', debug=True)
Плюс к нему Dockerfile:
FROM python:3.8-slim
WORKDIR /app COPY .
/app RUN pip install -r requirements.txt
EXPOSE 5000
CMD ["python", "app.py"]
Собираем и запускаем контейнер:
docker build -t bashdays .
docker run -d -p 5000:5000 bashdays
Идем в браузере на
http://bashdays.ru/app и получаем хуй с маслом:Not Found. The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again.
Важно! Уже по этой ошибке можно сделать какие-то выводы, эт не стандартная ошибка от nginx, а значит запрос отлично доходит до приложения. Но где-то внутри приложения теряется. Тренируй насмотренность, у nginx ошибки обычно по центру выводятся, а тут align вправо.
Еще как вариант, можешь остановить контейнер и еще раз в браузере тыкнуться, если получишь 502 Плохой шлюх, то значит что nginx нормально всё у тебя передает запросы на Flask. Но где-то внутри Flask происходит какое-то гавнище.
А что случилось? Всёж верно? Локейшен в nginx прописан, прокси-пасс тоже присутствует, где ответ от приложения?
Все дело в слэшах!
location /app {
proxy_pass http://localhost:5000/;
}В конце порта 5000 ставим слэш и проверяем. Хуяк и оно начинает работать!
Что вообще происходит?
Когда мы делаем локейшен без последнего слэша в прокси-пассе, nginx проксирует запросы на приложение без изменения пути.
То есть приложение
app.py получает роут /app а его там естественно нет. А есть просто корень /.А когда мы добавляем слэш, nginx добавляет путь после
/app к целевому урлу.Короче опять заумно расписал, давай снова на котиках!
/app проксируется на http://localhost:5000/app, что не совпадает с маршрутом, настроенным в Flask./app проксируется на http://localhost:5000, и приложение Flask обслуживает его как корневой путь /.В общем с конечным слэшем nginx «удаляет» часть пути
/app и отправляет запрос на корень приложения Flask.Вот и вся наука. Грабли прям жизненные и порой доставляют проблемы с многочасовым дебагом.
Так что держи это в голове, если с виду вроде все правильно, но не работает, пиздани в конце слэш, типа метод тыка.
Вечерком еще чтива подвезу, случайно набрал интеграций, теперь отдуваюсь.
tags: #nginx #devops #linuxfactory
—
Please open Telegram to view this post
VIEW IN TELEGRAM
Вчера многие обратили внимание на конструкцию в nginx:
Что это блядь за «чёрточка» вместо сервер_нейма?
ㅤ
Если техническим языком — это подстановочное имя хоста.
Пусть на сервере прописано так:
Если в браузере откроем
А как получить 444, тот самый с «чёрточкой»?
Просто! Например, зайти на сервер по его IP адресу. Nginx не сможет сопоставить доменные имена, которые прописаны в конфиге и отдаст статус 444.
То есть «чёрточка» это что-то типа заглушки. Nginx не воспринимает его как специальный символ, это обычное имя хоста, которое можно использовать для обработки запросов, не соответствующих другим явно указанным доменам.
Обычно эту «чёрточку» прописывают в файле defaults, чтобы тем, кто попал на сервер по IP адресу увидел, то что ты захочешь, а не рандомный сайт который у тебя висит на сервере.
Короче если запрос приходит с именем хоста, которое не совпадает ни с одним из явно прописанных
А в сочетании с
Если «чёрточка» не используется, то вместо неё можно просто прописать
Вот так вот и живём, изучай!
tags: #nginx #devops #linuxfactory
—
🔔 @bashdays➡️ @gitgate
server_name _;
Что это блядь за «чёрточка» вместо сервер_нейма?
ㅤ
Если техническим языком — это подстановочное имя хоста.
Пусть на сервере прописано так:
server {
listen 80;
server_name _;
return 444;
}
server {
listen 80;
server_name bashdays.ru;
return 200;
}
server {
listen 80;
server_name linuxfactory.ru;
return 200;
}Если в браузере откроем
bashdays.ru или linuxfactory.ru, то получим статус 200.А как получить 444, тот самый с «чёрточкой»?
Просто! Например, зайти на сервер по его IP адресу. Nginx не сможет сопоставить доменные имена, которые прописаны в конфиге и отдаст статус 444.
То есть «чёрточка» это что-то типа заглушки. Nginx не воспринимает его как специальный символ, это обычное имя хоста, которое можно использовать для обработки запросов, не соответствующих другим явно указанным доменам.
Обычно эту «чёрточку» прописывают в файле defaults, чтобы тем, кто попал на сервер по IP адресу увидел, то что ты захочешь, а не рандомный сайт который у тебя висит на сервере.
Короче если запрос приходит с именем хоста, которое не совпадает ни с одним из явно прописанных
server_name, то он будет обрабатываться этим серверным блоком.А в сочетании с
return 444 (No Response) используется для закрытия нежелательных запросов или для обработки некорректных запросов.Если «чёрточка» не используется, то вместо неё можно просто прописать
default_server в директиве listen, и блок будет работать аналогично.server {
listen 80 default_server;
return 444;
}Символ _ не имеет специального значения в самом Nginx. Это просто удобное соглашение, принятое сообществом.
Вот так вот и живём, изучай!
tags: #nginx #devops #linuxfactory
—
Please open Telegram to view this post
VIEW IN TELEGRAM
1 80
Ребята с LF порой интересуются — а нахуя в nginx нужна поддержка lua? Можно какой-то пример, но только не Hello World?
ㅤ
Конечно можно!
Понадобилось мне как-то реализовать продвинутый basic auth, чтобы nginx сходил в mysql базу и сопоставил введенные учетные данные.
А как блядь это сделать?
Тут-то и пригодится Lua!
Для начала создаем базу (nginx_auth) и табличку users. Ну и в ней колонки username и password. В username храним имя пользователя, в password захэшированный пароль:
Эту команду выполняешь в mysql, в ответ он выплюнет тебе хэш, его и нужно будет заебенить в колонку password.
Дальше конфигуряем nginx:
Ну и сам скрипт кидаем в
Всё! Релоадим nginx и получаем прокаченный Basic Auth.
Теперь nginx лезет в базу и при успешном исходе кидает пользователя в локейшен
Да, скрипт работает на mariadb. Для всяких перкон и т.п. возможно нужно будет переделать SELECT.
Вот такие пироги, вот тебе и заебачее применение Lua!
➡️ Кстати, если увидел вектор атаки, поделись в комментах.
tags: #linux #devops #lua #nginx
—
🔔 @bashdays➡️ @gitgate
ㅤ
Конечно можно!
Понадобилось мне как-то реализовать продвинутый basic auth, чтобы nginx сходил в mysql базу и сопоставил введенные учетные данные.
А как блядь это сделать?
Тут-то и пригодится Lua!
Для начала создаем базу (nginx_auth) и табличку users. Ну и в ней колонки username и password. В username храним имя пользователя, в password захэшированный пароль:
SHA1('$UpperPa$$word')Эту команду выполняешь в mysql, в ответ он выплюнет тебе хэш, его и нужно будет заебенить в колонку password.
Дальше конфигуряем nginx:
location / {
content_by_lua_file /etc/nginx/lua/auth.lua;
}
location @authenticated {
root /var/www/bashdays/htdocs/site;
index index.html;
}В nginx само собой добавляем модуль Lua, Как его собрать можешь в гугле посмотреть, ну либо взять какойнить openresty.
Ну и сам скрипт кидаем в
/etc/nginx/lua/auth.lua;local mysql = require "resty.mysql"
local sha1 = require "resty.sha1"
local resty_string = require "resty.string"
local db, err = mysql:new()
-- Установка таймаута
if not db then
ngx.log(ngx.ERR, "failed to create mysql object: ", err)
return ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR)
end
db:set_timeout(1000)
-- Подключение к базе данных
local res, err = db:connect{
host = "db",
port = 3306,
database = "nginx_auth",
user = "nginx_user",
password = "password",
charset = "utf8",
}
if not res then
ngx.log(ngx.ERR, "failed to connect to MySQL: ", err)
return ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR)
end
-- Извлекаем данные из заголовков Authorization
local auth = ngx.var.http_authorization
if not auth or not auth:find("Basic ") then
ngx.header["WWW-Authenticate"] = 'Basic realm="Restricted Area"'
return ngx.exit(ngx.HTTP_UNAUTHORIZED)
end
-- Парсим Basic Auth заголовок
local encoded = auth:sub(7) -- Убираем "Basic " из начала
local decoded = ngx.decode_base64(encoded)
if not decoded then
ngx.header["WWW-Authenticate"] = 'Basic realm="Restricted Area"'
return ngx.exit(ngx.HTTP_UNAUTHORIZED)
end
-- Разделяем строку на имя пользователя и пароль
local username, password = decoded:match("([^:]+):(.+)")
if not username or not password then
ngx.header["WWW-Authenticate"] = 'Basic realm="Restricted Area"'
return ngx.exit(ngx.HTTP_UNAUTHORIZED)
end
-- Хешируем пароль
local sha1_obj = sha1:new()
sha1_obj:update(password)
local password_hash = resty_string.to_hex(sha1_obj:final())
-- Проверяем пользователя и пароль в базе данных
local sql = string.format("SELECT * FROM users WHERE username = '%s' AND password = '%s'", username, password_hash)
local res, err = db:query(sql)
if not res or #res == 0 then
ngx.header["WWW-Authenticate"] = 'Basic realm="Restricted Area"'
return ngx.exit(ngx.HTTP_UNAUTHORIZED)
end
-- Передаем управление Nginx для загрузки страницы
ngx.exec("@authenticated")
Всё! Релоадим nginx и получаем прокаченный Basic Auth.
Сам скрипт не претендует на совершенство и очень простой, объяснять его не вижу смысла. Пробегись глазами и всё сам поймешь.
Теперь nginx лезет в базу и при успешном исходе кидает пользователя в локейшен
@authenticated.Да, скрипт работает на mariadb. Для всяких перкон и т.п. возможно нужно будет переделать SELECT.
Вот такие пироги, вот тебе и заебачее применение Lua!
tags: #linux #devops #lua #nginx
—
Please open Telegram to view this post
VIEW IN TELEGRAM
This media is not supported in your browser
VIEW IN TELEGRAM
Про яйца и балансировщик нагрузки
Когда нужно распределить запросы между серверами, возникает проблема — а как блядь понять, какой сервер сейчас менее нагружен?
ㅤ
Постоянно опрашивать сервера, это хуйня, информация будет не актуальной, все это медленно, пока мы собирали данные, ситуация уже поменялась.
На этом фоне возникает эффект «стада», когда много запросов дружно бегут туда, где вроде бы свободно и по итогу перегружают сервер еще больше.
Это можно решить проще — например перенаправлять запросы случайно.
Работает это вроде неплохо, но опять же всегда есть шанс, что нагрузка будет неравномерной. И снова получаем, что какой-то из серверов будет перегружен запросами.
Какой-то замкнутый круг, печаль и говнище.
А чё делать?
Представь: я в рандоме выбираю два сервера, смотрю какой из них менее загружен и отправляю туда запросы. Все!
Вроде мелочь, но работает этот подход прям заебись! И что интересно у этого подхода есть официальная формулировка — Power of Two Choices или «Сила двух выборов».
Почему это заебись?
На просторах есть задачка «яйца и корзины», в оригинале там конечно не «яйца», а шары.
Короче. Мы случайно кидаем яйца в корзины. Если класть каждое яйцо в случайную корзину, то в итоге некоторые корзины будут переполнены.
Но если каждый раз выбирать две корзины и класть яйцо туда, где их меньше — ситуация резко улучшается.
Максимальная перегрузка корзины падает в разы. И это при том, что мы по-прежнему делаем случайный выбор, просто из двух вариантов, а не из одного.
Все просто! Тоже самое и с серверами:
- Если мы выбираем сервер наугад, нагрузка на сервер может стать критической.
- Если выбираем между двумя, вероятность перегрузить сервер падает квадратично.
Давай на котиках:
Представь, что у тебя есть куча серверов, и на четверти из них пришло по 4 запроса.
- Если я выбираю сервер случайно, есть 25% шанс попасть именно на сервер, которому уже пезда.
- Если я выбираю два сервера и беру менее загруженный — вероятность того, что оба окажутся с нагрузкой 4, уже всего 6,25% (1/16).
Получается, что вероятность перегрузки падает очень быстро. А дальше — ещё быстрее: чтобы нагрузка выросла до 5, 6 и так далее, нужно каждый раз «удачно» попасть в редкие перегруженные сервера, и шанс становится ничтожным.
Видишь, математика нужна не только бекендерам, но и в девопсе можно применить.
Что получаем на практике:
На практике балансировка «выбором из двух» делает распределение нагрузки по серверам почти равномерной. При этом мы не тратим кучу ресурсов на мониторинг и не пытаемся каждый раз точно узнать состояние всех серверов.
Такой подход - простой и элегантный. Как говорится — без хуйни!
Формулы и расчеты визуально можешь глянуть тут. Там как раз разбирается способ с яйцами, но уже с углубленной математикой и формулами.
Как реализовать в nginx
Вместо случайного выбора
Мотай на ус, глядишь сгодится в хозяйстве.
🛠 #devops #nginx
—
✅ @bashdays ✅ @linuxfactory ✅ @blog
Когда нужно распределить запросы между серверами, возникает проблема — а как блядь понять, какой сервер сейчас менее нагружен?
ㅤ
Постоянно опрашивать сервера, это хуйня, информация будет не актуальной, все это медленно, пока мы собирали данные, ситуация уже поменялась.
На этом фоне возникает эффект «стада», когда много запросов дружно бегут туда, где вроде бы свободно и по итогу перегружают сервер еще больше.
Это можно решить проще — например перенаправлять запросы случайно.
Работает это вроде неплохо, но опять же всегда есть шанс, что нагрузка будет неравномерной. И снова получаем, что какой-то из серверов будет перегружен запросами.
Какой-то замкнутый круг, печаль и говнище.
А чё делать?
Представь: я в рандоме выбираю два сервера, смотрю какой из них менее загружен и отправляю туда запросы. Все!
Вроде мелочь, но работает этот подход прям заебись! И что интересно у этого подхода есть официальная формулировка — Power of Two Choices или «Сила двух выборов».
Почему это заебись?
На просторах есть задачка «яйца и корзины», в оригинале там конечно не «яйца», а шары.
Короче. Мы случайно кидаем яйца в корзины. Если класть каждое яйцо в случайную корзину, то в итоге некоторые корзины будут переполнены.
Но если каждый раз выбирать две корзины и класть яйцо туда, где их меньше — ситуация резко улучшается.
Максимальная перегрузка корзины падает в разы. И это при том, что мы по-прежнему делаем случайный выбор, просто из двух вариантов, а не из одного.
Все просто! Тоже самое и с серверами:
- Если мы выбираем сервер наугад, нагрузка на сервер может стать критической.
- Если выбираем между двумя, вероятность перегрузить сервер падает квадратично.
Давай на котиках:
Представь, что у тебя есть куча серверов, и на четверти из них пришло по 4 запроса.
- Если я выбираю сервер случайно, есть 25% шанс попасть именно на сервер, которому уже пезда.
- Если я выбираю два сервера и беру менее загруженный — вероятность того, что оба окажутся с нагрузкой 4, уже всего 6,25% (1/16).
Получается, что вероятность перегрузки падает очень быстро. А дальше — ещё быстрее: чтобы нагрузка выросла до 5, 6 и так далее, нужно каждый раз «удачно» попасть в редкие перегруженные сервера, и шанс становится ничтожным.
Видишь, математика нужна не только бекендерам, но и в девопсе можно применить.
Что получаем на практике:
На практике балансировка «выбором из двух» делает распределение нагрузки по серверам почти равномерной. При этом мы не тратим кучу ресурсов на мониторинг и не пытаемся каждый раз точно узнать состояние всех серверов.
Такой подход - простой и элегантный. Как говорится — без хуйни!
Формулы и расчеты визуально можешь глянуть тут. Там как раз разбирается способ с яйцами, но уже с углубленной математикой и формулами.
Этот же принцип используют, например, в cuckoo hashing (структура данных для хранения ключей).
Cuckoo hashing (кукушкино хеширование) — алгоритм разрешения коллизий значений хеш-функций в таблице с постоянным временем выборки в худшем случае.
Как реализовать в nginx
upstream backend {
random two; # Power of 2 Choices
server app1.bashdays.ru;
server app2.bashdays.ru;
server app3.bashdays.ru;
}Вместо случайного выбора
nginx берёт два случайных сервера и кидает запрос на тот, где меньше соединений.Этот же принцип используют, например, в cuckoo hashing (структура данных для хранения ключей).
Мотай на ус, глядишь сгодится в хозяйстве.
—
Please open Telegram to view this post
VIEW IN TELEGRAM
7 86
Чем глубже пропасть, в которую падаешь, тем больше шансов научиться летать.
На подходе новый закон о глобальном запрете мата в сети, поэтому к нему нужно подготовиться. Переебашивать каждый пост в блоге — проблематично, да и лень.
ㅤ
Поэтому, как обычно, будем изобретать велосипед.
Суть идеи — налету в DOM менять маты на синонимы. То есть в момент отдачи контента, контент будет насильно зацензурен.
А там уже можно будет добавить регулярки и гибко всё затюнить, мало ли, может можно будет звездочками разбавлять такой контент.
Реализация
За основу я возьму angie (форк nginx) с модулем LUA. Я давно на это решение пересел, так как всё из коробки работает, включая генерацию SSL. Не нужно ебстись с компиляций модулей и страдать.
Если LUA не установлен, ставим:
В
В
Ну и создаем файл
Проверяем:
Открываем сайт и видим что все маты зацензурились согласно шаблону в файле
Если всё осталось по-прежнему, скинь кеш, в 99% дело в нем.
Давай разберемся как это работает.
И получаем — блок берёт HTML-страницу, проходит по каждому чанку тела ответа, и заменяет в нём «запрещённые» слова из словаря на синонимы.
Ааа, еще в словаре
Любая буква, цифра или подчёркивание (
Поэтому лучше сделать как-то так:
LUA — сила! Рекомендую хоть раз потыкать, проникнешься и уже не сможешь без этого модуля жить. Костыли клепать милое дело.
Как вариант, позже еще запилю «специальный» заголовок, при передаче которого angie будет отключать цензуру и выводить посты в оригинале.
Ну заебись же! Осталось придумать, как зацензурить 1000 постов в телеге.
🛠 #angie #nginx #tricks
—
✅ @bashdays ✅ @linuxfactory ✅ @blog
На подходе новый закон о глобальном запрете мата в сети, поэтому к нему нужно подготовиться. Переебашивать каждый пост в блоге — проблематично, да и лень.
ㅤ
Поэтому, как обычно, будем изобретать велосипед.
Суть идеи — налету в DOM менять маты на синонимы. То есть в момент отдачи контента, контент будет насильно зацензурен.
Хуйня == Фигня, Пезда == 3.14зда ну и в таком духе.
А там уже можно будет добавить регулярки и гибко всё затюнить, мало ли, может можно будет звездочками разбавлять такой контент.
Реализация
За основу я возьму angie (форк nginx) с модулем LUA. Я давно на это решение пересел, так как всё из коробки работает, включая генерацию SSL. Не нужно ебстись с компиляций модулей и страдать.
Как настроить автополучение SSL в angie, писал в этом посте.
Если LUA не установлен, ставим:
apt install angie-module-lua
В
/etc/angie/angie.conf добавляем:load_module modules/ndk_http_module.so;
load_module modules/ngx_http_lua_module.so;
load_module modules/ngx_stream_lua_module.so;
В
/etc/angie/sites-available/bashdays.ru.conf добавляем в корневой локейшен:location / {
root /var/www/bashdays.ru/htdocs;
index index.html;
gzip off;
body_filter_by_lua_block {
local replacements = dofile("/etc/angie/wordmap.lua")
local chunk = ngx.arg[1]
if chunk then
for _, pair in ipairs(replacements) do
chunk = ngx.re.gsub(chunk, pair[1], pair[2], "ijo")
end
ngx.arg[1] = chunk
end
}
}Ну и создаем файл
/etc/angie/wordmap.lua который будет содержать шаблоны замены:return {
{"хуйня", "фигня"},
{"хуй", "писька"},
{"говн%w*", "ерунда"},
{"еба%w*", "плохой"},
}Проверяем:
angie -t и если всё ок, можно сделать systemctl restart angie.Открываем сайт и видим что все маты зацензурились согласно шаблону в файле
/etc/angie/wordmap.lua.Если всё осталось по-прежнему, скинь кеш, в 99% дело в нем.
Давай разберемся как это работает.
body_filter_by_lua_block — перед отправкой ответа клиенту, запустится Lua-скрипт, который изменит тело ответа.dofile("/etc/angie/wordmap.lua") — загружает Lua-файл со словарём замен.ngx.arg[1] — текущий кусок (chunk) ответа (HTML, JSON и т.п.), который angie собирается отправить клиенту. Ответ приходит потоками.for _, pair in ipairs(replacements) — перебор всех замен из словаря.ngx.re.gsub(chunk, pair[1], pair[2], "ijo") — регулярная замена, [1] что искать, [2] на что заменить."ijo" — флаги: i — без учёта регистра, j — dotall (точка матчится на \n), o — оптимизация.ngx.arg[1] = chunk — возвращаем изменённый кусок, который уйдёт клиенту.И получаем — блок берёт HTML-страницу, проходит по каждому чанку тела ответа, и заменяет в нём «запрещённые» слова из словаря на синонимы.
Ааа, еще в словаре
{"говн%w*", "ерунда"} есть символы %w* это регулярка. Любая буква, цифра или подчёркивание (
[0-9A-Za-z_]). В UTF-8 оно обычно ловит только латиницу, а кириллицу нет.Поэтому лучше сделать как-то так:
{"говн[А-Яа-яЁё]*", "ерунда"}. Короче тут тебе карты в руки, сам натыкай паттерны.LUA — сила! Рекомендую хоть раз потыкать, проникнешься и уже не сможешь без этого модуля жить. Костыли клепать милое дело.
Есть конечно нюансы, например — Если слово вдруг разорвётся между чанками (например, ху в одном чанке и йня в другом) — фильтр его не заменит. Для надёжности нужно буферизовать весь ответ.
Ну и с кириллицей надо вопрос дофиксить, но это я реализую чуть позже. Главное концепт. Всё остальное реализуемо.
Как вариант, позже еще запилю «специальный» заголовок, при передаче которого angie будет отключать цензуру и выводить посты в оригинале.
А можно разработчиков подъебать, пусть ищут в своем коде, почему у них слова странным образом заменяются.
Ну заебись же! Осталось придумать, как зацензурить 1000 постов в телеге.
—
Please open Telegram to view this post
VIEW IN TELEGRAM
13 52