Pull to refresh

От 3proxy до Nginx forward proxy через боль и страдания (Часть первая 3proxy)

Level of difficultyEasy
Reading time7 min
Views9.4K

Не судите строго, это моя первая статья, наверное если бы я был гуру Nginx и "Линуха", то скорее всего боли и страданий бы не было.

С чего все началось?

Одним днем мне понадобилось реализовать довольно не тривиальную задачу:

Есть множество сервисов с которых нужно собирать данные для обработки и дальнейшей аналитики, модуль который это все собирает может быть установлен на множество серверов (пока 40, но в горизонте года это 1000), но хочется чтобы все обращения от этих серверов шли на один ip , а с него уже распределялись в зависимости от типа запроса или конечной точки обращения. Условно мы обращаемся к серваку 100.1.2.101 по порту 8080 и просим от него данные о всех домах на определенной территории ,он в свою очередь по заданному сценарию коннектится к определенному proxy (Допустим squid, он нужен так как некоторые api залочены по ip) и через него получает данные из конечного api.

P.S. Данные нельзя хранить на промежуточном сервере, так как они слишком часто обновляются :(

В итоге я решил эту задачу разделить на несколько этапов

  1. Создать proxy сервер

  2. Создать возможность балансировки нагрузки (мне казалось ,что если получиться сделать proxy который будет принимать запрос и пересылать допустим на 300 других proxy, то уже пол дела будет готово)

  3. Создать логику выбора конкретного 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/

Tags:
Hubs:
Total votes 7: ↑4 and ↓3+4
Comments35

Articles