Table of Contents
*Автор выбрал фонд Организации Объединенных Наций для получения пожертвования в рамках программы Write for DOnations.*
*Оригинальная версия WordPress этого обучающего руководства была написана Кэйтлин Джуэлл (Kathleen Juell).*
Введение
Drupal — это система управления контентом (CMS), написанная на PHP и распространяемая по универсальной общественной лицензии GNU с открытым исходным кодом. Люди и организации по всему миру используют Drupal для управления правительственными сайтами, ведения личных блогов, бизнеса и не только. Уникальные отличия Drupal от других структур CMS: растущее сообщество и набор функций, которые включают безопасные процессы, надежную работу и адаптивность.
Для Drupal необходимо установить стек LAMP (Linux, Apache, MySQL и PHP) или LEMP (Linux, Nginx, MySQL и PHP), но установка компонентов по отдельности занимает много времени. Для упрощения процесса установки Drupal мы можем использовать такие инструменты, как Docker и Docker Compose. В этом обучающем руководстве будут использованы образы Docker для установки отдельных компонентов в Docker-контейнерах. С помощью Docker Compose мы можем определять и управлять несколькими контейнерами для базы данных, приложения, а также взаимодействием/коммуникацией между ними.
В этом обучающем руководстве мы установим Drupal с помощью Docker Compose для возможности контейнеризации и развертывания нашего веб-сайта Drupal на серверах. Мы запустим контейнеры для базы данных MySQL, веб-сервера Nginx и системы Drupal. Также мы защитим нашу установку, получив сертификаты TLS/SSL с Let’s Encrypt для домена, который мы хотим ассоциировать с нашим сайтом. Наконец, мы настроим задание cron для обновления ваших сертификатов, чтобы домен оставался защищенным.
Предварительные требования
Для данного обучающего руководства нам потребуется следующее:
- Сервер на базе Ubuntu 18.04, а также пользователь без прав root с привилегиями
sudoи активный брандмауэр. Дополнительную информацию о настройке этих параметров см. в руководстве по первоначальной настройке сервера.
- Система Docker, установленная на сервере в соответствии с шагами 1 и 2 руководства Установка и использование Docker в Ubuntu 18.04. Это обучающее руководство было протестировано на версии 19.03.8.
- Docker Compose, установленный на сервере в соответствии с шагом 1 руководства Установка Docker Compose в Ubuntu 18.04. Это обучающее руководство было протестировано на версии 1.21.2.
- Зарегистрированное доменное имя. В этом обучающем руководстве мы будем использовать
your_domain. Вы можете получить бесплатный домен на Freenom или зарегистрировать доменное имя по вашему выбору.
- На вашем сервере должны быть настроены обе нижеследующие записи DNS. Вы можете воспользоваться введением в работу с DNS hosting, чтобы получить подробную информацию о добавлении доменов в учетную запись the cloud provider, если вы используете этот способ:
- Запись A, где
<^>your_domain<^>указывает на публичный IP-адрес вашего сервера.
- Запись A, где
www.<^>your_domain<^>указывает на публичный IP-адрес вашего сервера.
Шаг 1 — Настройка конфигурации веб-сервера
Перед запуском контейнеров нам нужно определить конфигурацию для нашего веб-сервера Nginx. Наш файл конфигурации будет включать несколько специфических для Drupal блоков расположения наряду с блоками расположения, которые будут направлять передаваемые запросы верификации Let's Encrypt клиенту Certbot для автоматизированного обновления сертификатов.
Вначале создадим директорию проекта для нашей настройки Drupal с именем drupal:
mkdir <^>drupal<^>
Перейдите в недавно созданную директорию:
cd <^>drupal<^>
Теперь мы можем создать директорию для нашего файла конфигурации:
mkdir <^>nginx-conf<^>
Откройте файл с помощью nano или своего любимого редактора:
nano nginx-conf/nginx.conf
В этом файле мы добавим серверный блок с директивами для имени нашего сервера и корневой директории документов, а также блок расположения для направления запросов сертификатов от клиента Certbot, обработки PHP и запросов статичных активов.
Добавьте в этот файл следующий код. Обязательно замените <^>your_domain<^> на ваше доменное имя:
[label ~/drupal/nginx-conf/nginx.conf]
server {
listen 80;
listen [::]:80;
server_name <^>your_domain<^> www.<^>your_domain<^>;
index <^>index.php<^> index.html index.htm;
root /var/www/html;
location ~ /.well-known/acme-challenge {
allow all;
root /var/www/html;
}
location / {
try_files $uri $uri/ /index.php$is_args$args;
}
rewrite ^/core/authorize.php/core/authorize.php(.*)$ /core/authorize.php$1;
location ~ \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass <^>drupal<^>:9000;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
}
location ~ /\.ht {
deny all;
}
location = /favicon.ico {
log_not_found off; access_log off;
}
location = /robots.txt {
log_not_found off; access_log off; allow all;
}
location ~* \.(css|gif|ico|jpeg|jpg|js|png)$ {
expires max;
log_not_found off;
}
}
Наш серверный блок содержит следующую информацию:
Директивы:
listen: данный элемент просит Nginx прослушивать порт80, что позволит нам использовать плагин webroot Certbot для наших запросов сертификатов. Обратите внимание, что мы пока не будем включать порт443, мы обновим нашу конфигурацию и добавим SSL после успешного получения наших сертификатов.
server_name: этот элемент определяет имя нашего сервера и серверный блок, которые должны использоваться для запросов к нашему серверу. Обязательно замените<^>your_domain<^>в этой строке на ваше собственное доменное имя.
index: директива index определяет файлы, которые будут использоваться в качестве индексов при обработке запросов к нашему серверу. Здесь мы изменили порядок приоритета по умолчанию, поставивindex.phpпередindex.html, в результате чего Nginx будет давать приоритет файлам с именемindex.phpпри наличии возможности.
root: наша директива root назначает имя корневой директории для запросов к нашему серверу. Эта директория,/var/www/html, создается в качестве точки монтирования в момент сборки с помощью инструкций в файле Dockerfile Drupal. Эти инструкции Dockerfile также гарантируют, что файлы релиза Drupal монтируются в этот том.
rewrite: если указанное регулярное выражение (<^>^/core/authorize.php/core/authorize.php(.*)$<^>) соответствует запросу URI, URI меняется согласно указаниям в строке замены (<^>/core/authorize.php$1<^>).
Блоки расположения:
location ~ /.well-known/acme-challenge: этот блок расположения будет обрабатывать запросы в директории.well-known, где Certbot будет размещать временный файл для подтверждения того, что DNS для нашего домена будет работать с нашим сервером. Настроив данную конфигурацию, мы сможем использовать плагин webroot Certbot для получения сертификатов для нашего домена.
location /: в этом блоке расположения мы будем использовать директивуtry_filesдля проверки файлов, соответствующих отдельным запросам URI. Вместо того чтобы возвращать по умолчанию статус404 Not Found, мы будем передавать контроль файлуindex.phpDrupal с аргументами запроса.
location ~.php$: этот блок расположения будет обрабатывать PHP-запросы и проксировать эти запросы в наш контейнер drupal. Поскольку наш образ Drupal Docker будет опираться на образphp:fpm, мы также добавим параметры конфигурации, принадлежащие протоколу FastCGI, в этот блок. Nginx требует наличия независимого процессора PHP для запросов PHP: в нашем случае эти запросы будут обрабатываться процессоромphp-fpm, который будет включать образphp:fpm. Кроме того, этот блок расположения содержит директивы FastCGI, переменные и параметры, которые будут проксировать запросы для приложения Drupal, запущенного в нашем контейнере Drupal, задавать предпочитаемый индекс захваченного URI запроса, а также выполнять парсинг запросов URI.
location ~ /.ht: этот блок будет обрабатывать файлы.htaccess, поскольку Nginx не будет обслуживать их. Директиваdeny_allгарантирует, что файлы.htaccessникогда не будут отображаться для пользователей.
location = /favicon.ico, location = /robots.txt: эти блоки гарантируют, что запросы для/favicon.icoи/robots.txtне будут регистрироваться.
location ~* .(css|gif|ico|jpeg|jpg|js|png)$: этот блок отключает запись в журнал для запросов статичных активов и гарантирует, что эти активы будут иметь высокую кэшируемость, поскольку обычно их трудно обслуживать.
Дополнительную информацию о проксировании FastCGI см. в статье Понимание и реализация проксирования FastCGI в Nginx. Информацию о серверных блоках и блоках расположения см. в статье Знакомство с сервером Nginx и алгоритмы выбора блоков расположения.
Сохраните и закройте файл после завершения редактирования.
После настройки конфигурации Nginx вы можете перейти к созданию переменных среды для передачи в контейнеры приложения и базы данных во время исполнения.
Шаг 2 — Настройка переменных среды
Для сохранения информации, связанной с сайтом, нашему приложению Drupal требуется база данных (MySQL, PostgresSQL и др.). Контейнеру Drupal потребуется доступ к определенным переменным среды во время исполнения, чтобы получить доступ к контейнеру базы данных (MySQL). Эти переменные содержат конфиденциальную информацию, например учетные данные базы данных, поэтому мы не можем раскрыть ее непосредственно в файле Docker Compose — главном файле, содержащем информацию о том, как будут работать наши контейнеры.
Рекомендуется всегда помещать конфиденциальные значения в файл .env и ограничить их использование до внутреннего. Это не позволит скопировать эти значения в репозиторий нашего проекта и открыть их для общего доступа.
В главной директории проекта ~/drupal, создайте и откройте файл .env:
nano .env
Добавьте в файл .env следующие переменные, заменив выделенные части на учетные данные, которые вы хотите использовать:
[label ~/drupal/.env]
MYSQL_ROOT_PASSWORD=<^>root_password<^>
MYSQL_DATABASE=<^>drupal<^>
MYSQL_USER=<^>drupal_database_user<^>
MYSQL_PASSWORD=<^>drupal_database_password<^>
Теперь мы добавили пароль для административной учетной записи root MySQL, а также предпочитаемые имя пользователя и пароль для нашей базы данных приложения.
Наш файл .env содержит конфиденциальную информацию, поэтому его всегда рекомендуется включать в файлы проекта .gitignore и .dockerignore, чтобы ее нельзя было добавить в наши репозитории Git и образы Docker.
Если вы планируете использовать Git для контроля версий, инициализируйте текущую рабочую директорию в качестве репозитория с помощью git init:
git init
Откройте файл .gitignore:
nano .gitignore
Добавьте следующее:
[label ~/drupal/.gitignore]
.env
Сохраните и закройте файл.
Подобным образом откройте файл .dockerignore:
nano .dockerignore
Затем добавьте следующее:
[label ~/drupal/.dockerignore]
.env
.git
Сохраните и закройте файл.
Теперь, когда мы приняли меры для защиты наших учетных данных как переменных среды, перейдем к следующему шагу определения наших служб в файле docker-compose.yml.
Шаг 3 — Определение служб с помощью Docker Compose
Docker Compose — это инструмент для определения и запуска многоконтейнерных приложений. Мы определяем файл YAML для настройки служб нашего приложения. *Служба* Docker Compose — это запущенный контейнер, и Compose позволяет нам связывать эти службы с общими томами и сетями.
Мы создадим разные контейнеры для нашего приложения, базы данных и веб-сервера Drupal. Также мы создадим контейнер для запуска Certbot, чтобы получить сертификаты для нашего веб-сервера.
Создайте файл docker-compose.yml:
nano docker-compose.yml
Добавьте следующий код для определения версии файла Compose и службы базы данных mysql:
[label ~/drupal/docker-compose.yml]
version: "3"
services:
mysql:
image: mysql:8.0
container_name: mysql
command: --default-authentication-plugin=mysql_native_password
restart: unless-stopped
env_file: .env
volumes:
- db-data:/var/lib/mysql
networks:
- internal
Давайте пройдемся по ним отдельно со всеми параметрами настройки службы mysql:
image: указывает образ, который будет использоваться/извлекаться для создания контейнера. Чтобы избежать конфликтов в будущем, рекомендуется всегда использовать образ с соответствующей версией тега, кроме тегаlatest. Подробнее об оптимальных методах использования Dockerfile узнайте в документации Docker.
container_name: определяет имя контейнера.
command: используется для отмены команды по умолчанию (инструкции CMD) в образе. MySQL поддерживает разные плагины аутентификации, ноmysql_native_password— это традиционный способ аутентификации. Поскольку PHP и, следовательно, Drupal не будут поддерживать более новую аутентификацию MySQL, необходимо установить--default-authentication-plugin=mysql_native_password в качестве механизма аутентификации по умолчанию.
restart: используется для определения политики контейнера. Политикаunless-stopped повторно запускает контейнер, пока он не будет остановлен вручную.
env_file: добавляет переменные среды из файла. В нашем случае он будет считывать переменные среды из файла.env, определенные в предыдущем шаге.
volumes: монтирует пути к хосту или томам с именем, указанным как подпараметры службы. Мы монтируем том с именемdb-dataв директорию/var/lib/mysqlв контейнере, куда MySQL по умолчанию будет записывать свои файлы данных.
networks: определяет сетьinternal, к которой подключится наша служба приложения. Мы определим сети в конце файла.
Мы дали определение нашей службы mysql, а теперь добавим определение службы приложения drupal в конец файла:
[label ~/drupal/docker-compose.yml]
...
drupal:
image: drupal:8.7.8-fpm-alpine
container_name: drupal
depends_on:
- mysql
restart: unless-stopped
networks:
- internal
- external
volumes:
- drupal-data:/var/www/html
В этом определении службы мы называем наш контейнер и определяем политику перезапуска, как уже делали это для службы mysql. Также мы добавляем в этот контейнер ряд параметров:
image: здесь мы используем образ Drupal8.7.8-fpm-alpine. Этот образ содержит процессорphp-fpm, для которого наш веб-сервер Nginx должен выполнять обработку PHP. Кроме того, мы используем образalpine, полученный из проекта Alpine Linux, который уменьшит размер всего образа и рекомендуется в оптимальных методах использования Dockerfile. Drupal имеет несколько версий и образов, ознакомьтесь с ними в Dockerhub.
depends_on: используется для выражения зависимости между службами. Определение службыmysqlкак зависимости к нашему контейнеруdrupalобеспечит создание контейнераdrupalпосле контейнераmysql и поможет успешно запустить наше приложение.
networks: здесь мы добавили этот контейнер в сетьexternalвместе с сетьюinternal. Таким образом доступ к службеmysql будет возможен только из контейнераdrupalпо сетиinternal, но при этом доступ других контейнеров по сетиexternalк этому контейнеру будет сохранен.
volumes: мы монтируем том с именемdrupal-dataна точку монтирования/var/www/html, созданную образом Drupal. Использование тома с именем таким образом позволит разделить наш код приложения с другими контейнерами.
Далее добавим определение службы Nginx после определения службы drupal:
[label ~/drupal/docker-compose.yml]
...
webserver:
image: nginx:1.17.4-alpine
container_name: webserver
depends_on:
- drupal
restart: unless-stopped
ports:
- 80:80
volumes:
- drupal-data:/var/www/html
- ./nginx-conf:/etc/nginx/conf.d
- certbot-etc:/etc/letsencrypt
networks:
- external
Мы снова присвоим имя нашему контейнеру и сделаем его зависимым от контейнера Drupal в отношении порядка запуска. Также мы используем образ alpine — образ Nginx 1.17.4-alpine.
Это определение службы также включает следующие параметры:
ports: этот параметр открывает порт80, чтобы активировать параметры конфигурации, определенные нами в файлеnginx.confв шаге 1.
volumes: здесь мы определяем том с именем и путь хоста:
drupal-data:/var/www/html: этот параметр будет монтировать код нашего приложения Drupal в директорию/var/www/html, директорию, которую мы задали в качестве корневой директории в нашем серверном блоке Nginx.
./nginx-conf:/etc/nginx/conf.d: этот элемент будет монтировать директорию конфигурации Nginx на хост в соответствующую директорию в контейнере, гарантируя, что любые изменения, которые мы вносим в файлы на хосте, будут отражены в контейнере.
certbot-etc:/etc/letsencrypt: этот элемент будет монтировать соответствующие сертификаты и ключи Let's Encrypt для нашего домена в соответствующую директорию контейнера.
networks: мы определили сетьexternal только для того, чтобы этот контейнер мог обмениваться данными с контейнеромdrupal, а не с контейнеромmysql.
Наконец, мы добавим наше последнее определение для службы certbot. Обязательно замените <^>sammy@your_domain<^> и <^>your_domain<^> на свой адрес эл. почты и доменное имя:
[label ~/drupal/docker-compose.yml]
...
certbot:
depends_on:
- webserver
image: certbot/certbot
container_name: certbot
volumes:
- certbot-etc:/etc/letsencrypt
- drupal-data:/var/www/html
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 и код приложения в drupal-data.
Мы также использовали depends_on, чтобы убедиться, что контейнер certbot будет запущен после запуска службы webserver.
Мы не указали здесь networks, поскольку этот контейнер не будет обмениваться данными с какими-либо службами по сети. Это просто добавление доменных сертификатов и ключа, которые мы монтировали с помощью томов с именем.
Также мы включили параметр command, указывающий субкоманду для запуска с используемой контейнером по умолчанию командой certbot. Клиент Certbot поддерживает плагины для получения и установки сертификатов. Мы используем плагин webroot для получения сертификата путем включения certonly и --webroot в командную строку. Подробнее о плагине и дополнительных командах читайте в официальной документации Certbot.
Под определением службы certbot добавьте определения сети и тома:
[label ~/drupal/docker-compose.yml]
...
networks:
external:
driver: bridge
internal:
driver: bridge
volumes:
drupal-data:
db-data:
certbot-etc:
Ключ верхнего уровня networks позволяет нам указывать, какие сети необходимо создать. networks обеспечивает коммуникацию между службами/контейнерами во всех портах, так как они находятся на одном и том же хосте демона Docker. Мы определили две сети, internal и external, для защиты коммуникации между службами webserver, drupal и mysql.
Ключ volumes используется для определения томов с именем drupal-data, db-data и certbot-etc. Когда Docker создает тома, содержимое тома сохраняется в директории файловой системы хоста, /var/lib/docker/volumes/, а данным процессом управляет Docker. После этого содержимое каждого тома монтируется из этой директории в любой контейнер, использующий том. Таким образом мы можем делиться кодом и данными между контейнерами.
Итоговый файл docker-compose.yml будет выглядеть примерно так:
[label ~/drupal/docker-compose.yml]
version: "3"
services:
mysql:
image: mysql:8.0
container_name: mysql
command: --default-authentication-plugin=mysql_native_password
restart: unless-stopped
env_file: .env
volumes:
- db-data:/var/lib/mysql
networks:
- internal
drupal:
image: drupal:8.7.8-fpm-alpine
container_name: drupal
depends_on:
- mysql
restart: unless-stopped
networks:
- internal
- external
volumes:
- drupal-data:/var/www/html
webserver:
image: nginx:1.17.4-alpine
container_name: webserver
depends_on:
- drupal
restart: unless-stopped
ports:
- 80:80
volumes:
- drupal-data:/var/www/html
- ./nginx-conf:/etc/nginx/conf.d
- certbot-etc:/etc/letsencrypt
networks:
- external
certbot:
depends_on:
- webserver
image: certbot/certbot
container_name: certbot
volumes:
- certbot-etc:/etc/letsencrypt
- drupal-data:/var/www/html
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<^>
networks:
external:
driver: bridge
internal:
driver: bridge
volumes:
drupal-data:
db-data:
certbot-etc:
Мы завершили определение наших служб. Далее запустим контейнер и протестируем наши запросы сертификата.
Шаг 4 — Получение сертификатов SSL и учетных данных
Мы можем запустить наши контейнеры с помощью команды docker-compose up, которая будет создавать и запускать наши контейнеры и службы в указанном нами порядке. Если наши запросы доменов будут выполнены успешно, мы увидим корректный статус выхода в нашем выводе и нужные сертификаты, установленные в папке /etc/letsencrypt/live на контейнере веб-сервера.
Чтобы запустить контейнеры в фоновом режиме, используйте команду docker-compose up с флагом -d:
docker-compose up -d
Вы увидите аналогичный вывод, подтверждающий, что ваши службы были успешно созданы:
[secondary_label Output]
...
Creating mysql ... done
Creating drupal ... done
Creating webserver ... done
Creating certbot ... done
Проверьте статус служб с помощью команды docker-compose ps:
docker-compose ps
Мы увидим службы mysql, drupal и webserver с State в значении Up, а выход из certbot будет выполнен с сообщением о статусе 0:
[secondary_label Output]
Name Command State Ports
--------------------------------------------------------------------------
certbot certbot certonly --webroot ... Exit 0
drupal docker-php-entrypoint php-fpm Up 9000/tcp
mysql docker-entrypoint.sh --def ... Up 3306/tcp, 33060/tcp
webserver nginx -g daemon off; Up 0.0.0.0:80->80/tcp
Если вы увидите любое значение, кроме Up в столбце State для служб mysql, drupal или webserver, или любое сообщение о статусе выхода, отличающееся от 0, для контейнера certbot, проверьте журналы службы с помощью команды docker-compose logs:
docker-compose logs <^>service_name<^>
Теперь мы можем проверить, что наши сертификаты установлены на контейнере webserver, с помощью команды docker-compose exec:
docker-compose exec webserver ls -la /etc/letsencrypt/live
Результат будет выглядеть следующим образом:
[secondary_label Output]
total 16
drwx------ 3 root root 4096 Oct 5 09:15 .
drwxr-xr-x 9 root root 4096 Oct 5 09:15 ..
-rw-r--r-- 1 root root 740 Oct 5 09:15 README
drwxr-xr-x 2 root root 4096 Oct 5 09:15 <^>your_domain<^>
Теперь, когда все работает успешно, мы можем изменить определение службы certbot, чтобы удалить флаг --staging.
Откройте файл docker-compose.yml, найдите определение службы certbot и замените флаг --staging в параметрах команды на флаг --force-renewal, который будет указывать Certbot, что вы хотите запросить новый сертификат с теми же доменами, что и в уже существующем сертификате. Обновленное определение certbot будет выглядеть примерно следующим образом:
[label ~/drupal/docker-compose.yml]
...
certbot:
depends_on:
- webserver
image: certbot/certbot
container_name: certbot
volumes:
- certbot-etc:/etc/letsencrypt
- drupal-data:/var/www/html
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
Мы увидим вывод, указывающий, что запрос сертификата выполнен успешно:
[secondary_label Output]
Recreating certbot ... done
Attaching to certbot
certbot | Saving debug log to /var/log/letsencrypt/letsencrypt.log
certbot | Plugins selected: Authenticator webroot, Installer None
certbot | Renewing an existing certificate
certbot | Performing the following challenges:
certbot | http-01 challenge for <^>your_domain<^>
certbot | http-01 challenge for <^>www.your_domain<^>
certbot | Using the webroot path /var/www/html for all unmatched domains.
certbot | Waiting for verification...
certbot | Cleaning up challenges
certbot | IMPORTANT NOTES:
certbot | - Congratulations! Your certificate and chain have been saved at:
certbot | /etc/letsencrypt/live/<^>your_domain<^>/fullchain.pem
certbot | Your key file has been saved at:
certbot | /etc/letsencrypt/live/<^>your_domain<^>/privkey.pem
certbot | Your cert will expire on 2020-01-03. To obtain a new or tweaked
certbot | version of this certificate in the future, simply run certbot
certbot | again. To non-interactively renew *all* of your certificates, run
certbot | "certbot renew"
certbot | - Your account credentials have been saved in your Certbot
certbot | configuration directory at /etc/letsencrypt. You should make a
certbot | secure backup of this folder now. This configuration directory will
certbot | also contain certificates and private keys obtained by Certbot so
certbot | making regular backups of this folder is ideal.
certbot | - If you like Certbot, please consider supporting our work by:
certbot |
certbot | Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate
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
Результат будет выглядеть следующим образом:
[secondary_label Output]
Stopping webserver ... done
Затем удалим ранее созданный файл конфигурации Nginx:
rm nginx-conf/nginx.conf
Откройте другую версию файла:
nano nginx-conf/nginx.conf
Добавьте следующий код в файл для перенаправления HTTP на HTTPS и добавления учетных данных, протоколов и заголовков безопасности SSL. Не забудьте заменить <^>your_domain<^> на свой собственный домен:
[label ~/drupal/nginx-conf/nginx.conf]
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;
listen [::]:443 ssl;
server_name <^>your_domain<^> www.<^>your_domain<^>;
index <^>index.php<^> index.html index.htm;
root /var/www/html;
server_tokens off;
ssl_certificate /etc/letsencrypt/live/<^>your_domain<^>/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/<^>your_domain<^>/privkey.pem;
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;
location / {
try_files $uri $uri/ /index.php$is_args$args;
}
rewrite ^/core/authorize.php/core/authorize.php(.*)$ /core/authorize.php$1;
location ~ \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass <^>drupal<^>:9000;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
}
location ~ /\.ht {
deny all;
}
location = /favicon.ico {
log_not_found off; access_log off;
}
location = /robots.txt {
log_not_found off; access_log off; allow all;
}
location ~* \.(css|gif|ico|jpeg|jpg|js|png)$ {
expires max;
log_not_found off;
}
}
Блок сервера HTTP указывает плагин webroot для запросов обновления Certbot в директории .well-known/acme-challenge. Также он содержит директиву перезаписи, которая перенаправляет запросы HTTP в корневую директорию HTTPS.
Блок сервера HTTPS активирует ssl и http2. Дополнительную информацию о том, как выполняется итерация HTTP/2 в протоколах HTTP и какие преимущества это может дать для повышения производительности веб-сайта, см. во вводной части руководства по настройке Nginx с поддержкой HTTP/2 в Ubuntu 18.04.
Эти блоки активируют SSL, поскольку мы включили наш сертификат SSL и места расположения ключей, а также рекомендуемые заголовки. Эти заголовки позволят нам получить рейтинг А на SSL Labs и сайтах тестирования сервера Security Headers.
Наши директивы root и index также расположены в этом блоке, равно как и остальные блоки расположения Drupal, описанные в шаге 1.
Сохраните и закройте обновленный файл конфигурации Nginx.
Прежде чем воссоздать контейнер webserver, необходимо добавить сопоставление порта 443 в наше определение службы webserver, поскольку мы активировали сертификаты SSL.
Откройте файл docker-compose.yml:
nano docker-compose.yml
Сделайте следующие изменения в определении службы webserver:
[label ~/drupal/docker-compose.yml]
...
webserver:
image: nginx:1.17.4-alpine
container_name: webserver
depends_on:
- drupal
restart: unless-stopped
ports:
- 80:80
<^>- 443:443<^>
volumes:
- drupal-data:/var/www/html
- ./nginx-conf:/etc/nginx/conf.d
- certbot-etc:/etc/letsencrypt
networks:
- external
...
После активации сертификатов SSL наш файл docker-compose.yml будет выглядеть следующим образом:
[label ~/drupal/docker-compose.yml]
version: "3"
services:
mysql:
image: mysql:8.0
container_name: mysql
command: --default-authentication-plugin=mysql_native_password
restart: unless-stopped
env_file: .env
volumes:
- db-data:/var/lib/mysql
networks:
- internal
drupal:
image: drupal:8.7.8-fpm-alpine
container_name: drupal
depends_on:
- mysql
restart: unless-stopped
networks:
- internal
- external
volumes:
- drupal-data:/var/www/html
webserver:
image: nginx:1.17.4-alpine
container_name: webserver
depends_on:
- drupal
restart: unless-stopped
ports:
- 80:80
- 443:443
volumes:
- drupal-data:/var/www/html
- ./nginx-conf:/etc/nginx/conf.d
- certbot-etc:/etc/letsencrypt
networks:
- external
certbot:
depends_on:
- webserver
image: certbot/certbot
container_name: certbot
volumes:
- certbot-etc:/etc/letsencrypt
- drupal-data:/var/www/html
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<^>
networks:
external:
driver: bridge
internal:
driver: bridge
volumes:
drupal-data:
db-data:
certbot-etc:
Сохраните и закройте файл. Давайте воссоздадим службу webserver с нашей обновленной конфигурацией:
docker-compose up -d --force-recreate --no-deps webserver
Результат будет выглядеть следующим образом:
[secondary_label Output]
Recreating webserver ... done
Проверьте службы с помощью команды docker-compose ps:
docker-compose ps
Мы увидим службы mysql, drupal и webserver со значением Up, а выход из certbot будет выполнен с сообщением о статусе 0:
[secondary_label Output]
Name Command State Ports
--------------------------------------------------------------------------
certbot certbot certonly --webroot ... Exit 0
drupal docker-php-entrypoint php-fpm Up 9000/tcp
mysql docker-entrypoint.sh --def ... Up 3306/tcp, 33060/tcp
webserver nginx -g daemon off; Up 0.0.0.0:443->443/tcp, 0.0.0.0:80->80/tcp
Теперь все наши службы запущены, и мы можем продолжить установку Drupal через веб-интерфейс.
Шаг 6 — Завершение установки через веб-интерфейс
Давайте выполним установку через веб-интерфейс Drupal.
В браузере перейдите к домену сервера. Не забудьте заменить здесь your_domain на ваше доменное имя:
https://<^>your_domain<^>
Выберите язык:
Нажмите Сохранить и продолжить. Мы перейдем на страницу Профиль установки. Drupal имеет несколько профилей, поэтому выберите стандартный профиль и нажмите Сохранить и продолжить.
После выбора профиля мы перейдем к странице Конфигурация базы данных. Выберите тип базы данных MySQL, MySQL, MariaDB, Percona Server или аналогичная и введите значения для Имя базы данных, имя пользователя и пароль из значений, соответствующих MYSQL_DATABASE, MYSQL_USER и MYSQL_PASSWORD, определенных соответственно в файле .env в шаге 2. Нажмите Расширенные параметры и установите значение Хост, соответствующее контейнеру службы mysql. Нажмите Сохранить и продолжить.
После настройки базы данных начнется установка модулей и тем Drupal по умолчанию:
После установки сайта мы перейдем к странице настройки сайта Drupal для настройки имени сайта, электронной почты, имени пользователя, пароля и региональных параметров. Заполните информацию и нажмите Сохранить и продолжить:
После нажатия Сохранить и продолжить мы увидим страницу Добро пожаловать в Drupal, которая показывает, что наш сайт Drupal готов и работает успешно.
Теперь после завершения установки Drupal необходимо убедиться, что наши сертификаты SSL будут обновляться автоматически.
Шаг 7 — Обновление сертификатов
Сертификаты Let's Encrypt действительны в течение 90 дней, поэтому нам нужно будет настроить процесс автоматического обновления, чтобы гарантировать, что сертификаты не окажутся просроченными. Один из способов — создание задания с помощью утилиты планирования cron. В нашем случае мы настроим задание для cron с помощью скрипта, который будет обновлять наши сертификаты и перезагружать конфигурацию Nginx.
Давайте создадим файл ssl_renew.sh для обновления наших сертификатов:
nano ssl_renew.sh
Добавьте следующий код. Не забудьте заменить имя директории на своего собственного пользователя без прав root:
[label ~/drupal/ssl_renew.sh]
#!/bin/bash
cd /home/<^>sammy<^>/drupal/
/usr/local/bin/docker-compose -f docker-compose.yml run certbot renew --dry-run && \
/usr/local/bin/docker-compose -f docker-compose.yml kill -s SIGHUP webserver
Этот скрипт меняет директорию проекта ~/drupal и запускает следующие команды docker-compose.
docker-compose run: данный параметр запускает контейнерcertbotи переопределяет параметрcommand, указанный в определении службыcertbot. Вместо использования субкомандыcertonlyмы используем здесь субкомандуrenew, которая будет обновлять сертификаты, срок действия которых близок к окончанию. Мы включили параметр--dry-run, чтобы протестировать наш скрипт.
docker-compose kill: данный параметр отправляет сигналSIGHUPконтейнеруwebserverдля перезагрузки конфигурации Nginx.
Закройте файл и настройте его исполняемость, запустив следующую команду:
sudo chmod +x ssl_renew.sh
Далее откройте root-файл crontab для запуска скрипта обновления с заданным интервалом:
sudo crontab -e
Если вы впервые редактируете файл, вас попросят выбрать текстовый редактор, чтобы открыть файл с его помощью:
[secondary_label Output]
no crontab for root - using an empty one
Select an editor. To change later, run 'select-editor'.
1. /bin/nano
2. /usr/bin/vim.basic
3. /usr/bin/vim.tiny
4. /bin/ed
Choose 1-4 [1]:
...
В конце файла добавьте следующую строку, заменив sammy на ваше имя пользователя:
[label crontab]
...
*/5 * * * * /home/<^>sammy<^>/drupal/ssl_renew.sh >> /var/log/cron.log 2>&1
В результате будет установлен интервал в пять минут для выполнения работы, и мы сможем проверить, работает ли запрос обновления в соответствии с ожиданиями. Также мы создали файл журнала, cron.log, чтобы записывать соответствующий вывод выполнения задания.
Через пять минут воспользуйтесь командой tail для проверки cron.log, чтобы увидеть, выполнен ли запрос обновления:
tail -f /var/log/cron.log
Вы увидите вывод, подтверждающий успешное обновление:
[secondary_label 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.)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Нажмите CTRL+C, чтобы завершить процесс tail.
Теперь мы можем изменить файл crontab для запуска скрипта каждый 2-й день недели в 2:00. Измените последнюю строку crontab на следующее:
[label crontab]
...
* 2 * * 2 /home/<^>sammy<^>/drupal/ssl_renew.sh >> /var/log/cron.log 2>&1
Закройте и сохраните файл.
Теперь удалим параметр --dry-run из скрипта ssl_renew.sh. Сначала откройте его:
nano ssl_renew.sh
Затем измените содержимое на следующее:
[label ~/drupal/ssl_renew.sh]
#!/bin/bash
cd /home/<^>sammy<^>/drupal/
/usr/local/bin/docker-compose -f docker-compose.yml run certbot renew && \
/usr/local/bin/docker-compose -f docker-compose.yml kill -s SIGHUP webserver
Теперь наше задание cron будет выполнять обновление сертификатов SSL.
Заключение
В этом руководстве мы использовали Docker Compose для создания установки Drupal с веб-сервером Nginx. В рамках этого рабочего процесса мы получили сертификаты TLS/SSL для домена, который мы хотели ассоциировать с сайтом Drupal, и создали задание cron для обновления этих сертификатов при необходимости.
Для получения дополнительной информации посетите тематическую страницу Docker.