С чего всё начиналось
Ты как специалист в области IT, после февральских событий скорее всего столкнулся с проблемой недоступности некоторых ресурсов и наверняка подумал о том, как это дело обойти. Но использовать "бесплатный" или сторонний сервис кажется небезопасным или не даёт нужную ширину канала. У тебя есть навыки работы с Linux и свой сервер где нибудь за бугром. Почему бы собственно говоря не сделать свой прямой прокси?
Скорее всего ты посмотришь в сторону SOCKS5 сервера и даже запустишь его в контейнере, всё будет работать, но при этом если ты используешь Windows + любой браузер с расширением для прокси (я использую Switchy Omega), ты столкнёшься с двумя вариантами:
Ты будешь поднимать SOCKS5 без аутентификации. Следовательно наш прокси будет открыт для всего света и нашедшие его люди могут использовать его по своему усмотрению;
Как умный инженер, ты сделаешь это с аутентификацией. Но тут есть проблема - Windows не умеет в SOCKS5 с аутентификацией. Я пытался найти решение этой проблемы, но у меня не получилось найти информацию, как это сделать. Как вариант использовать Tor Browser, но мне лично его использование не кажется удобным.
А почему бы не использовать nginx?
Ни для кого не секрет, что nginx прекрасно из коробки умеет быть обратным прокси, и не без этого получил свою популярность. Но вот быть прямым прокси сервером из коробки он не умеет, для этого придётся его пересобрать! Собственно говоря ниже пойдёт речь о том, как научить его это делать.
Подготовка
Нам потребуется:
Linux сервер за пределами необъятной. Ubuntu, Centos или что вам там нравится. Без разницы;
Доменное имя, которое будет ссылаться на наш сервер;
TLS сертификат (очень желательно, но можно без него). Его получение выходит за рамки данной статьи. Лично я использую acme.sh.
За работу!
Я буду производить настройку на Ubuntu 20.04, вы же вольны использовать всё, что вам душе угодно, но там могут быть свои нюансы. Если вы пойдёте этим путём, то полагаю, вы сами сможете применить эту инструкцию в другом дистрибутиве.
Заблаговременно установим в систему необходимые для сборки пакеты:
apt install -y make build-essential apache2-utils libpcre++-dev libssl-dev zlib1g-dev
Создам директорию для "сборки" проекта, в которой будут храниться все временные файлы.
mkdir build && cd build
Теперь отправная точка для каждого шага именно эта директория.
-
Скачиваем nginx и разархивируем загруженный архив
wget https://nginx.org/download/nginx-1.21.6.tar.gz
tar -xzf nginx-1.21.6.tar.gz -
Клонируем следующие репозитории, они нам все будут нужны
git clone https://github.com/chobits/ngx_http_proxy_connect_module
git clone https://github.com/openresty/lua-nginx-module
git clone https://github.com/vision5/ngx_devel_kit -
Подготовка для Lua модуля:
-
Необходимо скачать, разархивировать и установить в систему LuaJIT.
git clone https://github.com/openresty/luajit2
cd luajit2
make && make installПосле этого необходимо создать две необходимые переменные окружения
export LUAJIT_LIB=/usr/local/lib/
export LUAJIT_INC=/usr/local/include/luajit-2.1/ -
Установим в систему lua-resty-core и lua-resty-lrucache. Поочерёдно перейдём в клонированные репозитории и выполним
make install
git clone https://github.com/openresty/lua-resty-core
cd lua-resty-core
make installgit clone https://github.com/openresty/lua-resty-lrucache
cd lua-resty-lrucache
make install
-
-
Переходим к настройке модуля ngx_http_proxy_connect_module
Согласно документации этого модуля мы должны перейти в директорию с nginx и выполнить команду, в которой указываем путь к патчу, который соответствует нашей версии nginx. Эта информация есть в README этого модуля.
cd nginx-1.21.6 && patch -p1 <
/etc/nginx/modules/ngx_http_proxy_connect_module/patch/proxy_connect_rewrite_102101.patch
-
Теперь запускаем команду configure. В указанном примере стоит обратить внимание на пути к новым модулям (первые три ключа). Они у вас могут быть другими. Также другие ключи взяты из пакета, который устанавливается из стандартного репозитория Ubuntu. Из этого можно много чего выкинуть, но большинству эту не надо.
./configure --add-module=/root/build/ngx_devel_kit \ --add-module=/root/build/ngx_http_proxy_connect_module \ --add-module=/root/build/lua-nginx-module \ --prefix=/etc/nginx \ --sbin-path=/usr/sbin/nginx \ --modules-path=/usr/lib/nginx/modules \ --conf-path=/etc/nginx/nginx.conf\ --error-log-path=/var/log/nginx/error.log \ --http-log-path=/var/log/nginx/access.log\ --pid-path=/var/run/nginx.pid\ --lock-path=/var/run/nginx.lock \ --http-client-body-temp-path=/var/cache/nginx/client_temp \ --http-proxy-temp-path=/var/cache/nginx/proxy_temp \ --http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp \ --http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp \ --http-scgi-temp-path=/var/cache/nginx/scgi_temp \ --user=nginx \ --group=nginx \ --with-compat \ --with-file-aio \ --with-threads \ --with-http_addition_module \ --with-http_auth_request_module \ --with-http_dav_module \ --with-http_flv_module \ --with-http_gunzip_module -\ --with-http_gzip_static_module \ --with-http_mp4_module \ --with-http_random_index_module \ --with-http_realip_module \ --with-http_secure_link_module \ --with-http_slice_module \ --with-http_ssl_module \ --with-http_stub_status_module \ --with-http_sub_module \ --with-http_v2_module \ --with-mail \ --with-mail_ssl_module \ --with-stream \ --with-stream_realip_module \ --with-stream_ssl_module \ --with-stream_ssl_preread_module
-
Осталось запустить
make && make install
Настройка nginx
Для упрощения инструкции все действия буду производится под пользователем root, в частности запуск демона и создание директорий.
Создадим директорию
mkdir -p /var/cache/nginx
-
Нужно создать файл для запуска nginx, как сервис
vim /lib/systemd/system/nginx.service
Со следующим содержимым
[Unit] Description=A high performance web server and a reverse proxy server Documentation=man:nginx(8) After=network.target [Service] Type=forking PIDFile=/run/nginx.pid ExecStartPre=/usr/sbin/nginx -t -q -g 'daemon on; master_process on;' ExecStart=/usr/sbin/nginx -g 'daemon on; master_process on;' ExecReload=/usr/sbin/nginx -g 'daemon on; master_process on;' -s reload ExecStop=-/sbin/start-stop-daemon --quiet --stop --retry QUIT/5 --pidfile /run/nginx.pid TimeoutStopSec=5 KillMode=mixed [Install] WantedBy=multi-user.target
Теперь обязательно нужно выполнить. Без этого systemd не узнает о нашем сервисе.
systemctl daemon-reload
-
Отредактируем файл /etc/nginx/nginx.conf и приведём его примерно к такому содержанию
# /etc/nginx/nginx.conf user root; worker_processes 1; pid /run/nginx.pid; events { worker_connections 1024; } http { lua_package_path "/usr/local/lib/lua/?.lua;;"; #обазательный параметр! #lua_load_resty_core off; include mime.types; default_type application/octet-stream; sendfile on; keepalive_timeout 65; include /etc/nginx/conf.d/*.conf; include /etc/nginx/sites-enabled/*; }
-
Сгенерируем файл аутентификации. Этот файл будет использоваться сервером для проверки учетных данных. И при настройке прокси в браузере нужно будет указать пользователя proxyuser и пароль, который будет введён при выполнении кода ниже.
mkdir -p /etc/nginx/auth
htpasswd -c /etc/nginx/auth/htpasswd proxyuser -
Создадим директорию с конфигурациями сайтов
mkdir -p /etc/nginx/sites-enabled
-
Осталось создать файл конфигурации в созданной выше директории с таким содержимым. Посмотрите комментарии в коде, если будете делать конфигурацию без сертификата.
vim /etc/nginx/sites-enabled/fw-proxy
# /etc/nginx/sites-enabled/fw-proxy server { # Если без сертифката, то listen 80; listen 443 ssl; server_name proxy.example.com; # Если без сертификата, то убрать или закомментировать два нижних параметра ssl_certificate <path to certificate>/fullchain.pem; ssl_certificate_key <path to ptivate key>/key.pem; auth_basic "Server auth"; auth_basic_user_file /etc/nginx/auth/htpasswd; # transfer Proxy-Authorization header to Authorization header rewrite_by_lua_file /etc/nginx/auth/proxy_auth.lua; server_tokens off; resolver 8.8.8.8 ipv6=off; proxy_connect; proxy_connect_allow all; proxy_connect_connect_timeout 10s; proxy_connect_read_timeout 10s; proxy_connect_send_timeout 10s; location / { #proxy_http_version 1.1; proxy_pass http://$host; proxy_set_header Host $host; # If backend wont check Auth header, we should not pass the user/password. proxy_hide_header Authorization; proxy_hide_header Proxy-Authorization; } }
-
Проверки работоспособности
Проверяем конфигурацию nginx командой
nginx -t
Проверим подключение утилитой curl
-
Настройка браузера
После успешного завершения предыдущих шагов можно переходить к настройке браузера.
Надо установить расширение Switchy Omega из любого удобного магазина расширений;
-
Зайти в его настройки и создать новый прокси сервер. Как на скриншоте ниже, не забыв указать данные пользователя в "замочке" справа.
Осталось перейти в профиль switch и сопоставить необходимый сайт с прокси сервером и радоваться жизни. Расширение автоматически будет ходить на указанные сайты через прокси. Естественно в расширении немало возможностей по кастомизации поведения.
Заключение
В заключении хотелось бы написать, что скорее всего есть более элегантные варианты решить эту проблему, но я решил пойти именно этим путём, потому что другого не увидел. В данной инструкции конечно же можно отказаться от использования TLS и базовой аутентификации. Благодаря этому можно будет не заморачиваться с Lua. И собирать nginx только с ngx_http_proxy_connect_module. И даже есть готовые образы для создания контейнера. Но так не секьюрно, а цель была именно в том, чтобы максимально защитить прокси от посягательств извне.
Комментарии (31)
FSA
05.08.2022 12:35+4Мне нужен был белый IP адрес для ноутбука. Я просто взял дешёвый VPS и поднял до него Wireguard. Но не стал в него загонять весь свой трафик, а использовал только для связи между ноутбуком и сервером. На сервере просто поднял socks сервер и теперь пользуюсь им, если нужно. Весь трафик идёт внутри туннеля.
И, да. Ничего не пришлось собирать из исходников. Да и при желании можно весь трафик запихать в туннель, просто создав другую конфигурацию на клиенте.А вот тут я описал как настраивал Wireguard: https://tavda.net/wireguard
mikes
05.08.2022 13:02+1а что не так со squid коль есть потребность именно в прокси?
vesper-bot
05.08.2022 13:18Громоздкий, наверно. Я когда его увидел, в осадок выпал от возможностей и объемов необходимой конфигурации.
mikes
05.08.2022 14:08возможностей много да, минимальный конфиг будет строчек 10-15 а то и меньше. ИМХО существенно проще.
Hu3yP7
06.08.2022 23:45Есть ещё такая штука для прокси: https://github.com/qwj/python-proxy
Тут и протоколов больше (shadowsocks если кому нужно больше скрытности), и настраивать просто.
egorsergey Автор
05.08.2022 15:01Была и такая мысль. Но я с ним не работал никогда и мне показалось сделать быстрее через nginx, чем изучать абсолютно новый для себя продукт.
FSA
05.08.2022 15:32Избыточно. Есть простенькие socks прокси с минимумом настроек. Для обхода багов сети самое то.
select26
06.08.2022 18:15+23proxy использую уже не один год. По сравнению со squid есть один недостаток- 3proxy не кэширующий прокси. Но можно ли считать это недостатком в эпоху HTTPS? В общем забыл про squid уже.
Просто посмотрите.
ABATAPA
05.08.2022 13:17+1навыки работы с Linux и свой сервер где нибудь за бугром. Почему бы собственно говоря не сделать свой прямой прокси?
Тогда почему ты с такими навыками просто не поднял VPN и не завернул в него нужный трафик?
egorsergey Автор
05.08.2022 14:59VPN безусловно есть и для меня было проще использовать именно такую схему. В первую очередь требовалось выборочно обозначить сайты, на которые нужно ходить через прокси. И это очень удобно делать через браузер.
select26
06.08.2022 18:18Я тоже так сделал: поднял пару прокси серверов в РФ и в Европе и настроил proxy.pac скрипт, в котором описана маршрутизация.
Например, все домены *.ru выпускать через российский прокси, *.de - через европейский и т.д. Естественно, можно указать конкретные сайты.
Этот скрипт подключил как "автоконфигурация прокси" в браузере.
Просто. Быстро. Надёжно.
init0
05.08.2022 14:32+2А зачем красноглазить и собирать nginx когда можно установить его несколькими командами (не скажу за другие дистрибутивы, но в Debian тот же lua модуль добавляется
apt install libnginx-mod-http-lua
, думаю и в других это не проблема) или еще проще - запустить его из docker на базе openresty, где уже в наличии тот же lua модуль.egorsergey Автор
07.08.2022 21:04Не уверен насчёт наличия пакета для модуля прокси;
В образе openresty этого модуля по-моему нет.
П.С. всё это надо уточнять.
mpa4b
05.08.2022 14:53+1Интересно, есть ли какое-либо интегрированное решение (linux), которое бы по маскам для IP и по маскам (регекспам) для dns-имён заворачивало бы трафик в разные места (интерфейсы)? Например что-то прямиком к провайдеру, что-то в vpn-туннель. Эдакий NAT вместе с DNS, только умный.
vesper-bot
05.08.2022 15:31Как я понимаю, колхозить надо. Поставить DNS-прокси (форвардер/кэш) который будет сверять DNS-запросы с регекспами, и обновлять таблицу маршрутизации, чтобы запрос к этому узлу улетал в VPN, если обмен данными с этим узлом настроено отправлять в VPN. При этом браузерный DoH/DoT придется отключить, иначе никакой магии не получится. Ну и вишенка на торте — что делать, если два разных имени ресолвятся в один IPv4, но одно в списке "только VPN" а второе в списке "только без VPN"?
Правда, сильно не исключаю, что на подобное как раз способен squid, как прокси выше уровнем, чем L3.
Manrus
05.08.2022 17:03Это задача легко решается прямо на роутерах на "продвинутых" прошивках. Либо микротик в стоке.
gwathedhel
06.08.2022 19:50Вот по совпадению - ровно вчера делал такое на микротике. Для заворота в туннель только нужного траффика
egorsergey Автор
07.08.2022 21:02Тоже делал ни МТ такое. Заворачивал траффик на определённые айпишники в туннель. Из минусов:
Не удобно обновлять адрес-листы. Можно конечно написать скрипт на баш/повершелл/питон/(что нравится), который бы это делал, или ходить в сам МТ и делать ручками. В браузере это сделать куда как удобнее и быстрее.
Скорость работы. Вот тут я увидел ОЧЕНЬ медленную загрузку сайтов.
aleks-th
05.08.2022 22:58Мне кажется проще Squid заюзать.
Или какой-нить OpenVPN.
egorsergey Автор
07.08.2022 21:00В Сквид не умею.
OpenVPN не совсем подходит для решения данной задачи, но может я не очень понял, что вы имеете ввиду.
Dime_n_u
06.08.2022 09:29+1Как опыт наверное пригодится таким заняться, но всё ж раз заморский сервак, то лучше начать с статьи как его оплачивать) пользовался hetzner, но была возможность оплачивать только через swift. Не знаю что это за услуга, но за оплату счёта в 16 евро надо было платить комиссию в 15... Да и раз пошёл такой разговор подскажите как барыги настраивают впн или куда смотреть в плане ограничения ресурсов/трафика? Я по неопытности дал свой впн товарищу, так это чудовище скачало какой-то тупой фильм и мне пришло письмо от MGM от чего я не плохо труханул
duckhawk
07.08.2022 07:39+1Есть масса реселлеров, продающих виртуалки вне РФ, которые принимают российские карточки, к примеру inferno.name, vdsina.ru, да десятки их
Dime_n_u
07.08.2022 11:01Спасибо, пошарился на инферно - похоже на барахолку, как буд-то в старом Питере на рынок юнона пришёл где можно найти/купить всё)) На инферно просят за хиленький vps в Германии 75$, когда в хетзнер аналогичный сервак 5-10€ если память не изменяет... Но всё равно спасибо
duckhawk
07.08.2022 14:27+1Выглядит да, привет из 90-ых, но вполне работает.
Не знаю, где Вы смотрите, но у них там как у всех, "одно ядро один гиг" стоит по 5 баксов в месяц. Из плюсов конкретно инферно - условно безлимитный траф (есть некоторые рамки) и абьюзоустойчивость (они очень лояльны к не сильно противозаконным запросам, типа "с вас качали торренты").
(Подозреваю, что Вы смотрите выделенные сервера, а в данном случае нужно смотреть в виртуальные)
0x131315
07.08.2022 10:25Имхо nginx лучше поднимать через docker. Это быстрее, проще, и чище. С докером также в легком доступе множество преднастроенных проксей и VPN на любой вкус. И домен для всего этого не обязателен.
egorsergey Автор
07.08.2022 20:58Да, конечно. Только вот готовый докер образ с такими модулями вы не найдёте. Можете собрать и поделиться с сообществом. Метод в статье не претендует быть идеальным и подходящим для всех.
Johan_Palych
08.08.2022 09:32Был хороший цикл статей.
Иногда использую для синхронизации локальных реп Zabbix.
На Windows и Android не тестировал.
Работают отлично все три клиента.https://habr.com/ru/post/555368/
vesper-bot
Проще поднять SSH-тоннель и настроить его в браузере как socks-proxy. А ещё, если твой ssh-тоннель будет принимать подключения только с localhost, его ещё никто не сможет найти.
egorsergey Автор
Век живи - век учись, надо попробовать.