Не судите строго, это моя первая статья, наверное если бы я был гуру Nginx и "Линуха", то скорее всего боли и страданий бы не было.
С чего все началось?
Одним днем мне понадобилось реализовать довольно не тривиальную задачу:
Есть множество сервисов с которых нужно собирать данные для обработки и дальнейшей аналитики, модуль который это все собирает может быть установлен на множество серверов (пока 40, но в горизонте года это 1000), но хочется чтобы все обращения от этих серверов шли на один ip , а с него уже распределялись в зависимости от типа запроса или конечной точки обращения. Условно мы обращаемся к серваку 100.1.2.101 по порту 8080 и просим от него данные о всех домах на определенной территории ,он в свою очередь по заданному сценарию коннектится к определенному proxy (Допустим squid, он нужен так как некоторые api залочены по ip) и через него получает данные из конечного api.
P.S. Данные нельзя хранить на промежуточном сервере, так как они слишком часто обновляются :(
В итоге я решил эту задачу разделить на несколько этапов
Создать proxy сервер
Создать возможность балансировки нагрузки (мне казалось ,что если получиться сделать proxy который будет принимать запрос и пересылать допустим на 300 других proxy, то уже пол дела будет готово)
Создать логику выбора конкретного Proxy. (Я думал ,что это просто , я сильно ошибался, но об этом позже)
Этап 1: Создать proxy сервер (3proxy)
Для начала нужно смириться ,что мне нельзя использовать как ОС Windows, а в линухах я как макака с гранатой. После дня анализа мой выбор пал на 3proxy как на испытуемого и beget как VPS для места тестирования (Vps там стоит от 7р в день, что для тестов очень гуманно) и пак в 300 прокси на стороннем ресурсе, все они залочены на один ip (в инете их множество можете подобрать себе по карману, мне обошлось в 30$, адрес не скажу так как боюсь оно ляжет от хабраэффекта), ОС выбрал ubuntu 20.04 (просто под нее много материалов и статей) и MobaXterm для удобства подключения по SSH (скачать можно с оф сайта или всем известным способом????☠️ на просторах интернета).
3proxy маленький и много умеет, а главное в нем есть parent который позволит мне в дальнейшем обращаться к другим. Итак установка 3proxy:
Обновим пакеты
sudo apt update
sudo apt upgrade
Установим 3proxy
wget https://github.com/z3APA3A/3proxy/releases/download/0.9.4/3proxy-0.9.4.x86_64.deb; dpkg -i 3proxy-0.9.4.x86_64.deb
И все, оно поставилось.
теперь идем править конфиги: /usr/local/3proxy/conf/3proxy.cfg (я это делал в MobaXterm, мне так удобнее)
nscache 65536
nserver 8.8.8.8
nserver 8.8.4.4
config /conf/3proxy.cfg
monitor /conf/3proxy.cfg
log /logs/3proxy-%y%m%d.log D
logformat "%d-%m-%Y %H:%M:%S %U %C:%c %R:%r %O %I %T"
rotate 60
counter /count/3proxy.3cf
users $/conf/passwd
include /conf/counters
include /conf/bandlimiters
nscache 65536
timeouts 1 5 30 60 180 1800 15 60
auth strong
allow *
proxy -n -p4888 -a
flush
allow *
proxy -n -p4890 -a
flush
allow proxyuser
admin -p8080
Тут 3 открытых порта на 4888 и 4890 proxy ,а на 8080 админка с доступом только для пользователя proxyuser
Но теперь нам нужно создать proxyuser для этого нужно вызвать /usr/local/3proxy/conf/add3proxyuser.sh <логин> <пароль> <дневной_лимит_трафика_в_МБ> <ограничение_скорости_в_битах_в_секунду> , но если попробовать сделать это сразу то получим Permission denied, для начало поправим права
cd /usr/local/3proxy/conf/
chmod ug+rwx add3proxyuser.sh
/usr/local/3proxy/conf/add3proxyuser.sh proxyuser proxypass
Мы создали пользователя proxyuser с паролем proxypass. Теперь запускаем 3proxy
systemctl enable 3proxy && service 3proxy start && netstat -tlpn | grep prox
Если какой-то из портов не слушается, то прописываем
ufw allow 4888
ufw allow 4890
ufw allow 8080
Теперь проверим Админку зайдя на ip_Сервера:8080 и введя логин proxyuser и пароль proxypass (ну или то ,что мы указали)
Админка работает, уже хорошо (я ей не пользовался ,но вроде конфиги можно из нее править). Но нас интересует не это :) Попробуем сделать curl запрос
curl -L -I -x http://proxyuser:proxypass@IP_Сервера:4888 https://habr.com
Таки работает, Итак мы получили тот результат который хотели и можно сворачиваться ?! А вот и нет :<
Мы просто поставили 3proxy и настроили его для работы, теперь нужно научить его работать с другими серверами (на тестах это будут proxy его проще всего проверить). Делаем запрос и смотрим что вернет нам сервер по определению IP
curl -L -x http://proxyuser:proxypass@IP_Сервера:4888 https://myip.ru/index_small.php
А вернул он нам IP_Сервера (Помечен зеленым на скрине)
Этап 2 : Создать возможность балансировки нагрузки (3proxy)
У 3proxy есть возможность создавать перенаправления она описана в документации , но есть ряд нюансов(ну или я просто тупой и не сразу до них докумекал). Для теста нам понадобиться какой нибудь proxy server(ага для теста proxy Нужен прокси, вы можете его поднять на другой машине или просто купить на просторах интернета: я выбрал второй вариант).
Итак, у нас есть IP_proxy_Сервера_2 (Красный на скринах) который работает по порту 8085(или другому) и не имеет авторизацию (логин пароль) или имеет (это не принципиально). Для начала нам нужно поменять конфиг файл /usr/local/3proxy/conf/3proxy.cfg и добавить
parent <weight> <type> <ip> <port> <username> <password>
weight - вес или вероятность выбора этого Ip,вес прокси,
type - тип прокси (tcp - перенаправление соединения, может быть только последним в цепочке, http - синоним tcp, connect - HTTP CONNECT/HTTPS прокси, socks4 - SOCKSv4 прокси, socks5 - SOCKSv5 прокси),
ip - IP адрес прокси,
port - порт прокси,
username - имя для авторизации на прокси ,
-
password - пароль для авторизации на прокси.
Логин и пароль можно не указывать если сервер их не требует. Добавим строку parent 1000 connect IP_proxy_Сервера_2 8085 для порта 4890 (внимание ip и порт разделяются пробелом а не ":" как обычно )
nscache 65536
nserver 8.8.8.8
nserver 8.8.4.4
config /conf/3proxy.cfg
monitor /conf/3proxy.cfg
log /logs/3proxy-%y%m%d.log D
logformat "%d-%m-%Y %H:%M:%S %U %C:%c %R:%r %O %I %T"
rotate 60
counter /count/3proxy.3cf
users $/conf/passwd
include /conf/counters
include /conf/bandlimiters
nscache 65536
timeouts 1 5 30 60 180 1800 15 60
auth strong
allow *
proxy -n -p4888 -a
allow *
parent 1000 connect IP_proxy_Сервера_2 8085
proxy -n -p4890 -a
flush
allow proxyuser
admin -p8080
Перезапускаем 3proxy
systemctl restart 3proxy
При перезапуске сервак немного задумывается на секунд 5 (если этого не произошло, то скорее всего в конфиге ошибка)
Теперь проверяем через curl
curl -L -x http://proxyuser:proxypass@ip_Сервера:4888 https://myip.ru/index_small.php
curl -L -x http://proxyuser:proxypass@ip_Сервера:4890 https://myip.ru/index_small.php
Поздравляю при запросе к серверу по порту 4888 возвращает ip_Сервера (Зеленый на скрине), а при запросе по порту 4890 возвращает IP_proxy_Сервера_2 (Красный на скрине).
Теперь мы можем управлять нагрузкой добавляя новые proxy сервера (IP_proxy_Сервера_3, IP_proxy_Сервера_4, IP_proxy_Сервера_5 .... IP_proxy_Сервера_251) через конструкцию parent <weight> <type> <ip> <port> <username> <password>
пример конфига :
nscache 65536
nserver 8.8.8.8
nserver 8.8.4.4
config /conf/3proxy.cfg
monitor /conf/3proxy.cfg
log /logs/3proxy-%y%m%d.log D
logformat "%d-%m-%Y %H:%M:%S %U %C:%c %R:%r %O %I %T"
rotate 60
counter /count/3proxy.3cf
users $/conf/passwd
include /conf/counters
include /conf/bandlimiters
nscache 65536
timeouts 1 5 30 60 180 1800 15 60
auth strong
allow *
proxy -n -p4888 -a
flush
allow *
parent 4 connect IP_proxy_Сервера_2 8085
parent 4 connect IP_proxy_Сервера_3 8085
parent 4 connect IP_proxy_Сервера_4 8085
parent 4 connect IP_proxy_Сервера_5 8085
parent 4 connect IP_proxy_Сервера_6 8085
parent 4 connect IP_proxy_Сервера_7 8085
...
parent 4 connect IP_proxy_Сервера_251 8085
proxy -n -p4890 -a
flush
allow proxyuser
admin -p8080
После каждого изменения конфига не забудьте перезагрузить сервер
systemctl restart 3proxy
Разработчик утверждает :
Вес (от 1 до 1000) задается для каждого прокси. Сумма весов по всем перенаправлениям должна быть кратна 1000. Прокси с весами до 1000 группируются, и при построении цепочки один из них выбирается случайно согласно весу. Длина цепочки определяется из суммарного веса. Например, если суммарный вес цепочки 3000, в цепочке будет 3 звена (хопа).
Но есть нюанс, я пробывал ставить вес 1000 всем, оно так не работает! Я не просто так указал "parent 4 connect IP_proxy_Сервера_7 8085" где 4 это <weight> (вес), сумма всех <weight> (весов) должна равняться 1000. Допустим у вас 300 серверов и вы хотите их применять с равной вероятностью, забудьте так не получится потому что если разделить 1000 на 300 вы получите не целое число, то есть вы можете использовать 250 (вес 4) или 500(вес 2) или 1000(вес 1).
P.S. Возможно поправят или уже поправили, но на момент написания статьи оно работало так )
Этап 3 :Создать логику выбора конкретного Proxy.
Вот тут я столкнулся с «суровой действительностью», 3proxy не умеет создавать сложные сценарии для управления нагрузкой :(
Как вариант можно разбить на разные порты и каждый порт отправлять на свои прокси. Пример конфига ниже
nscache 65536
nserver 8.8.8.8
nserver 8.8.4.4
config /conf/3proxy.cfg
monitor /conf/3proxy.cfg
log /logs/3proxy-%y%m%d.log D
logformat "%d-%m-%Y %H:%M:%S %U %C:%c %R:%r %O %I %T"
rotate 60
counter /count/3proxy.3cf
users $/conf/passwd
include /conf/counters
include /conf/bandlimiters
nscache 65536
timeouts 1 5 30 60 180 1800 15 60
auth strong
allow *
proxy -n -p4888 -a
flush
allow *
parent 500 connect IP_proxy_Сервера_2 8085
parent 500 connect IP_proxy_Сервера_3 8085
proxy -n -p4890 -a
flush
allow *
parent 500 connect IP_proxy_Сервера_4 8085
parent 500 connect IP_proxy_Сервера_5 8085
proxy -n -p4891 -a
flush
allow *
parent 500 connect IP_proxy_Сервера_6 8085
parent 500 connect IP_proxy_Сервера_7 8085
proxy -n -p4892 -a
flush
allow proxyuser
admin -p8080
Но это не решение, а костыль. Буду копать дальше в сторону Nginx forward proxy (статья по нему уже пишется)
Всем спасибо, за критику буду благодарен :-)
UPD. Народ пишет ,что Nginx не умеет в Forward proxy и что на нем такую задачу не решить. Хотелось внести ясности:
У Nginx есть модули для forward proxy и модули lua для обработки , ясно что на стандарте никто делать не будет, а будет собирать Nginx отдельно для этого, именно этим я сейчас и занят
Модули:
https://github.com/chobits/ngx_http_proxy_connect_module
https://www.nginx.com/resources/wiki/modules/lua/
Комментарии (33)
A1EF
17.06.2023 21:27+1sudo apt update
sudo apt upgrade
Если система свежеустановленная, то вместо
apt upgrade
лучше сделатьapt full-upgrade
.cd /usr/local/3proxy/conf/
chmod ug+rwx add3proxyuser.sh
/usr/local/3proxy/conf/add3proxyuser.sh proxyuser proxypass
Странно, что issue про это закрыт с сообщением об исправлении проблемы в версии
0.9.4
. Но вообще достаточно было дать прав на запуск, права на запись тут избыточны.systemctl enable 3proxy && service 3proxy start && netstat -tlpn | grep prox
Можно одной командой включить и запустить systemd-юнит:
systemctl enable --now 3proxy
net-tools
давно считается deprecated, на свежей системе его может уже и вовсе не оказаться. Стоит использовать актуальныйiproute2
, где заменойnetstat -tlpn
будет командаss -ntlp
.curl -L -x http://proxyuser:proxypass@IP_Сервера:4888 https://myip.ru/index_small.php
Мелочь, но есть ресурсы с более приятным выводом в консоли. Тот же https://2ip.ru выведет лишь IP адрес, без всяких html-тегов.
danemon
17.06.2023 21:27А в итоге прокси на nginx так и не попробовал? Я не гуру, но балансирование там вроде поддерживается (сам ещё не пробовал), а редирект на какой-либо адрес в зависимости от приходящего урла там точно есть. Или это будет в следующей статье?
Причем в моем случае оказалось очень удобно что можно через nginx пропустить даже трафик без шифрования и придать ему все прелести HTTPS - превратить его в зашифрованный.
Потом обернуть nginx в контейнер (или сразу взять готовый контейнер), и понеслась.
xngel Автор
17.06.2023 21:27Попробовал, но пока не получается его нормально настроить, как добью его сразу напишу статью
anonymous
17.06.2023 21:27НЛО прилетело и опубликовало эту надпись здесь
danemon
17.06.2023 21:27А зачем вам допы, тем более платные? ))
У меня безопы требуют наоборот отказаться от всех неиспользуемых модулей, а раз так - я вообще посматриваю не просто на тему удалить все сторонние модули, а вообще скомпилировать nginx с нуля со всеми нужными настройками и внести это в пайплайн, осталось лишь добраться и сделать. Материалы на хабре об этом есть ))
savostin
17.06.2023 21:27Данные нельзя хранить на промежуточном сервере, так как они слишком часто обновляются :(
"Слишком часто" - это несколько раз в секунду? Да и в этом случае странный выбор. Имхо для большинства сценариев подойдет демон, который опрашивает все "дома" и отдает уже готовый датасет. В противном случае Вы одним упавшим "домом" завалите всю кухню.
shushu
17.06.2023 21:27xngel Автор
17.06.2023 21:27Звучит многообещающе
A1EF
17.06.2023 21:27Ваша задача достаточно легко решается с использованием любого балансировщика, будь то Nginx, HAProxy и т.п. В моей практике выход через нужный socks5-прокси из пула как раз был сделан с использованием HAProxy: несколько фронтендов (разные порты) для подключения клиентов и соответствующие бекенды (наборы проксей по странам, например) для выхода с балансировщика.
xngel Автор
17.06.2023 21:27Я уже мучаю nginx, но очень заинтересовал haproxy попробую и его посмотреть) спасибо за информацию
Karroplan
17.06.2023 21:27что-то, мне кажется, вы сильно не понимаете, что такое прокси.
есть forward proxy: это софтина перенаправляет запросы от пользователей к серверам в интернет. То есть, в браузере у пользователя вы явно настраиваете адрес прокси (ни или curl -x) и браузер идет к проксе и говорит "дай мне страничку", а прокси устанавливает новое соединения, возможно с другого интерфейса, получает страничку и перекладывает ее в пользовательское соединение. Это - 3proxy, squid, tinyproxy, etc...
есть reverse proxy который ставится в обратную сторону. Это по сути обычный веб-сервер принимающий запросы от пользователей из интернета и перенапавляющий их другим веб-серверам. Это - nginx, haproxy, traefik, apache, etc.
вы в своей задаче в посте описываете обычный каскадированный forward proxy и продукт берете соответствующий. А в комментах вам советуют reverse proxy и вы пишите - пробую, интересно, но ничего не выходит. И не выйдет: ngnix и haproxy - это reverse proxy, они для другого. У forward proxy и reverse proxy (web server, по-факту) даже формат get запроса разный:
https://www.oreilly.com/library/view/http-the-definitive/1565925092/ch06s05.html
xngel Автор
17.06.2023 21:27У Nginx есть модули для forward proxy и модули lua для обработки , ясно что на стандарте никто делать не будет, а будет собирать Nginx отдельно для этого
Karroplan
17.06.2023 21:27ну то есть вы предлагаете вместо того чтоб взять просто squid засесть за пересборку или вообще за программирование? ну так в принципе и хлеб напильником можно резать, да )
xngel Автор
17.06.2023 21:27Squid не решит задачу, пробовали уже) если бы не стояло ограничение на ос то я мог бы и написать данный инструмент, а в сборке не вижу ничего страшного, nginx изначально облегчен и все что нужно можно доставить)
Karroplan
17.06.2023 21:27-1nginx и haproxy - НЕ балансировщики ) это reverse proxy. например, из важных функций балансировщика у nginx и haproxy нет возможности кластеризации, т.е. обеспечения отказоустойчивости - надо городить что-то с помщью другого софта типа keepalived, pacemaker и т.п.
F5 LTM, Citrix NetScaler, Kemp - это балансировщики.
A1EF
17.06.2023 21:27+2И ещё, кажется, вы путаете кластеризацию с отказоустойчивость.
Karroplan
17.06.2023 21:27кластер - это несколько узлов выполняющих одну задачу. бывают кластеры для повышения производительности общей системы (hadoop), кластер для повышения емкости (кластер гипервизоров), так и кластеры для повышения отказоустойчивости (failover cluster, например у Cisco ASA или MS Failover Cluster).
по поводу балансеров: балансер служит для двух целей - обеспечение бесперебойной работы того что он там балансирует и соответственно сам не должен становиться точкой отказа; распределение нагрузки. Ни nginx, ни haproxy не умеют ничего самостоятельно про второй пункт. А еще ngnix про себя сам думать ничего не может, потому что он F5 ;)
ах, да - кто это сказал, что они best-in-class? хоть кто-то из софтовых решений умеет в аппаратное ускорение шифрования, например?
A1EF
17.06.2023 21:27+2кластер - это несколько узлов выполняющих одну задачу. бывают кластеры для повышения производительности общей системы (hadoop), кластер для повышения емкости (кластер гипервизоров), так и кластеры для повышения отказоустойчивости (failover cluster, например у Cisco ASA или MS Failover Cluster).
Иначе говоря, "кластер" вовсе не тождественен "отказоустойчивому кластеру". И "возможность кластеризации" совсем не тождественна "отказоустойчивости".
балансер служит для двух целей - обеспечение бесперебойной работы того что он там балансирует
Балансер занимается балансировкой нагрузки. Это прям в его названии отражено. Обеспечение отказоустойчивости - это отдельная задача. Вы явно привыкли использовать проприетарные коммерческие продукты, где вам за деньги все функции заботливо уложили в одну коробочку. Что ж, пожалуйста. Только это никак не делает справедливым ваше суждение, что "nginx и haproxy - НЕ балансировщики".
А еще ngnix про себя сам думать ничего не может, потому что он F5 ;)
Ну зайдите по ссылке к скриншоту, посмотрите что за сайт и чей он.
ах, да - кто это сказал, что они best-in-class? хоть кто-то из софтовых решений умеет в аппаратное ускорение шифрования, например?
Спрашивать про аппаратное ускорение шифрования софтверных решений? Вы это серьезно?
Neveil
17.06.2023 21:27Не понял задачу. Опишите пожалуйста подробнее.
«Условно мы обращаемся к серваку 100.1.2.101 по порту 8080 и просим от него данные о всех домах на определенной территории ,он в свою очередь по заданному сценарию коннектится к определенному proxy»
Какая логика выбора сервера? Мы обращаемся снаружи и запрашиваем данные с одного из агентов?
Bkmz
Рекомендую посмотреть на https://github.com/nadoo/glider
xngel Автор
Спасибо, гляну
xngel Автор
Очень интересная штука, покручу и её, возможно получиться (если получу адекватный результат, то тоже статью напишу)