Как защитить контейнерное приложение Node.js с помощью Nginx, Let’s Encrypt и Docker Compose
Введение
Существует несколько способов повысить гибкость и безопасность вашего Nginx, предлагая вам возможность распределять нагрузку запросов, кэшировать статический контент и внедрять Transport Layer Security (TLS). Включение зашифрованного HTTPS на вашем сервере гарантирует, что обмен данными с вашим приложением останется безопасным.
Реализация обратного прокси-сервера с TLS/SSL в контейнерах включает набор процедур, отличный от работы непосредственно в операционной системе хоста. Например, если вы получали сертификаты от клиента Certbot, это позволит вам получить ваши сертификаты. Следуя этим шагам, вы сможете воспользоваться преимуществами модульности и мобильности контейнерного рабочего процесса.
В этом руководстве вы развернете приложение Node.js с обратным прокси-сервером Nginx с помощью Docker Compose. Вы получите сертификаты TLS/SSL для домена, связанного с вашим приложением, и убедитесь, что он получает высокий рейтинг безопасности от задания cron
, чтобы обновить ваши сертификаты, чтобы ваш домен оставался безопасным.
Предпосылки
Чтобы следовать этому руководству, вам понадобятся:
- Сервер Ubuntu 18.04, пользователь без полномочий root с привилегиями
sudo
и активный брандмауэр. Чтобы узнать, как их настроить, ознакомьтесь с этим руководством по начальной настройке сервера. - Docker и Docker Compose установлены на вашем сервере. Чтобы получить инструкции по установке Docker, выполните шаги 1 и 2 раздела «Как установить Docker Compose в Ubuntu 18.04».
- Зарегистрированное доменное имя. В этом руководстве будет использоваться your_domain. Вы можете получить его бесплатно на Freenom или воспользоваться услугами регистратора домена по вашему выбору.
- Обе следующие записи DNS настроены для вашего сервера. Вы можете следовать этому введению в DNS DigitalOcean, чтобы узнать, как добавить их в учетную запись DigitalOcean, если это то, что вы используете:
- Запись A с
your_domain
, указывающая на общедоступный IP-адрес вашего сервера. - Запись A с
www.your_domain
, указывающая на общедоступный IP-адрес вашего сервера.
После того, как вы все настроили, вы готовы начать первый шаг.
Шаг 1 — Клонирование и тестирование приложения узла
В качестве первого шага вы клонируете репозиторий с кодом приложения Node, который включает файл Dockerfile для создания образа приложения с помощью Compose. Затем вы протестируете приложение, создав и запустив его с помощью команды
docker run
без обратного прокси-сервера или SSL.В домашнем каталоге вашего пользователя без полномочий root клонируйте How To Build a Node.js Application with Docker.
Клонируйте репозиторий в каталог. В этом примере в качестве имени каталога используется
node_project
. Не стесняйтесь называть этот каталог по своему вкусу:- git clone https://github.com/do-community/nodejs-image-demo.git node_project
Перейдите в каталог
node_project
:- cd node_project
В этом каталоге находится файл Dockerfile, содержащий инструкции по созданию приложения Node с использованием образа Docker
node:10
и содержимого текущего каталога проекта. Вы можете просмотреть содержимое Dockerfile следующим образом:- cat Dockerfile
OutputFROM node:10-alpine RUN mkdir -p /home/node/app/node_modules && chown -R node:node /home/node/app WORKDIR /home/node/app COPY package*.json ./ USER node RUN npm install COPY --chown=node:node . . EXPOSE 8080 CMD [ "node", "app.js" ]Эти инструкции создают образ узла, копируя код проекта из текущего каталога в контейнер и устанавливая зависимости с помощью
npm install
. Они также используют преимущества кэширования и многоуровневого изображения Docker, отделяя копиюpackage.json
иpackage-lock.json
, содержащих перечисленные зависимости проекта, от копии файла остальной код приложения. Наконец, в инструкциях указано, что контейнер будет запускаться от имени пользователя узла без полномочий root с соответствующими разрешениями, установленными для кода приложения и каталоговnode_modules
.Для получения дополнительной информации об этом Dockerfile и рекомендациях по образу Node, пожалуйста, изучите полное обсуждение в шаге 3 Как создать приложение Node.js с помощью Docker.
Чтобы протестировать приложение без SSL, вы можете собрать и пометить образ с помощью
docker build
и флага-t
. В этом примере изображение называетсяnode-demo
, но вы можете назвать его как угодно:- docker build -t node-demo .
После завершения процесса сборки вы можете перечислить свои образы с помощью
docker images
:- docker images
Следующий вывод подтверждает сборку образа приложения:
OutputREPOSITORY TAG IMAGE ID CREATED SIZE node-demo latest 23961524051d 7 seconds ago 73MB node 10-alpine 8a752d5af4ce 3 weeks ago 70.7MBЗатем создайте контейнер с помощью
docker run
. Эта команда включает три флага:-p
: публикует порт в контейнере и сопоставляет его с портом на вашем хосте. В этом примере вы будете использовать порт80
на хосте, но не стесняйтесь изменять его по мере необходимости, если у вас есть другой процесс, работающий на этом порту. Дополнительные сведения о том, как это работает, см. в этом обсуждении в документации Docker по привязке портов.-d
: запускает контейнер в фоновом режиме.--name
: позволяет дать контейнеру запоминающееся имя.
Выполните следующую команду для создания контейнера:
- docker run --name node-demo -p 80:8080 -d node-demo
Проверьте работающие контейнеры с помощью
docker ps
:- docker ps
Следующий вывод подтверждает, что ваш контейнер приложения работает:
OutputCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 4133b72391da node-demo "node app.js" 17 seconds ago Up 16 seconds 0.0.0.0:80->8080/tcp node-demoТеперь вы можете посетить свой домен, чтобы проверить настройки:
http://ваш_домен
. Не забудьте заменитьyour_domain
своим собственным доменным именем. Ваше приложение отобразит следующую целевую страницу:Теперь, когда вы протестировали приложение, вы можете остановить контейнер и удалить изображения. Используйте
docker ps
, чтобы получить свойID КОНТЕЙНЕРА
:- docker ps
OutputCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 4133b72391da node-demo "node app.js" 17 seconds ago Up 16 seconds 0.0.0.0:80->8080/tcp node-demoОстановите контейнер с помощью
docker stop
. Обязательно замените указанный здесьИДЕНТИФИКАТОР КОНТЕЙНЕРА
своим собственнымИДЕНТИФИКАТОРОМ КОНТЕЙНЕРА
:- docker stop 4133b72391da
Теперь вы можете удалить остановленный контейнер и все образы, включая неиспользуемые и висящие образы, с помощью
docker system prune
и флага-a
:- docker system prune -a
Нажмите
y
, когда в выводе будет предложено подтвердить, что вы хотите удалить остановленный контейнер и изображения. Имейте в виду, что это также удалит ваш кеш сборки.Протестировав образ приложения, вы можете перейти к созданию остальной части вашей установки с помощью Docker Compose.
Шаг 2 — Определение конфигурации веб-сервера
Имея наше приложение Dockerfile, вы создадите файл конфигурации для запуска вашего контейнера Nginx. Вы можете начать с минимальной конфигурации, которая будет включать ваше доменное имя, корень документа, информацию о прокси-сервере и блок местоположения, чтобы направлять запросы Certbot в каталог
.well-known
, где он будет размещать временный файл. чтобы убедиться, что DNS для вашего домена разрешается на ваш сервер.Сначала создайте каталог в текущем каталоге проекта,
node_project
, для файла конфигурации:- mkdir nginx-conf
Создайте и откройте файл с помощью
nano
или вашего любимого редактора:- nano nginx-conf/nginx.conf
Добавьте следующий блок сервера, чтобы проксировать пользовательские запросы в контейнер приложения Node и направлять запросы Certbot в каталог
.well-known
. Обязательно заменитеyour_domain
своим собственным доменным именем:server { listen 80; listen [::]:80; root /var/www/html; index index.html index.htm index.nginx-debian.html; server_name your_domain www.your_domain; location / { proxy_pass http://nodejs:8080; } location ~ /.well-known/acme-challenge { allow all; root /var/www/html; } }
Этот серверный блок позволит вам запустить контейнер Nginx в качестве обратного прокси-сервера, который будет передавать запросы в контейнер вашего приложения Node. Это также позволит вам использовать метод проверки Certbot HTTP-01, который использует HTTP-запрос, чтобы доказать, что Certbot может получить доступ к ресурсам с сервера, который отвечает на данное доменное имя.
Закончив редактирование, сохраните и закройте файл. Если вы использовали
nano
, вы можете сделать это, нажавCTRL + X
, затемY
иENTER
. Чтобы узнать больше о сервере Nginx и алгоритмах блокировки местоположения, обратитесь к этой статье «Понимание алгоритмов выбора сервера Nginx и блока местоположения».Имея сведения о конфигурации веб-сервера, вы можете перейти к созданию файла
docker-compose.yml
, который позволит вам создать службы приложений и контейнер Certbot, который вы будете использовать для получения сертификатов. .Шаг 3 — Создание файла Docker Compose
Файл
docker-compose.yml
будет определять ваши службы, включая приложение Node и веб-сервер. В нем будут указаны такие детали, как именованные тома, которые будут иметь решающее значение для обмена учетными данными SSL между контейнерами, а также информация о сети и порте. Это также позволит вам указать команды для запуска при создании ваших контейнеров. Этот файл является центральным ресурсом, который определяет, как ваши службы будут работать вместе.Создайте и откройте файл в текущем каталоге:
- nano docker-compose.yml
Сначала определите службу приложения:
version: '3' services: nodejs: build: context: . dockerfile: Dockerfile image: nodejs container_name: nodejs restart: unless-stopped
Определение службы
nodejs
включает следующее:build
: определяет параметры конфигурации, включаяcontext
иdockerfile
, которые будут применяться при сборке Compose образа приложения. Если вы хотите использовать существующий образ из реестра, например инструкциюimage
, с информацией о вашем имени пользователя, репозитории и теге изображения.context
: определяет контекст сборки для сборки образа приложения. В данном случае это текущая директория проекта, представленная с помощью.
.dockerfile
: указывает файл Dockerfile, который Compose будет использовать для сборки — файл Dockerfile, рассмотренный на шаге 1.image
,имя_контейнера
: присваивают имена изображению и контейнеру.restart
: определяет политику перезапуска. По умолчанию используетсянет
, но в этом примере контейнер настроен на перезапуск, если он не будет остановлен.
Обратите внимание, что вы не включаете привязку монтирования в эту службу, поскольку ваша установка ориентирована на развертывание, а не на разработку. Для получения дополнительной информации, пожалуйста, прочитайте документацию Docker по томам.
Чтобы включить связь между приложением и контейнерами веб-сервера, добавьте сеть-мост с именем
app-network
после определения перезапуска:services: nodejs: ... networks: - app-network
Определяемая пользователем мостовая сеть, подобная этой, обеспечивает связь между контейнерами на одном хосте демона Docker. Это оптимизирует трафик и связь внутри вашего приложения, поскольку открывает все порты между контейнерами в одной и той же мостовой сети, не открывая порты внешнему миру. Таким образом, вы можете избирательно открывать только те порты, которые вам нужны для предоставления внешних служб.
Затем определите службу
webserver
:... webserver: image: nginx:mainline-alpine container_name: webserver restart: unless-stopped ports: - "80:80" volumes: - web-root:/var/www/html - ./nginx-conf:/etc/nginx/conf.d - certbot-etc:/etc/letsencrypt - certbot-var:/var/lib/letsencrypt depends_on: - nodejs networks: - app-network
Некоторые параметры, определенные здесь для службы
nodejs
, остались прежними, но были внесены некоторые из следующих изменений:image
: указывает Compose загрузить последнюю версию How To Build a Node.js Application with Docker.ports
: предоставляет доступ к порту80
для включения параметров конфигурации, которые вы определили в конфигурации Nginx.
Также указаны следующие именованные тома и привязки:
web-root:/var/www/html
: это добавит статические ресурсы вашего сайта, скопированные в том с именемweb-root
, в папку/var/www/html
в контейнере../nginx-conf:/etc/nginx/conf.d
: это свяжет каталог конфигурации Nginx на хосте с соответствующим каталогом в контейнере, гарантируя, что любые внесенные вами изменения файлы на хосте будут отражены в контейнере.certbot-etc:/etc/letsencrypt
. При этом соответствующие сертификаты и ключи Let’s Encrypt для вашего домена будут смонтированы в соответствующий каталог контейнера.certbot-var:/var/lib/letsencrypt
: монтирует рабочий каталог Let’s Encrypt по умолчанию в соответствующий каталог в контейнере.
Затем добавьте параметры конфигурации для контейнера
certbot
. Обязательно замените информацию о домене и электронной почте своим собственным доменным именем и контактным адресом электронной почты:... certbot: image: certbot/certbot container_name: certbot volumes: - certbot-etc:/etc/letsencrypt - certbot-var:/var/lib/letsencrypt - web-root:/var/www/html depends_on: - webserver command: certonly --webroot --webroot-path=/var/www/html --email sammy@your_domain --agree-tos --no-eff-email --staging -d your_domain -d www.your_domain
Это определение сообщает Compose, что необходимо извлечь образ certbot/certbot из Docker Hub. Он также использует именованные тома для совместного использования ресурсов с контейнером Nginx, включая сертификаты домена и ключ в
certbot-etc
, рабочий каталог Let's Encrypt вcertbot-var
и код приложения вweb-root
.Опять же, вы использовали
depends_on
, чтобы указать, что контейнерcertbot
должен запускаться после запуска службыwebserver
.Параметр
command
указывает команду, которая будет выполняться при запуске контейнера. Он включает подкомандуcertonly
со следующими параметрами:--webroot
: указывает Certbot использовать подключаемый модуль webroot для размещения файлов в папке webroot для аутентификации.--webroot-path
: указывает путь к корневому веб-каталогу.--email
: предпочтительный адрес электронной почты для регистрации и восстановления.--agree-tos
: указывает, что вы согласны с Соглашением с подписчиком ACME.--no-eff-email
: Это сообщает Certbot, что вы не хотите делиться своей электронной почтой с Electronic Frontier Foundation (EFF). Не стесняйтесь опустить это, если хотите.--staging
: указывает Certbot, что вы хотели бы использовать тестовую среду Let’s Encrypt для получения тестовых сертификатов. Использование этого параметра позволяет протестировать параметры конфигурации и избежать возможных ограничений запросов домена. Дополнительные сведения об этих ограничениях см. в документации по ограничениям скорости Let’s Encrypt.-d
: это позволяет вам указать доменные имена, которые вы хотели бы применить к вашему запросу. В данном случае вы включиливаш_домен
иwww.ваш_домен
. Обязательно замените их своими собственными доменами.
В качестве последнего шага добавьте определения тома и сети. Обязательно замените имя пользователя здесь своим собственным пользователем без полномочий root:
... volumes: certbot-etc: certbot-var: web-root: driver: local driver_opts: type: none device: /home/sammy/node_project/views/ o: bind networks: app-network: driver: bridge
Именованные тома включают ваш сертификат Certbot и тома рабочего каталога, а также том для статических ресурсов вашего сайта,
web-root
. В большинстве случаев драйвером по умолчанию для томов Docker является драйверlocal
, который в Linux принимает параметры, аналогичные описанным в разделе Как создать приложение Node.js с помощью Docker.Ниже приведен полный файл
docker-compose.yml
:version: '3' services: nodejs: build: context: . dockerfile: Dockerfile image: nodejs container_name: nodejs restart: unless-stopped networks: - app-network webserver: image: nginx:mainline-alpine container_name: webserver restart: unless-stopped ports: - "80:80" volumes: - web-root:/var/www/html - ./nginx-conf:/etc/nginx/conf.d - certbot-etc:/etc/letsencrypt - certbot-var:/var/lib/letsencrypt depends_on: - nodejs networks: - app-network certbot: image: certbot/certbot container_name: certbot volumes: - certbot-etc:/etc/letsencrypt - certbot-var:/var/lib/letsencrypt - web-root:/var/www/html depends_on: - webserver command: certonly --webroot --webroot-path=/var/www/html --email sammy@your_domain --agree-tos --no-eff-email --staging -d your_domain -d www.your_domain volumes: certbot-etc: certbot-var: web-root: driver: local driver_opts: type: none device: /home/sammy/node_project/views/ o: bind networks: app-network: driver: bridge
Имея определения служб, вы готовы запустить контейнеры и протестировать запросы сертификатов.
Шаг 4 — Получение SSL-сертификатов и учетных данных
Вы можете запустить контейнеры с помощью
docker-compose up
. Это создаст и запустит ваши контейнеры и службы в указанном вами порядке. После успешного выполнения запросов домена ваши сертификаты будут смонтированы в папку/etc/letsencrypt/live
в контейнереwebserver
.Создайте службы с помощью
docker-compose up
с флагом-d
, которые будут запускать контейнерыnodejs
иwebserver
. на заднем фоне:- docker-compose up -d
Ваш вывод подтвердит, что ваши сервисы были созданы:
OutputCreating nodejs ... done Creating webserver ... done Creating certbot ... doneИспользуйте
docker-compose ps
, чтобы проверить статус ваших служб:- docker-compose ps
Если все прошло успешно, ваши службы
nodejs
ивеб-сервер
будутUp
, а контейнерcertbot
завершит работу с Сообщение о состоянии0
:OutputName Command State Ports ------------------------------------------------------------------------ certbot certbot certonly --webroot ... Exit 0 nodejs node app.js Up 8080/tcp webserver nginx -g daemon off; Up 0.0.0.0:80->80/tcpЕсли вы заметили что-либо, кроме
Up
в столбцеState
для службnodejs
иwebserver
, или статус выхода кроме0
для контейнераcertbot
, обязательно проверьте журналы службы с помощью командыdocker-compose logs
. Например, если вы хотите проверить журнал Certbot, вы должны запустить:- docker-compose logs certbot
Теперь вы можете проверить, смонтированы ли ваши учетные данные в контейнер
webserver
с помощьюdocker-compose exec
:- docker-compose exec webserver ls -la /etc/letsencrypt/live
Как только ваш запрос будет выполнен успешно, ваш вывод покажет следующее:
Outputtotal 16 drwx------ 3 root root 4096 Dec 23 16:48 . drwxr-xr-x 9 root root 4096 Dec 23 16:48 .. -rw-r--r-- 1 root root 740 Dec 23 16:48 README drwxr-xr-x 2 root root 4096 Dec 23 16:48 your_domainТеперь, когда вы знаете, что ваш запрос будет выполнен успешно, вы можете изменить определение службы
certbot
, чтобы удалить флаг--staging
.Откройте файл
docker-compose.yml
:- nano docker-compose.yml
Найдите раздел файла с определением службы
certbot
и замените флаг--staging
в опцииcommand
на- -force-renewal
флаг. Это сообщит Certbot, что вы хотите запросить новый сертификат с теми же доменами, что и существующий сертификат. Определение службыcertbot
должно иметь следующие определения:... certbot: image: certbot/certbot container_name: certbot volumes: - certbot-etc:/etc/letsencrypt - certbot-var:/var/lib/letsencrypt - web-root:/var/www/html depends_on: - webserver command: certonly --webroot --webroot-path=/var/www/html --email sammy@your_domain --agree-tos --no-eff-email --force-renewal -d your_domain -d www.your_domain ...
Когда вы закончите редактирование, сохраните и выйдите из файла. Теперь вы можете запустить
docker-compose up
, чтобы воссоздать контейнерcertbot
и его соответствующие тома. Включив параметр--no-deps
, вы сообщаете Compose, что он может пропустить запуск службыwebserver
, так как она уже запущена:- docker-compose up --force-recreate --no-deps certbot
Следующий вывод показывает, что ваш запрос на сертификат был успешным:
OutputRecreating certbot ... done Attaching to certbot certbot | Account registered. certbot | Renewing an existing certificate for your_domain and www.your_domain certbot | certbot | Successfully received certificate. certbot | Certificate is saved at: /etc/letsencrypt/live/your_domain/fullchain.pem certbot | Key is saved at: /etc/letsencrypt/live/your_domain phd.com/privkey.pem certbot | This certificate expires on 2022-11-03. certbot | These files will be updated when the certificate renews. certbot | NEXT STEPS: certbot | - The certificate will need to be renewed before it expires. Cert bot can automatically renew the certificate in the background, but you may need to take steps to enable that functionality. See https://certbot.org/renewal-setu p for instructions. certbot | Saving debug log to /var/log/letsencrypt/letsencrypt.log certbot | certbot | - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - certbot | If you like Certbot, please consider supporting our work by: certbot | * Donating to ISRG / Let's Encrypt: https://letsencrypt.org/do nate certbot | * Donating to EFF: https://eff.org/donate-le certbot | - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - certbot exited with code 0Имея сертификаты, вы можете перейти к изменению конфигурации Nginx, чтобы включить SSL.
Шаг 5 — Изменение конфигурации веб-сервера и определения службы
Включение SSL в вашей конфигурации Nginx потребует добавления перенаправления HTTP на HTTPS и указания сертификата SSL и расположения ключей. Это также потребует указания группы Диффи-Хеллмана, которую вы будете использовать для полной секретности пересылки.
Поскольку вы собираетесь воссоздать службу
webserver
, чтобы включить эти дополнения, вы можете остановить ее сейчас:- docker-compose stop webserver
Затем создайте каталог в текущем каталоге проекта для ключа Диффи-Хеллмана:
- mkdir dhparam
Сгенерируйте ключ с помощью команды
openssl
:- sudo openssl dhparam -out /home/sammy/node_project/dhparam/dhparam-2048.pem 2048
Генерация ключа займет несколько минут.
Чтобы добавить соответствующую информацию о Диффи-Хеллмане и SSL в вашу конфигурацию Nginx, сначала удалите файл конфигурации Nginx, который вы создали ранее:
- rm nginx-conf/nginx.conf
Откройте другую версию файла:
- nano nginx-conf/nginx.conf
Добавьте в файл следующий код, чтобы перенаправить HTTP на HTTPS и добавить учетные данные SSL, протоколы и заголовки безопасности. Не забудьте заменить
your_domain
своим собственным доменом:server { listen 80; listen [::]:80; server_name your_domain www.your_domain; location ~ /.well-known/acme-challenge { allow all; root /var/www/html; } location / { rewrite ^ https://$host$request_uri? permanent; } } server { listen 443 ssl http2; listen [::]:443 ssl http2; server_name your_domain www.your_domain; server_tokens off; ssl_certificate /etc/letsencrypt/live/your_domain/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/your_domain/privkey.pem; ssl_buffer_size 8k; ssl_dhparam /etc/ssl/certs/dhparam-2048.pem; ssl_protocols TLSv1.2; ssl_prefer_server_ciphers on; ssl_ciphers ECDH+AESGCM:ECDH+AES256:ECDH+AES128:DH+3DES:!ADH:!AECDH:!MD5; ssl_ecdh_curve secp384r1; ssl_session_tickets off; ssl_stapling on; ssl_stapling_verify on; resolver 8.8.8.8; location / { try_files $uri @nodejs; } location @nodejs { proxy_pass http://nodejs:8080; add_header X-Frame-Options "SAMEORIGIN" always; add_header X-XSS-Protection "1; mode=block" always; add_header X-Content-Type-Options "nosniff" always; add_header Referrer-Policy "no-referrer-when-downgrade" always; add_header Content-Security-Policy "default-src * data: 'unsafe-eval' 'unsafe-inline'" always; #add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always; # enable strict transport security only if you understand the implications } root /var/www/html; index index.html index.htm index.nginx-debian.html; }
Блок HTTP-сервера указывает веб-корневой каталог для запросов на обновление Certbot в каталог
.well-known/acme-challenge
. Он также включает директиву перезаписи, которая направляет HTTP-запросы к корневому каталогу на HTTPS.Блок сервера HTTPS включает
ssl
иhttp2
. Чтобы узнать больше о том, как HTTP/2 повторяет протоколы HTTP, и о преимуществах, которые он может иметь для производительности веб-сайта, ознакомьтесь с введением в TLS-рукопожатие, которое может ускорить процесс аутентификации.Блок также указывает ваши учетные данные SSL и Diffie-Hellman и расположение ключей.
Наконец, вы переместили в этот блок информацию о пропуске прокси, включая блок местоположения с функцией «предварительной загрузки».
Закончив редактирование, сохраните и закройте файл.
Перед повторным созданием службы
webserver
вам необходимо добавить несколько вещей в определение службы в файлеdocker-compose.yml
, включая соответствующую информацию о порте для HTTPS и Diffie- Определение объема Хеллмана.Откройте файл:
- nano docker-compose.yml
В определении службы
webserver
добавьте следующее сопоставление портов и именованный томdhparam
:... webserver: image: nginx:latest container_name: webserver restart: unless-stopped ports: - "80:80" - "443:443" volumes: - web-root:/var/www/html - ./nginx-conf:/etc/nginx/conf.d - certbot-etc:/etc/letsencrypt - certbot-var:/var/lib/letsencrypt - dhparam:/etc/ssl/certs depends_on: - nodejs networks: - app-network
Затем добавьте том
dhparam
в свои определенияvolumes
. Не забудьте заменить каталогиsammy
иnode_project
на ваши:... volumes: ... webroot: ... dhparam: driver: local driver_opts: type: none device: /home/sammy/node_project/dhparam/ o: bind
Как и том
web-root
, томdhparam
смонтирует ключ Диффи-Хеллмана, хранящийся на хосте, в контейнерwebserver
.Сохраните и закройте файл, когда закончите редактирование.
Воссоздайте службу
webserver
:- docker-compose up -d --force-recreate --no-deps webserver
Проверьте свои сервисы с помощью
docker-compose ps
:- docker-compose ps
Следующий вывод показывает, что ваши службы
nodejs
иwebserver
запущены:OutputName Command State Ports ---------------------------------------------------------------------------------------------- certbot certbot certonly --webroot ... Exit 0 nodejs node app.js Up 8080/tcp webserver nginx -g daemon off; Up 0.0.0.0:443->443/tcp, 0.0.0.0:80->80/tcpНаконец, вы можете посетить свой домен, чтобы убедиться, что все работает должным образом. Перейдите в браузере по адресу
https://ваш_домен
, заменивваш_домен
своим собственным доменным именем:Значок замка должен появиться в индикаторе безопасности вашего браузера. При желании вы можете перейти на тестовую целевую страницу сервера Security Headers. Включенные параметры конфигурации должны принести вашему сайту рейтинг A в тесте сервера SSL Labs. Чтобы получить оценку A в тесте сервера Security Headers, вам нужно раскомментировать заголовок Strict Transport Security (HSTS) в вашем файле
nginx-conf/nginx.conf
:… location @nodejs { proxy_pass http://nodejs:8080; add_header X-Frame-Options "SAMEORIGIN" always; add_header X-XSS-Protection "1; mode=block" always; add_header X-Content-Type-Options "nosniff" always; add_header Referrer-Policy "no-referrer-when-downgrade" always; add_header Content-Security-Policy "default-src * data: 'unsafe-eval' 'unsafe-inline'" always; add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always; # enable strict transport security only if you understand the implications } …
Опять же, включите эту опцию только в том случае, если вы понимаете последствия и оценили ее функциональность «предварительной загрузки».
Шаг 6 — Обновление сертификатов
Сертификаты Let’s Encrypt действительны в течение 90 дней. Вы можете настроить автоматический процесс продления, чтобы гарантировать, что они не истечет. Один из способов сделать это — создать задание с помощью утилиты планирования
cron
. Вы можете запланировать заданиеcron
с помощью скрипта, который обновит ваши сертификаты и перезагрузит конфигурацию Nginx.Откройте скрипт с именем
ssl_renew.sh
в каталоге вашего проекта:- nano ssl_renew.sh
Добавьте в сценарий следующий код, чтобы обновить сертификаты и перезагрузить конфигурацию веб-сервера:
#!/bin/bash COMPOSE="/usr/local/bin/docker-compose --ansi never" DOCKER="/usr/bin/docker" cd /home/sammy/node_project/ $COMPOSE run certbot renew --dry-run && $COMPOSE kill -s SIGHUP webserver $DOCKER system prune -af
Этот сценарий сначала присваивает двоичный файл
docker-compose
переменной с именемCOMPOSE
и указывает параметр--no-ansi
, который будет запускатьdocker-compose
команды без управляющих символов ANSI. Затем он делает то же самое с двоичным файломdocker
. Наконец, он переходит в каталог~/node_project
и выполняет следующие командыdocker-compose
:docker-compose run
. Это запустит контейнерcertbot
и переопределиткоманду
, указанную вcertbot
. определение услуги. Вместо использования подкомандыcertonly
используйте подкомандуrenew
, которая обновит сертификаты, срок действия которых истекает. Также включен параметр--dry-run
для проверки скрипта. Сигнал SIGHUP
контейнеруwebserver
для перезагрузки конфигурации Nginx.
Затем он запускает
docker system prune
, чтобы удалить все неиспользуемые контейнеры и образы.Закройте файл, когда закончите редактирование, а затем сделайте его исполняемым:
- chmod +x ssl_renew.sh
Затем откройте корневой файл
crontab
, чтобы запускать скрипт обновления с заданным интервалом:sudo crontab -e
Если вы впервые редактируете этот файл, вам будет предложено выбрать редактор:
no crontab for root - using an empty one Select an editor. To change later, run 'select-editor'. 1. /bin/ed 2. /bin/nano <---- easiest 3. /usr/bin/vim.basic 4. /usr/bin/vim.tiny Choose 1-4 [2]: ...
В конце файла добавьте следующую строку:
... */5 * * * * /home/sammy/node_project/ssl_renew.sh >> /var/log/cron.log 2>&1
Это установит интервал задания каждые пять минут, чтобы вы могли проверить, сработал ли ваш запрос на продление, как предполагалось. Вы также создали файл журнала
cron.log
для записи соответствующих выходных данных задания.Через пять минут проверьте
cron.log
, чтобы убедиться, что запрос на продление выполнен успешно:- tail -f /var/log/cron.log
Через несколько секунд следующий вывод сигнализирует об успешном обновлении:
Output- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ** DRY RUN: simulating 'certbot renew' close to cert expiry ** (The test certificates below have not been saved.) Congratulations, all renewals succeeded. The following certs have been renewed: /etc/letsencrypt/live/your_domain/fullchain.pem (success) ** DRY RUN: simulating 'certbot renew' close to cert expiry ** (The test certificates above have not been saved.) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Killing webserver ... doneOutput… Congratulations, all simulated renewals succeeded: /etc/letsencrypt/live/your_domain/fullchain.pem (success) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Saving debug log to /var/log/letsencrypt/letsencrypt.log Killing webserver ... Killing webserver ... done Deleted Containers: 00cad94050985261e5b377de43e314b30ad0a6a724189753a9a23ec76488fd78 Total reclaimed space: 824.5kBВыйдите, введя
CTRL + C
в своем терминале.Теперь вы можете изменить файл
crontab
, чтобы установить дневной интервал. Например, чтобы запускать скрипт каждый день в полдень, вы можете изменить последнюю строку файла следующим образом:... 0 12 * * * /home/sammy/node_project/ssl_renew.sh >> /var/log/cron.log 2>&1
Вы также можете удалить параметр
--dry-run
из сценарияssl_renew.sh
:#!/bin/bash COMPOSE="/usr/local/bin/docker-compose --no-ansi" DOCKER="/usr/bin/docker" cd /home/sammy/node_project/ $COMPOSE run certbot renew && $COMPOSE kill -s SIGHUP webserver $DOCKER system prune -af
Ваше задание
cron
гарантирует, что ваши сертификаты Let’s Encrypt не истечет, обновляя их, когда они соответствуют требованиям. Вы также можете настроить ротацию журналов с помощью утилиты Logrotate для ротации и сжатия файлов журналов.Заключение
Вы использовали контейнеры для настройки и запуска приложения Node с обратным прокси-сервером Nginx. Вы также защитили SSL-сертификаты для домена своего приложения и настроили задание
cron
для обновления этих сертификатов при необходимости.Если вы хотите узнать больше о подключаемых модулях Let’s Encrypt, ознакомьтесь с нашими статьями об использовании автономного подключаемого модуля.
Вы также можете узнать больше о Docker Compose из следующих ресурсов:
- Как установить Docker Compose в Ubuntu 18.04.
- Как настроить среду тестирования непрерывной интеграции с помощью Docker и Docker Compose в Ubuntu 16.04.
- Как настроить Laravel, Nginx и MySQL с помощью Docker Compose.
Документация по Compose также является отличным ресурсом для получения дополнительной информации о многоконтейнерных приложениях.
- Запись A с