Предисловие

Я уже писал про то, как организовать использование собственных сервисов из локальной сети. Если кратко, то мой рецепт - назначить статические IP адреса компьютерам (не важно, физическим или виртуальным), на которых "крутятся" сервисы, и следить за тем, чтобы сервисы на одной машине не пересекались по используемым портам. Но что делать, если хочется использовать свои сервисы, находясь за пределами локальной сети? Ведь это именно и есть та задача, которую я, в конечном итоге, ставил перед собой! И, как всегда, существует несколько подходов, которые можно использовать для решения этой задачи и ответа на поставленный чуть выше вопрос. Я приведу краткое описание тех, которые рассматривал сам, наверное, есть и другие. На каком остановиться - зависит от требований, которые вы предъявляете к реализуемой системе, ну и, от личных предпочтений, конечно. Начнём, пожалуй (прошу учесть, что порядок перечисления, в данном случае, ни на что не намекает).

Первый метод - VPN

Скажем, можно использовать виртуальную сеть - так называемую VPN. Для этого необходимо будет установить и настроить на своём оборудовании (ну, или, на арендуемом виртуальном или физическом сервере) VPN сервер, установить и настроить на своих устройствах, которыми собираетесь пользоваться за пределами домашней локальной сети, клиентское ПО, и наслаждаться. Каждый раз, когда вы будете подключаться с помощью клиента на своем устройстве к своему же VPN серверу, будет происходить маленькое чудо - вы словно окажетесь в своей домашней локальной сети. Нет, телепортация пока никем не изобретена, но цифровые технологии позволяют "делать настоящие чудеса" (©).

Ну а если серьёзно, то, конечно, никаких чудес - всё очень практично и логично. Если упрощённо, то VPN сервер создает свою собственную сеть, поверх существующей. И в эту новую сеть (если, конечно, все правильно настроить) будут входить и устройства домашней локальной сети, и ваши устройства, которые вы используете, находясь вне дома. Условие одно - на устройствах, находящихся за пределами локальной сети, должно быть запущено клиентское ПО, которое, в свою очередь, предварительно, должно было быть настроено для работы с вашим сервером VPN. Естественно, при выполнении этого условия, все ресурсы, которые размещены в домашней сети - принтеры, файловые хранилища, сервисы и так далее - станут доступны всем устройствам, объединенным в VPN. Притом, весь трафик будет ещё и шифроваться, что значительно усилит безопасность соединений внутри виртуальной сети.

Однако, у данной модели работы есть пара моментов, омрачающих, в общем-то, яркую и красивую картинку. Во-первых, это необходимость установки и настройки отдельного серверного и клиентского ПО. И хотя во многих устройствах клиентское ПО встроено, пока его правильно не настроить - воспользоваться благами VPN не получится. Во-вторых, это скорость работы получившейся виртуальной сети. Как не крути, она оказывается ниже, иногда весьма ощутимо, чем если бы все устройства работали напрямую. Но, как говорится, за всё (в данном случае, за безопасный доступ к ресурсам домашней локальной сети) приходится платить. И, во многих случаях, перечисленные неприятные моменты не могут перевесить плюсов VPN. Лично я настроил всё необходимое ПО, но сейчас использую возможности частной виртуальной сети только тогда, когда это необходимо.

Второй метод - DMZ

Другой возможностью доступа к домашним ресурсам является использование так называемой демилитаризованной зоны - DMZ. Эта зона из себя представляет сегмент сети (в простейших случаях, это один физический или виртуальный компьютер), в котором размещаются публичные сервисы, и для которого делается всё возможное, чтобы сделать его относительно легко доступным из-за пределов локальной сети. Остальные сегменты остаются недоступными извне. При этом, связь между этими двумя сегментами сети есть, но сервисам, размещённым в DMZ, разрешён только весьма ограниченный доступ к сервисам в остальной части сети.

DMZ призвана увеличить общую безопасность сети и облегчить доступ к публичным сервисам. В настоящее время даже домашние роутеры позволяют настраивать DMZ, так что, к этой технологии можно присмотреться. Но я решил не использовать этот подход. Основным его минусом, как мне кажется, является то, что компьютер, находящийся в демилитаризованной зоне, практически полностью открыт внешнему миру - все его порты доступны. И в самом простом, но наиболее доступном и распространенном способе объявления DMZ - на домашних роутерах - как правило, ничего нельзя сделать, кроме как определить IP адрес компьютера. На мой взгляд, этого не совсем достаточно для спокойствия.

Третий метод - проброс портов

Еще одним способом работы с self-hosted сервисами извне локальной сети, является проброс (или перенаправление) портов. Суть заключается в том, что на роутере задаётся правило, которое определяет, куда должен быть перенаправлен трафик, пришедший на определённый порт роутера. Под "куда" понимается IP адрес компьютера (физического или виртуального), на котором запущен нужный сервис, и номер порта, на котором этот сервис "слушает" приходящие запросы.

Проблема этого метода заключается в том, что необходимо задавать правила для каждого порта, используемого каким-то сервисом. Но что делать, если сервисов в локальной сети много? А если они еще и "слушают" один и тот же порт? Конечно, сервисы можно настроить так, чтобы они использовали разные порты, и на роутере можно использовать несколько правил - по одному на каждый сервис. Да и до конечных пользователей можно донести нужные номера портов. Но все это как-то не очень удобно. Должно быть еще какое-то решение. И оно, действительно, есть...

Четвёртый метод - reverse proxy

Основывается это решение на использовании специального типа прокси сервера, так называемого reverse proxy - обратного прокси. Если обычный прокси служит для перенаправления запросов клиентов из внутренней сети к серверам в интернете, то обратный прокси получает запросы от клиентов в интернете и перенаправляет их к серверам во внутренней сети, причём, только к тем серверам, которые ассоциированы с данным конкретным прокси сервером. Такое использование обратного прокси позволяет реализовать в нём множество интересных функций.

Например, в него можно встроить защиту от DDOS атак, реализовать балансировку нагрузки, можно организовать кэширование статического и/или динамического контента, наконец, он может выполнять функции SSL и/или TLS терминатора (это когда основной сервис не поддерживает операции шифрования трафика или не выполняет их, исходя из соображений производительности, а делегирует эту функцию обратному прокси, который шифрует и дешифрует трафик с клиентами в интернете, а с внутренними серверами общается без шифрования, к тому же, такой прокси может быть снабжён специальными аппаратными ускорителями операций шифрования).

Надо сказать, что функции обратного прокси могут выполнять хорошо известные и широко используемые серверы, такие как, Apache, Nginx, HAProxy. Существует множество примеров их использования и хорошие сообщества пользователей, что облегчает вхождение в этот мир абсолютного новичка.

Именно многообразие функциональных возможностей, а также, относительная простота получаемого решения и привлекли меня. В конечном итоге, этот интерес вылился в то, что я настроил в домашней локальной сети обратный прокси и обеспечил через него доступ ко всем своим self-hosted сервисам. И именно это комбинированное решение - проброс портов и reverse proxy - используется мною в настоящий момент.

Мой выбор

Несколько слов о том, как все это устроено (в моём случае). В качестве обратного прокси я решил использовать HAProxy. Основной причиной этого выбора явился тот факт, что настройка этого прокси показалась мне наиболее понятной и логичной. На самом деле, это очень личный момент. Изначально я думал, что буду использовать Nginx, все-таки, это более "свежий" программный продукт - по сравнению, например, с Apache. Кроме того, одно из предназначений Nginx - выступать именно в роли reverse proxy. Плюс к этому, дополнительные очки в моих глазах этот продукт завоёвывал благодаря своему происхождению 😏.

Но когда я прочитал про HAProxy и ознакомился с его возможностями, а также с основами конфигурирования, я понял, что именно его и возьму в качестве обратного прокси. И дело тут не только в том, что HAProxy строго специализированный продукт и в нем нет ненужного мне функционала - он не является, например, web сервером (хотя, для многих, наоборот, "комбайн" - то, что нужно). Дело, скорее, в том, что концепции, лежащие в основе его настройки, воспринимались мною без малейшего напряжения. Именно так я бы думал, если бы сам писал такое ПО. И, несмотря на то что примеров по настройке и использованию HAProxy существенно меньше, чем по тому же Nginx, тем не менее, его освоение шло значительно быстрее. В общем, выбор был сделан, и я не жалею о нём.

Итак, что же получилось в итоге? А получилось вот что. Я завёл отдельную виртуалку с Debian Jessie (тогда эта версия была stable) в качестве гостевой ОС. Благодаря тому, что HAProxy очень бережлив к имеющимся в его распоряжении ресурсам, а мои сервисы не предполагают огромного количества обращений в секунду, виртуалке этой было выделено совсем немного памяти. Следуя собственному совету, я назначил этой машинке статический локальный адрес. Далее, на роутере было настроено перенаправление портов с номерами 80 и 443 на эту виртуалку, а работающий на ней HAProxy сконфигурирован так, чтобы "слушать" именно эти порты. Кроме того, конфигурация HAProxy сделана таким образом, чтобы, получая запросы, этот обратный прокси анализировал затребованный адрес, выделяя из него нужную информацию. Пользуясь этой информацией, reverse proxy переадресует запрос на другие виртуальные машины, на которых запущены self-hosted сервисы, каждый в своём собственном docker контейнере (или наборе docker контейнеров). Сервисы используют обычные для себя порты, которые с помощью механизмов docker, сопоставляются определенным портам виртуалки, на которой запущены контейнеры. Именно эти определенные порты и используются обратным прокси при переадресации. Благодаря такому решению удается развести сервисы, использующие одни и те же порты!

Приведу пример. Допустим, есть два сервиса, использующие 80-ый порт. Они установлены на одной виртуальной машине, но - каждый в своем собственном docker контейнере. Каждому сервису в его контейнере выделен 80 порт, но благодаря тому, что контейнеры независимы, конфликта нет. Далее, 80-ый порт одного контейнера связывается, скажем, с портом 8080 родительской виртуалки, а 80-ый порт другого контейнера привязывается к другому порту, например, 8081. На роутере настроен проброс порта с номером 80 на машину с установленным HAProxy. В нём, в свою очередь, описываются правила переадресации, в результате выполнения которых, трафик, пришедший в адрес первого сервиса. перенаправляется на порт 8080 нашей виртуальной машины, а трафик, пришедший в адрес второго сервиса, уходит на порт 8081 той же самой машины. Далее запросы уходят на 80-ые порты соответствующих контейнеров и обрабатываются каждый своим сервисом. Задача решена.

Я понимаю, что все это, возможно, звучит как-то запутанно: какие-то docker контейнеры, reverse proxy, виртуалки и перенаправление портов. На самом деле, всё не совсем так... Всё ещё хуже... 😉. Шучу, конечно. Но, в любом случае, результат того стоит. Вот, пока, и всё...