Docker и nginx для статичных сайтов

В моем блоге маловато статей про devops и я, уж точно, не считаю себя хорошим девопсером (стать бы, для начала, хорошим разрабом). Но есть ряд практик, которые я регулярно использую у в своей работе. Сегодня расскажу как я запускаю статичные сайты, frontend приложения через nginx, который в docker.

Основная задача, которую я хотел решить минимизировать количество запущенных контейнеров на сервере. Например у нас проект. который состоит из нескольких nodejs контейнеров и 4-5 различных фронтэнд приложений (обычно Vue), которые представляю собой набор из HTML, JS, CSS скриптов и для которых лучше всего подходит nginx.

Причем у каждого фронта свой домен. И хочется сделать так, чтобы добавлять новые фронты и домены можно было очень легко и не надо было запускать отдельный nginx контейнер под это дело. Причем я прекрасно знаю, что статичные сайты можно заливать на Github pages и другие инструменты для подобных проектов. Но я для себя решил, что мне удобней держать и такие вещи на своей инфраструктуре, чтобы не зависеть от внешних сервисов для таких простых задач.

Стандартная архитектура на малых проектах

В своем посте про Bash+Docker-compose я делился тем, что я активный пользователь nginx-proxy, который автоматически настраивает проброс на разные контейнеры, на которых указана переменная окружения VIRTUAL_HOST

Таким образом этот подход позволяет держать большое количество контейнеров с web сервисами на одном сервере и все их адекватно и удобно "переваривать". Также не стоит забыть, что в этом решении есть способ автоматически получать https сертификаты.

По-началу я активно пользовался этим способом и запускал для каждого статичного сайта отдельный nginx контейнер (когда было совсем лень запускал прямо nodejs) и не парился. В итоге если на сервере у меня хостилось 5-7 статичных сайтов это приводило к тому, что у меня было запущено 5-7 docker контейнеров из образа nginx. Звучит как-то неэффективно...

Решение

В итоге я понял, что можно поступить проще. Создается одна папка на сервере, в которой есть папка hosts и в каждую папку, которая есть внутри нее, проксируется запрос для домена, которым я называю эту папку. Для этого у nginx можно создать переменную$vhost которая содержит в себе домен текущего запроса.

Таким образом, для того, чтобы можно было сразу запускать несколько статичных сайтов на одном сервере nginx и, каждый раз, не перенастраивать nginx, можно сделать следующий конфиг для server:

server {
    server_name ~^(?.*)$;
    root /srv/www/$vhost;
    index  index.html index.php index.cgi index.txt;
    access_log            /var/log/nginx/access.log;
    error_log             /var/log/nginx/error.log;
    location / {
      try_files $uri $uri/ /index.html?$args;
      autoindex off;
    }
 }

Строка server_name ~^(?.*)$; указывает на то, что мы принимаем все запросы в этот блок, а домен, по которому к нам прилетел домен, помещаем в переменную $vhost. Далее мы указываем папку, из которой нужно раздавать контент: root /srv/www/$vhost;. Ну и стандартные настройки для работы статичного сайта в блоке location /.

Запустив nginx сервер с таким конфигом мы получим желаемый результат. Поскольку я активно использую Docker, я сделал небольшой Docker образ, который собирается в одну строчку:

FROM nginx

ADD host.conf /etc/nginx/conf.d/default.conf

Осталось лишь, при запуске образа, указывать volume с папкой hosts. Чтобы этими наработками было проще пользоваться я сделал репозиторий на github. Клонируете его, создаете файл .env с одной строкой:

DOMAINS=site1.ru,site2.ru,site3.ru
  • Запускаете через docker-compose up -d на сервере, где уже запущен nginx-proxy,
  • Создаете папки site1.ru, site2.ru, site3.ru, кладете в них содержимое вашего сайта
  • Получаете результат

Указывать DOMAINS в переменной окружения нужно для того, чтобы nginx-proxy понимал, что по этим доменам нужно отдавать контент с запущенного контейнера + letsencrypt сгенерирует для вас сертификаты, которые тоже будут привязаны к этим доменам. В результате вы получите, достаточно быстро, работающий через https статичный сайт.

Заключение

Если вдруг вы знаете способ как организовать статичные сайты быстрее и удобнее, то буду признателен за любую обратную связь через мои контакты.

Благодарю за внимание!