Питание прокси
В тот или иной момент вы, скорее всего, слышали термин «обратный прокси» или «прокси-сервер», который встречается то тут, то там, но что это такое? В контексте компьютерных сетей Консорциум World Wide Web (или W3C) определяет их следующим образом:
Агент, который ретранслирует сообщение между агентом запрашивающей стороны и агентом поставщика, который представляется веб-службе запрашивающей стороной.
Прокси обычно делятся на две отдельные категории при рассмотрении типичных реализаций:
- Переслать прокси
- Обратный прокси
Прямые прокси чрезвычайно распространены в бизнес-сетях любого размера и особенно полезны в крупномасштабных корпоративных средах. Вы, скорее всего, использовали его каждый раз, когда вы были за компьютером на работе, пытаясь получить доступ к веб-сайту или другому сетевому ресурсу. Вы когда-нибудь пытались перейти на сайт, который ваша компания заблокировала? Это прямой прокси-сервер, фильтрующий веб-запросы перед отправкой в сеть!
Хотя я уверен, что многие из нас имели недовольство, увидев такие надоедливые оповещения о прокси, эти конфигурации нас здесь не интересуют! Мы хотим воспользоваться мощным обратным прокси:
Обратный прокси-сервер — это сервер, который находится перед веб-серверами и перенаправляет запросы клиентов (например, веб-браузера) на эти веб-серверы. Обычно обратные прокси-серверы используются для повышения безопасности, производительности и надежности¹.
Наш сценарий
У вас есть общедоступный веб-сайт, и вы хотите создать несколько различных внутренних API-интерфейсов, чтобы эффективно и безопасно использовать различные службы уведомлений, не открывая несколько открытых портов. Как нам это сделать? Правильно… обратный прокси!
Как и многие вещи в мире программирования, есть несколько способов выполнить задачу. Способ, которым мы собираемся структурировать этот проект (который, как правило, я предпочитаю), будет следующим:
- Воспользуйтесь преимуществом скорости Go и богатыми платформами сообщества, чтобы создать API для нашей службы уведомлений.
- Используйте гибкость и дополнительную безопасность контейнеризации с помощью Docker и Docker Compose.
- Используйте встроенные прокси-функции Nginx для обработки маршрутизации всех наших сервисов.
Общая структура нашего проекта выглядит следующим образом:
. ├── api ├── backend │ └── main │ └── assets │ ├── css │ ├── fonts │ ├── img │ └── js ├── devices └── nginx └── sites-enabled
Что касается каталогов ресурсов, папка активов довольно проста. Его родительский каталог, backend/main, содержит базовый шаблон веб-сайта, используемый для имитации общедоступного сайта, используемого в реальном развертывании.
Возможно, вы заметили два интересных каталога в приведенной выше структуре. Папки api
и devices
содержат пример кода для имитации серверных API, которые должны быть доступны для получения уведомлений. Один предназначен для отправки новых контактных форм, а другой — для предупреждений датчиков устройства для имитации срабатывания локального устройства IoT.
Поскольку Go обеспечивает отличную скорость и параллелизм, простой синтаксис и многочисленные библиотеки сообщества, он легко становится популярным для программирования API. Давайте посмотрим на наш пример кода для недавно отправленных контактных форм веб-сайта:
Программа относительно проста, но давайте пробежимся по основным пунктам кода:
- Мы начинаем с запуска функции
init
для добавления/создания файла журнала для отслеживания всех запросов в течение жизни контейнера (подробнее об этом позже) - Мы импортируем мощную библиотеку Gorilla Mux, а также Logrus, чтобы предоставить простые интерфейсы для создания пользовательских маршрутов и записей в журнале.
- Создайте две функции конечной точки для сопоставления запросов маршрута, каждая из которых вызывает функцию выполнения, которая запускает скрипт Python, специфичный для маршрута… в результате чего вам (или, возможно, клиенту) отправляется оповещение по электронной почте.
- Наконец, мы создаем основной маршрутизатор и объявляем наши пользовательские маршруты в теле функции
main
, а также запускаем наш сервер API на определенном порту.
Каталог devices
использует ту же структуру кода для создания своего API. Основное отличие заключается в скрипте Python, используемом для службы уведомлений, и создании специальных структур Sensor
для каждого датчика устройства.
Следующий важный раздел проекта включает в себя создание контейнеров, которые будут запускать серверы API. Чтобы обеспечить дополнительную модульность и безопасность нашему веб-серверу, мы будем использовать Docker для запуска двух разных API в их собственных изолированных средах. Если вы новичок во всей концепции контейнеризации, обязательно ознакомьтесь с обширной документацией, доступной на веб-сайте Docker, чтобы ускорить работу и настроить использование контейнеров на вашем компьютере.
Для Docker доступна отличная программа оркестровки под названием Docker Compose. Это позволяет нам написать простой файл YAML, указывающий, какие образы докеров и ресурсы мы планируем использовать, и он идеально соответствует нашим потребностям в этом проекте!
Вот как наш веб-сервер будет раскручивать нужные нам контейнеры:
Подробное описание каждого шага, который проходит Docker Compose, выходит за рамки этой статьи; однако, если вы посмотрите на каталоги devices
и api
, вы увидите Dockerfile
в каждом из них. Они содержат инструкции по созданию образа для каждой службы… и это то, что compose использует в качестве плана. Через минуту мы рассмотрим процесс высокого уровня!
Заключительные части
Все, что нам осталось сделать, это убедиться, что на нашем сервере правильно установлен/настроен Nginx для размещения нашего сайта и соответствующей маршрутизации входящих запросов.
Если вы еще не установили и не настроили Nginx на своем сервере, рекомендую ознакомиться с одним из нескольких пошаговых руководств, доступных на Digital Ocean. Они не только проведут вас через этапы установки и базовой настройки, но также включают шаги по настройке бесплатных сертификатов LetsEncrypt, чтобы ваша страница могла использовать SSL/TLS.
После того, как каталоги вашего веб-сервера настроены (если они еще не были настроены), вам нужно сделать только одно большое изменение. Если вы следовали любому из пошаговых руководств Digital Ocean, скорее всего, у вас должен быть файл, созданный для вашего веб-сайта внутри /etc/nginx/sites-enabled
. Именно здесь объявляется важная конфигурация, позволяющая нам использовать возможности обратного прокси-сервера Nginx! Ниже приведен пример конфигурации для нашей новой веб-страницы и маршрутов API:
Имейте в виду, что это лишь частичный фрагмент файла конфигурации, так как CertBot автоматически добавляет другие строки при получении сертификата Lets Encrypt (см. статьи Digital Ocean), а также другие фрагменты, которые здесь не имеют значения.
Основные детали, которые следует вынести из вышеизложенного, следующие:
- Мы объявляем блоки
location
с именами маршрутов и местами, куда мы хотим их проксировать. Например, если запрос должен был прийти с URL-адресомawesomeinc.com/contact
, наш сервер перенаправил бы его на порт8081
. - URL-адреса
proxy_pass
соответствуют портам, которые прослушивают наши контейнеры API. limit_req
и другие объявления рекомендуются документацией Nginx для ограничения одновременных запросов и не являются полностью необходимыми сами по себе.
После этого все, что осталось, — это перезапустить (или, наконец, запустить) нашу службу Nginx, используя sudo systemctl restart nginx
. Если вы размещаете этот сервер на облачной виртуальной машине, используя что-то вроде AWS EC2, обязательно зайдите в свою сетевую панель управления, чтобы разрешить только входящий сетевой трафик на порты 80
и 443
(что должно было быть сделано для получения сертификатов SSL). Если вы создали правильные записи DNS, теперь вы сможете перейти на свою домашнюю страницу и увидеть, что веб-сайт обслуживается должным образом!
Последний шаг
Итак, теперь наш веб-сервер запущен и работает, но наши API пока недоступны.
Убедившись, что ваша основная веб-страница доступна, вернитесь к терминалу вашего сервера и скажите docker-compose, чтобы он развернул эти контейнеры для вас! Прежде чем что-либо делать, чрезвычайно важно убедиться, что ваш компоновочный файл YAML находится в основе каталога вашего проекта, а ваши различные API-интерфейсы сервисного контейнера находятся в их собственной конкретной папке (чтобы соответствовать объявлениям компоновочного файла):
Пока все выглядит хорошо, мы можем запустить очень простую команду, чтобы все заработало:
sudo docker-compose up -d
Вот что будет делать эта команда:
- Указывает compose просмотреть каждую папку, объявленную в файле конфигурации, и создать для них «образы», используя
Dockerfile
в каждом - Эти изображения будут использоваться композицией для создания новых контейнеров.
- После завершения процесса сборки docker-compose запустит все в фоновом режиме, чтобы разрешить дальнейшее использование терминала (
-d
означает «отключено»).
Вам может понадобиться перезапустить службу nginx
, а может и не понадобиться, но как только все будет наконец сделано, вы сможете протестировать запросы к своим серверным службам API! Мы добавили специальный «тестовый» маршрут в приведенный выше пример кода. Откройте терминал на вашем локальном компьютере и используйте curl
для запроса вашего домена с тестовой конечной точкой:
curl https://www.awesomeinc.com/test
Если это работает, отличная работа! Если нет… не расстраивайтесь! При настройке серверной части, такой как эта, есть много движущихся частей. Вернитесь к файлам конфигурации, проверьте объявления конечных точек… затем повторите попытку.
Проект и все соответствующие файлы можно найти на GitHub:
¹Что такое обратный прокси-сервер? | Объяснение прокси-серверов | Cloudflare. https://www.cloudflare.com/learning/cdn/glossary/reverse-proxy/.