Table of Contents
Введение
WordPress — бесплатная система управления контентом (CMS) с открытым исходным кодом, которая опирается на базу данных MySQL и обрабатывает запросы с помощью PHP. Благодаря огромному количеству плагинов и системе шаблонов, а также тому факту, что большая часть административных функций может производиться через веб-интерфейс, WordPress завоевала популярность среди создателей самых разных сайтов, от блогов и страниц с описанием продукта и до сайтов электронной торговли.
Для запуска WordPress, как правило, требуется установка стека LAMP (Linux, Apache, MySQL и PHP) или LEMP (Linux, Nginx, MySQL и PHP), что может занять много времени. С помощью таких инструментов, как Docker и Docker Compose, вы можете упростить процесс настройки предпочитаемого стека и установки WordPress. Вместо установки отдельных компонентов вручную, вы можете использовать *образы*, которые обладают такими стандартными элементами, как библиотеки, файлы конфигурации и переменные среды, и запускать эти образы в *контейнерах*, т. е. изолированных процессах, запущенных в общей операционной системе. Кроме того, используя Compose, вы можете координировать действия нескольких контейнеров, например приложения и базы данных, которые будут коммуницировать друг с другом.
В этом обучающем руководстве вы будете выполнять установку WordPress с несколькими контейнерами. Ваши контейнеры будут включать базу данных MySQL, веб-сервер Nginx и непосредственно WordPress. Также вы должны будете обеспечить защиту установки, получая с помощью Let's Encrypt сертификаты TLS/SSL для доменов, которые вы хотите привязать к вашему сайту. Наконец, вы настроите задание cron для обновления ваших сертификатов, чтобы ваш домен оставался защищенным.
Предварительные требования
Для данного обучающего руководства вам потребуется следующее:
- Сервер на базе Ubuntu 18.04, а также пользователь без прав root с привилегиями
sudoи активный брандмауэр. Дополнительную информацию о настройке этих параметров см. в руководстве по первоначальной настройке сервера.
- Система Docker, установленная на сервере в соответствии с шагами 1 и 2 руководства Установка и использование Docker в Ubuntu 18.04.
- Docker Compose, установленный на сервере, в соответствии с шагом 1 руководства Установка Docker Compose в Ubuntu 18.04.
- Зарегистрированное доменное имя. В этом обучающем руководстве мы будем использовать example.com. Вы можете получить бесплатный домен на Freenom или зарегистрировать доменное имя по вашему выбору.
- На вашем сервере должны быть настроены обе нижеследующие записи DNS. Вы можете воспользоваться введением в работу с DNS hosting, чтобы получить подробную информацию о добавлении доменов в учетную запись the cloud provider, если вы используете этот способ:
- Запись A, где
<^>example.com<^>указывает на публичный IP-адрес вашего сервера.
- Запись A, где
www.<^>example.com<^>указывает на публичный IP-адрес вашего сервера.
Шаг 1 — Настройка конфигурации веб-сервера
Перед запуском контейнеров прежде всего необходимо настроить конфигурацию нашего веб-сервера Nginx. Наш файл конфигурации будет включать несколько специфических для WordPress блоков расположения наряду с блоками расположения, которые будут направлять передаваемые Let's Encrypt запросы верификации клиенту Certbot для автоматизированного обновления сертификатов.
Во-первых, создайте директорию проекта для настройки WordPress с именем <^>wordpress<^> и перейдите в эту директорию:
mkdir <^>wordpress<^> && cd <^>wordpress<^>
Затем создайте директорию для файла конфигурации:
mkdir nginx-conf
Откройте файл с помощью nano или своего любимого редактора:
nano nginx-conf/nginx.conf
В этом файле мы добавим серверный блок с директивами для имени нашего сервера и корневой директории документов, а также блок расположения для направления запросов сертификатов от клиента Certbot, обработки PHP и запросов статичных активов.
Добавьте в файл следующий код. Обязательно замените <^>example.com<^> на ваше доменное имя.
[label ~/wordpress/nginx-conf/nginx.conf]
server {
listen 80;
listen [::]:80;
server_name <^>example.com<^> www.<^>example.com<^>;
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;
}
location ~ \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass <^>wordpress<^>: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: этот элемент определяет имя вашего сервера и серверный блок, которые должны использоваться для запросов к вашему серверу. Обязательно замените<^>example.com<^>в этой строке на ваше собственное доменное имя.
index: директиваindexопределяет файлы, которые будут использоваться в качестве индексов при обработке запросов к вашему серверу. Здесь мы изменили порядок приоритета по умолчанию, поставивindex.phpпередindex.html, в результате чего Nginx будет давать приоритет файлам с именемindex.phpпри наличии возможности.
root: наша директиваrootназначает имя корневой директории для запросов к нашему серверу. Эта директория,/var/www/html, создается в качестве точки монтирования в момент сборки с помощью инструкций в Dockerfile WordPress. Эти инструкции Dockerfile также гарантируют, что файлы релиза WordPress монтируются в этот том.
Блоки расположения:
location ~ /.well-known/acme-challenge: этот блок расположения будет обрабатывать запросы в директории.well-known, где Certbot будет размещать временный файл для подтверждения того, что DNS для нашего домена будет работать с нашим сервером. Настроив данную конфигурацию, мы сможем использовать плагин webroot Certbot для получения сертификатов для нашего домена.
location /: в этом блоке расположения мы будем использовать директивуtry_filesдля проверки файлов, соответствующих отдельным запросам URI. Вместо того, чтобы возвращать по умолчанию статус 404не найдено, мы будем передавать контроль файлуindex.phpWordPress с аргументами запроса.
location ~.php$: этот блок расположения будет обрабатывать PHP-запросы и проксировать эти запросы в наш контейнерwordpress. Поскольку наш образ WordPress Docker будет опираться на образphp:fpm, мы также добавим параметры конфигурации, принадлежащие протоколу FastCGI, в этот блок. Nginx требует наличия независимого процессора PHP для запросов PHP: в нашем случае эти запросы будут обрабатываться процессоромphp-fpm, который будет включать образphp:fpm. Кроме того, этот блок расположения содержит директивы FastCGI, переменные и опции, которые будут проксировать запросы для приложения WordPress, запущенного в нашем контейнереwordpress, задавать предпочитаемый индекс захваченного 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 и алгоритмы выбора блоков расположения.
Сохраните и закройте файл после завершения редактирования. Если вы используете nano, нажмите CTRL+X, Y, затем ENTER.
После настройки конфигурации Nginx вы можете перейти к созданию переменных среды для передачи в контейнеры приложения и базы данных во время исполнения.
Шаг 2 — Настройка переменных среды
Контейнеры базы данных и приложения WordPress должны получить доступ к определенным переменным среды в момент выполнения для сохранения данных приложения и предоставления доступа к этим данным для вашего приложения. Эти переменные включают чувствительные и нечувствительные данные: к чувствительным данным относятся root-пароль MySQL и пароль и пользователь базы данных приложения, а к нечувствительным данным относится информация об имени и хосте базы данных приложения.
Вместо того, чтобы задавать эти значения в нашем файле Docker Compose, основном файле, который содержит информацию о том, как наши контейнеры будут работать, мы можем задать чувствительные значения в файле .env и ограничить его распространение. Это не позволит скопировать эти значения в репозиторий нашего проекта и открыть их для общего доступа.
В главной директории проекта ~/<^>wordpress<^>, откройте файл с именем .env:
nano .env
Конфиденциальные значения, которые мы зададим в этом файле, включают пароль для нашего root-пользователя MySQL, имя пользователя и пароль, которые WordPress будет использовать для доступа к базе данных.
Добавьте в файл следующие имена и значения переменных: Обязательно предоставьте здесь ваши собственные значения для каждой переменной:
[label ~/wordpress/.env]
MYSQL_ROOT_PASSWORD=<^>your_root_password<^>
MYSQL_USER=<^>your_wordpress_database_user<^>
MYSQL_PASSWORD=<^>your_wordpress_database_password<^>
Мы включили пароль для административной учетной записи root, а также предпочитаемые имя пользователя и пароль для нашей базы данных приложения.
Сохраните и закройте файл после завершения редактирования.
Поскольку ваш файл .env содержит чувствительную информацию, вы можете убедиться, что в файлы .gitignore и .dockerignore вашего проекта включены инструкции, указывающие Git и Docker, какие файлы не копировать в ваши репозитории Git и образы Docker.
Если вы планируете использовать Git для контроля версий, инициализируйте текущую рабочую директорию в качестве репозитория с помощью git init:
git init
Затем откройте файл .gitignore:
nano .gitignore
Добавьте .env в файл:
[label ~/wordpress/.gitignore]
.env
Сохраните и закройте файл после завершения редактирования.
Также в качестве дополнительной меры предосторожности рекомендуется добавить .env в файл .dockerignore, чтобы он не потерялся в ваших контейнерах, когда вы используете эту директорию в качестве контекста для сборки.
Откройте файл:
nano .dockerignore
Добавьте .env в файл:
[label ~/wordpress/.dockerignore]
.env
Ниже вы можете дополнительно добавить файлы и директории, связанные с разработкой вашего приложения:
[label ~/wordpress/.dockerignore]
.env
.git
docker-compose.yml
.dockerignore
Сохраните файл и закройте его после завершения.
Теперь, когда все чувствительные данные на месте, вы можете перейти к определению ваших служб в файле docker-compose.yml.
Шаг 3 — Определение служб с помощью Docker Compose
Ваш файл docker-compose.yml будет содержать определения службы для вашей настройки. *Служба* в Compose — это запущенный контейнер, а определения службы содержат информацию о том, как каждый контейнер будет работать.
Используя Compose, вы можете определить различные службы для запуска приложений с несколькими контейнерами, поскольку Compose позволяет привязать эти службы к общим сетям и томам. Это будет полезно для нашей текущей настройки, поскольку мы создадим различные контейнеры для нашей базы данных, приложения WordPress и веб-сервера. Также мы создадим контейнер для запуска клиента Certbot, чтобы получить сертификаты для нашего веб-сервера.
Откройте файл docker-compose.yml:
nano docker-compose.yml
Добавьте следующий код для определения версии файла Compose и базы данных db:
[label ~/wordpress/docker-compose.yml]
version: '3'
services:
db:
image: mysql:<^>8.0<^>
container_name: db
restart: unless-stopped
env_file: .env
environment:
- MYSQL_DATABASE=<^>wordpress<^>
volumes:
- dbdata:/var/lib/mysql
command: '--default-authentication-plugin=mysql_native_password'
networks:
- app-network
Определение службы db включает следующие параметры:
image: данный элемент указывает Compose, какой образ будет загружаться для создания контейнера. Мы закрепим здесь образmysql:<^>8.0<^>, чтобы избежать будущих конфликтов, так как образmysql:latestпродолжит обновляться. Дополнительную информацию о закреплении версии и предотвращении конфликтов зависимостей см. в документации Docker в разделе Рекомендации по работе с Dockerfile.
container_name: данный элемент указывает имя контейнера.
restart: данный параметр определяет политику перезапуска контейнера. По умолчанию установлено значениеno, но мы задали значение, согласно которому контейнер будет перезапускаться, пока не будет остановлен вручную.
env_file: этот параметр указывает Compose, что мы хотим добавить переменные среды из файла с именем.env, расположенного в контексте сборки. В этом случае в качестве контекста сборки используется наша текущая директория.
environment: этот параметр позволяет добавить дополнительные переменные среды, не определенные в файле.env. Мы настроим переменнуюMYSQL_DATABASEсо значением<^>wordpress<^>, которая будет предоставлять имя нашей базы данных приложения. Поскольку эта информация не является чувствительной, мы можем включить ее напрямую в файлdocker-compose.yml.
volumes: здесь мы монтируем именованный том с названиемdbdataв директорию/var/lib/mysqlв контейнере. Это стандартная директория данных в большинстве дистрибутивов.
command: данный параметр указывает команду, которая будет переопределять используемое по умолчанию значение инструкции CMD для образа. В нашем случае мы добавим параметр для стандартной командыmysqldобраза Docker, которая запускает сервер MySQL в контейнере. Эта опция--default-authentication-plugin=mysql_native_passwordустанавливает для системной переменной--default-authentication-pluginзначениеmysql_native_password, которое указывает, какой механизм аутентификации должен управлять новыми запросами аутентификации для сервера. Поскольку PHP и наш образ WordPress не будут поддерживать новое значение аутентификации MySQL по умолчанию, мы должны внести изменения, чтобы выполнить аутентификацию пользователя базы данных приложения.
networks: данный параметр указывает, что служба приложения будет подключаться к сетиapp-network, которую мы определим внизу файла.
Затем под определением службы db добавьте определение для вашей службы приложения wordpress:
[label ~/wordpress/docker-compose.yml]
...
wordpress:
depends_on:
- db
image: wordpress:<^>5.1.1<^>-fpm-alpine
container_name: wordpress
restart: unless-stopped
env_file: .env
environment:
- WORDPRESS_DB_HOST=db:3306
- WORDPRESS_DB_USER=$MYSQL_USER
- WORDPRESS_DB_PASSWORD=$MYSQL_PASSWORD
- WORDPRESS_DB_NAME=<^>wordpress<^>
volumes:
- wordpress:/var/www/html
networks:
- app-network
В этом определении службы мы называем наш контейнер и определяем политику перезапуска, как уже делали это для службы db. Также мы добавляем в этот контейнер ряд параметров:
depends_on: этот параметр гарантирует, что наши контейнеры будут запускаться в порядке зависимости, и контейнерwordpressзапускается после контейнераdb. Наше приложение WordPress зависит от наличия базы данных приложения и пользователя, поэтому установка такого порядка зависимостей позволит выполнять запуск приложения корректно.
image: для этой настройки мы будем использовать образ WordPress<^>5.11<^>-fpm-alpine. Как было показано в шаге 1, использование этого образа гарантирует, что наше приложение будет иметь процессорphp-fpm, который требуется Nginx для обработки PHP. Это еще и образalpine, полученный из проекта Alpine Linux, который поможет снизить общий размер образа. Дополнительную информацию о преимуществах и недостатках использования образовalpine, а также о том, имеет ли это смысл в случае вашего приложения, см. в полном описании в разделе Варианты образа на странице образа WordPress на Docker Hub.
env_file: и снова мы укажем, что хотим загрузить значения из файла.env, поскольку там мы определили пользователя базы данных приложения и пароль.
environment: здесь мы будем использовать значения, определенные в файле.env, но мы привяжем их к именам переменных, которые требуются для образа WordPress:WORDPRESS_DB_USERиWORDPRESS_DB_PASSWORD. Также мы определяем значениеWORDPRESS_DB_HOST, которое будет указывать сервер MySQL, который будет работать в контейнереdb, доступный на используемом по умолчанию порту MySQL3306. Наше значениеWORDPRESS_DB_NAMEбудет тем же, которое мы указали при определении службы MySQL дляMYSQL_DATABASE:<^>wordpress<^>.
volumes: мы монтируем том с именемwordpressна точку монтирования/var/www/html, созданную образом WordPress. Использование тома с именем таким образом позволит разделить наш код приложения с другими контейнерами.
networks: мы добавляем контейнерwordpressв сетьapp-network.
Далее под определением службы приложения wordpress добавьте следующее определение для службы Nginx webserver:
[label ~/wordpress/docker-compose.yml]
...
webserver:
depends_on:
- wordpress
image: nginx:<^>1.15.12<^>-alpine
container_name: webserver
restart: unless-stopped
ports:
- "80:80"
volumes:
- wordpress:/var/www/html
- ./nginx-conf:/etc/nginx/conf.d
- certbot-etc:/etc/letsencrypt
networks:
- app-network
Мы снова присвоим имя нашему контейнеру и сделаем его зависимым от контейнера wordpress в отношении порядка запуска. Также мы используем образ alpine — образ Nginx <^>1.15.12<^>-alpine.
Это определение службы также включает следующие параметры:
ports: этот параметр открывает порт80, чтобы активировать параметры конфигурации, определенные нами в файлеnginx.confв [шаге 1]().
volumes: здесь мы определяем комбинацию названных томов и связанных монтируемых образов:
wordpress:/var/www/html: этот параметр будет монтировать код нашего приложения WordPress в директорию/var/www/html, директорию, которую мы задали в качествеroot-директории в нашем серверном блоке Nginx.
./nginx-conf:/etc/nginx/conf.d: этот элемент будет монтировать директорию конфигурации Nginx на хост в соответствующую директорию в контейнере, гарантируя, что любые изменения, которые мы вносим в файлы на хосте, будут отражены в контейнере.
certbot-etc:/etc/letsencrypt: этот элемент будет монтировать соответствующие сертификаты и ключи Let's Encrypt для нашего домена в соответствующую директорию контейнера.
Здесь мы снова добавили этот контейнер в сеть app-network.
Наконец, под определением webserver добавьте последнее определение для службы certbot. Обязательно замените адрес электронной почты и доменные имена, перечисленные здесь, на ваши собственные:
[label ~/wordpress/docker-compose.yml]
certbot:
depends_on:
- webserver
image: certbot/certbot
container_name: certbot
volumes:
- certbot-etc:/etc/letsencrypt
- wordpress:/var/www/html
command: certonly --webroot --webroot-path=/var/www/html --email <^>sammy@example.com<^> --agree-tos --no-eff-email --staging -d <^>example.com<^> -d www.<^>example.com<^>
Это определение попросит Compose извлекать образ certbot/certbot из Docker Hub. Также оно использует имена томов для обмена ресурсами с контейнером Nginx, включая доменные сертификаты и ключ в certbot-etc и код приложения в wordpress.
Мы использовали depends_on, чтобы указать, что контейнер certbot следует запускать только после запуска службы webserver.
Также мы включили параметр command, указывающий субкоманду для запуска с используемой контейнером по умолчанию командой certbot. Субкоманда certonly будет получать сертификат со следующими параметрами:
--webroot: данный элемент говорит Certbot о необходимости использования плагина webroot для размещения файлов в папке webroot для аутентификации. Работа плагина основана на методе валидации HTTP-01, который использует запрос HTTP, чтобы доказать, что Certbot может получить доступ к ресурсам с сервера, который отвечает на заданное доменное имя.
--webroot-path: данный элемент указывает путь директории webroot.
--email: предпочитаемый адрес электронной почты для регистрации и восстановления.
--agree-tos: данный элемент указывает, что вы принимаете Соглашение о подписке ACME.
--no-eff-email: данный элемент указывает Certbot, что вы не хотите делиться адресом электронной почты с Electronic Frontier Foundation (EFF). Вы можете пропустить этот элемент.
--staging: данный элемент говорит Certbot, что вы хотите использовать промежуточную среду Let's Encrypt для получения тестовых сертификатов. При использовании этого параметра вы можете протестировать параметры конфигурации и избежать возможных пределов для запросов домена. Дополнительную информацию об этих предельных значениях см. в документации по ограничениям скорости Let's Encrypt.
-d: данный элемент позволяет указать доменные имена, которые вы хотите использовать для вашего запроса. В нашем случае мы включили<^>example.com<^>иwww.<^>example.com<^>. Обязательно замените эти данные на имя вашего домена.
Под определением службы certbot добавьте определения сети и тома:
[label ~/wordpress/docker-compose.yml]
...
volumes:
certbot-etc:
wordpress:
dbdata:
networks:
app-network:
driver: bridge
Наш ключ верхнего уровня volumes определяет тома certbot-etc, wordpress и dbdata. Когда Docker создает тома, содержимое тома сохраняется в директории файловой системы хоста, /var/lib/docker/volumes/, а данным процессом управляет Docker. После этого содержимое каждого тома монтируется из этой директории в любой контейнер, использующий том. Таким образом мы можем делиться кодом и данными между контейнерами.
Создаваемая пользователем мостовая система app-network позволяет организовать коммуникацию между нашими контейнерами, поскольку они находятся на одном хосте демона Docker. Это позволяет организовать трафик и коммуникации внутри приложения, поскольку она открывает все порты между контейнерами в одной мостовой сети, скрывая все порты от внешнего мира. Таким образом, наши контейнеры db, wordpress и webserver могут взаимодействовать друг с другом, и нам нужно будет только открыть порт 80 для внешнего доступа к приложению.
Итоговый файл docker-compose.yml будет выглядеть примерно так:
[label ~/wordpress/docker-compose.yml]
version: '3'
services:
db:
image: mysql:<^>8.0<^>
container_name: db
restart: unless-stopped
env_file: .env
environment:
- MYSQL_DATABASE=<^>wordpress<^>
volumes:
- dbdata:/var/lib/mysql
command: '--default-authentication-plugin=mysql_native_password'
networks:
- app-network
wordpress:
depends_on:
- db
image: wordpress:<^>5.1.1<^>-fpm-alpine
container_name: wordpress
restart: unless-stopped
env_file: .env
environment:
- WORDPRESS_DB_HOST=db:3306
- WORDPRESS_DB_USER=$MYSQL_USER
- WORDPRESS_DB_PASSWORD=$MYSQL_PASSWORD
- WORDPRESS_DB_NAME=<^>wordpress<^>
volumes:
- wordpress:/var/www/html
networks:
- app-network
webserver:
depends_on:
- wordpress
image: nginx:<^>1.15.12<^>-alpine
container_name: webserver
restart: unless-stopped
ports:
- "80:80"
volumes:
- wordpress:/var/www/html
- ./nginx-conf:/etc/nginx/conf.d
- certbot-etc:/etc/letsencrypt
networks:
- app-network
certbot:
depends_on:
- webserver
image: certbot/certbot
container_name: certbot
volumes:
- certbot-etc:/etc/letsencrypt
- wordpress:/var/www/html
command: certonly --webroot --webroot-path=/var/www/html --email <^>sammy@example.com<^> --agree-tos --no-eff-email --staging -d <^>example.com<^> -d www.<^>example.com<^>
volumes:
certbot-etc:
wordpress:
dbdata:
networks:
app-network:
driver: bridge
Сохраните и закройте файл после завершения редактирования.
После добавления определений службы вы можете запустить контейнеры и протестировать запросы сертификата.
Шаг 4 — Получение сертификатов SSL и учетных данных
Мы можем запустить наши контейнеры с помощью команды docker-compose up, которая будет создавать и запускать наши контейнеры и службы в указанном нами порядке. Если наши запросы доменов будут выполнены успешно, мы увидим корректный статус выхода в нашем выводе и нужные сертификаты, установленные в папке /etc/letsencrypt/live на контейнере webserver.
Создайте контейнеры с помощью команды docker-compose up и флага -d, которые будут запускать контейнеры db, wordpress и webserver в фоновом режиме:
docker-compose up -d
Вы увидите вывод, подтверждающий, что ваши службы были успешно созданы:
[secondary_label Output]
Creating db ... done
Creating wordpress ... done
Creating webserver ... done
Creating certbot ... done
С помощью docker-compose ps проверьте статус ваших служб:
docker-compose ps
Если все будет выполнено успешно, ваши службы db, wordpress и webserver должны иметь статус Up, а работа контейнера certbot будет завершена с сообщением о статусе 0:
[secondary_label Output]
Name Command State Ports
-------------------------------------------------------------------------
certbot certbot certonly --webroot ... Exit 0
db docker-entrypoint.sh --def ... Up 3306/tcp, 33060/tcp
webserver nginx -g daemon off; Up 0.0.0.0:80->80/tcp
wordpress docker-entrypoint.sh php-fpm Up 9000/tcp
Если вы увидите любое значение, кроме Up в столбце State для служб db, wordpress и 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 May 10 15:45 .
drwxr-xr-x 9 root root 4096 May 10 15:45 ..
-rw-r--r-- 1 root root 740 May 10 15:45 README
drwxr-xr-x 2 root root 4096 May 10 15:45 <^>example.com<^>
Теперь, когда вы убедились, что ваш запрос будет выполнен успешно, вы можете изменить определение службы certbot для удаления флага --staging.
Откройте docker-compose.yml:
nano docker-compose.yml
Найдите раздел файла с определением службы certbot и замените флаг --staging в параметрах command на флаг --force-renewal, который будет указывать Certbot, что вы хотите запросить новый сертификат с теми же доменами, что и в уже существующем сертификате. Определение службы certbot должно будет выглядеть следующим образом:
[label ~/wordpress/docker-compose.yml]
...
certbot:
depends_on:
- webserver
image: certbot/certbot
container_name: certbot
volumes:
- certbot-etc:/etc/letsencrypt
- certbot-var:/var/lib/letsencrypt
- wordpress:/var/www/html
command: certonly --webroot --webroot-path=/var/www/html --email <^>sammy@example.com<^> --agree-tos --no-eff-email <^>--force-renewal<^> -d <^>example.com<^> -d www.<^>example.com<^>
...
Теперь вы можете запустить команду 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 <^>example.com<^>
certbot | http-01 challenge for www.<^>example.com<^>
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/<^>example.com<^>/fullchain.pem
certbot | Your key file has been saved at:
certbot | /etc/letsencrypt/live/<^>example.com<^>/privkey.pem
certbot | Your cert will expire on 2019-08-08. 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
Прежде чем мы самостоятельно изменим файл конфигурации, нам нужно предварительно получить рекомендуемые параметры безопасности Nginx от Certbot с помощью curl:
curl -sSLo nginx-conf/options-ssl-nginx.conf https://raw.githubusercontent.com/certbot/certbot/master/certbot-nginx/certbot_nginx/_internal/tls_configs/options-ssl-nginx.conf
Данная команда будет сохранять эти параметры в файле с именем options-ssl-nginx.conf, расположенном в директории nginx-conf.
Затем удалите ранее созданный файл конфигурации Nginx:
rm nginx-conf/nginx.conf
Откройте другую версию файла:
nano nginx-conf/nginx.conf
Добавьте следующий код в файл для перенаправления HTTP на HTTPS и добавления учетных данных, протоколов и заголовков безопасности SSL. Обязательно замените <^>example.com<^> на ваше доменное имя:
[label ~/wordpress/nginx-conf/nginx.conf]
server {
listen 80;
listen [::]:80;
server_name <^>example.com<^> www.<^>example.com<^>;
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 <^>example.com<^> www.<^>example.com<^>;
index index.php index.html index.htm;
root /var/www/html;
server_tokens off;
ssl_certificate /etc/letsencrypt/live/<^>example.com<^>/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/<^>example.com<^>/privkey.pem;
include /etc/nginx/conf.d/options-ssl-nginx.conf;
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
location / {
try_files $uri $uri/ /index.php$is_args$args;
}
location ~ \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass <^>wordpress<^>: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 и ключа, а также рекомендованные параметры безопасности Certbot, которые мы сохранили в nginx-conf/options-ssl-nginx.conf.
Кроме того, мы включили ряд заголовков безопасности, которые позволят нам получить оценки A на сайтах серверных тестов SSL Labs и Security Headers. Эти заголовки включают X-Frame-Options, X-Content-Type-Options, Referrer Policy, Content-Security-Policy и X-XSS-Protection. Заголовок HTTP Strict Transport Security (Строгая безопасность передачи информации по протоколу HTTP) закомментирован, активируйте этот элемент, только если вы понимаете возможные последствия и оценили его «предварительно загруженный» функционал.
Наши директивы root и index также расположены в этом блоке, равно как и остальные блоки расположения WordPress, описанные в шаге 1.
После завершения редактирования сохраните и закройте файл.
Перед повторным созданием службы webserver вам потребуется добавить распределение порта 443 в определение службы webserver.
Откройте ваш файл docker-compose.yml:
nano docker-compose.yml
В определении службы webserver добавьте следующее распределение порта:
[label ~/wordpress/docker-compose.yml]
...
webserver:
depends_on:
- wordpress
image: nginx:<^>1.15.12<^>-alpine
container_name: webserver
restart: unless-stopped
ports:
- "80:80"
- <^>"443:443"<^>
volumes:
- wordpress:/var/www/html
- ./nginx-conf:/etc/nginx/conf.d
- certbot-etc:/etc/letsencrypt
networks:
- app-network
Файл docker-compose.yml будет выглядеть следующим образом после завершения настройки:
[label ~/wordpress/docker-compose.yml]
version: '3'
services:
db:
image: mysql:<^>8.0<^>
container_name: db
restart: unless-stopped
env_file: .env
environment:
- MYSQL_DATABASE=wordpress
volumes:
- dbdata:/var/lib/mysql
command: '--default-authentication-plugin=mysql_native_password'
networks:
- app-network
wordpress:
depends_on:
- db
image: wordpress:<^>5.1.1<^>-fpm-alpine
container_name: wordpress
restart: unless-stopped
env_file: .env
environment:
- WORDPRESS_DB_HOST=db:3306
- WORDPRESS_DB_USER=$MYSQL_USER
- WORDPRESS_DB_PASSWORD=$MYSQL_PASSWORD
- WORDPRESS_DB_NAME=wordpress
volumes:
- wordpress:/var/www/html
networks:
- app-network
webserver:
depends_on:
- wordpress
image: nginx:<^>1.15.12<^>-alpine
container_name: webserver
restart: unless-stopped
ports:
- "80:80"
- "443:443"
volumes:
- wordpress:/var/www/html
- ./nginx-conf:/etc/nginx/conf.d
- certbot-etc:/etc/letsencrypt
networks:
- app-network
certbot:
depends_on:
- webserver
image: certbot/certbot
container_name: certbot
volumes:
- certbot-etc:/etc/letsencrypt
- wordpress:/var/www/html
command: certonly --webroot --webroot-path=/var/www/html --email <^>sammy@example.com<^> --agree-tos --no-eff-email --force-renewal -d <^>example.com<^> -d www.<^>example.com<^>
volumes:
certbot-etc:
wordpress:
dbdata:
networks:
app-network:
driver: bridge
Сохраните и закройте файл после завершения редактирования.
Повторно создайте службу webserver:
docker-compose up -d --force-recreate --no-deps webserver
Проверьте ваши службы с помощью команды docker-compose ps:
docker-compose ps
Вы должны получить результат, указывающий, что ваши службы db, wordpress и webserver запущены:
[secondary_label Output]
Name Command State Ports
----------------------------------------------------------------------------------------------
certbot certbot certonly --webroot ... Exit 0
db 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
wordpress docker-entrypoint.sh php-fpm Up 9000/tcp
После запуска ваших контейнеров вы можете завершить процесс установки WordPress через веб-интерфейс.
Шаг 6 — Завершение установки через веб-интерфейс
После запуска контейнеров мы можем завершить установку через веб-интерфейс WordPress.
В браузере перейдите на домен вашего сервера. Не забудьте заменить здесь <^>example.com<^> на ваше доменное имя:
https://<^>example.com<^>
Выберите язык, который вы хотите использовать:
После нажатия Continue (Продолжить) вы перейдете на главную страницу настройки, где вам нужно будет выбрать имя вашего сайта и пользователя. Рекомендуется выбрать запоминающееся имя пользователя (не просто «admin») и надежный пароль. Вы можете использовать пароль, который генерирует WordPress автоматически, или задать собственный пароль.
Наконец, вам нужно будет ввести ваш адрес электронной почты и указать, хотите ли вы, чтобы движки поисковых систем могли индексировать ваш сайт:
После нажатия Install WordPress (Установить WordPress) внизу страницы на экране появится запрос выполнения входа:
После входа вы получите доступ к панели управления WordPress:
После завершения установки WordPress вы можете выполнить определенные действия, необходимые для гарантии того, что ваши сертификаты SSL будут обновляться автоматически.
Шаг 7 — Обновление сертификатов
Сертификаты Let's Encrypt действительны в течение 90 дней, поэтому вам нужно будет настроить автоматический процесс обновления, чтобы гарантировать, что сертификаты не окажутся просроченными. Один из способов — создание задания с помощью утилиты планирования cron. В нашем случае мы настроим задание для cron с помощью скрипта, который будет обновлять наши сертификаты и перезагружать конфигурацию Nginx.
Откройте скрипт под названием ssl_renew.sh:
nano ssl_renew.sh
Добавьте следующий код в скрипт, чтобы обновить ваши сертификаты и перезагрузить конфигурацию веб-сервера. Не забудьте заменить приведенное в качестве примера имя пользователя своим именем пользователя без прав root:
[label ~/wordpress/ssl_renew.sh]
#!/bin/bash
COMPOSE="/usr/local/bin/docker-compose --no-ansi"
DOCKER="/usr/bin/docker"
cd /home/<^>sammy<^>/wordpress/
$COMPOSE run certbot renew --dry-run && $COMPOSE kill -s SIGHUP webserver
$DOCKER system prune -af
Данный скрипт привязывает двоичный код docker-compose для переменной COMPOSE и задает параметр --no-ansi, который запускает команды docker-compose без управляющих символов ANSI. Затем он делает то же самое с двоичным файлом docker. В заключение он меняет директорию проекта на ~/wordpress и запускает следующие команды docker-compose:
docker-compose run: данный параметр запускает контейнерcertbotи переопределяет параметрcommand, указанный в определении службыcertbot. Вместо использования субкомандыcertonlyмы используем здесь субкомандуrenew, которая будет обновлять сертификаты, срок действия которых близок к окончанию. Мы включили параметр--dry-run, чтобы протестировать наш скрипт.
docker-compose kill: данный параметр отправляет сигналSIGHUPконтейнеруwebserverдля перезагрузки конфигурации Nginx. Дополнительную информацию об использовании этого процесса для перезагрузки конфигурации Nginx см. в этой публикации блога Docker, посвященной развертыванию официального образа Nginx с помощью Docker.
После этого он выполняет команду docker system prune для удаления всех неиспользуемых контейнеров и образов.
Закройте файл после завершения редактирования. Сделайте его исполняемым:
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 <---- easiest
2. /usr/bin/vim.basic
3. /usr/bin/vim.tiny
4. /bin/ed
Choose 1-4 [1]:
...
Добавьте внизу файла следующую строку:
[label crontab]
...
*/5 * * * * /home/<^>sammy<^>/wordpress/ssl_renew.sh >> /var/log/cron.log 2>&1
В результате будет установлен интервал в 5 минут для выполнения работы, и вы можете проверить, работает ли запрос обновления так, как предполагается. Также мы создали файл журнала, cron.log, чтобы записывать соответствующий вывод выполнения задания.
Через 5 минут проверьте 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/<^>example.com<^>/fullchain.pem (success)
** DRY RUN: simulating 'certbot renew' close to cert expiry
** (The test certificates above have not been saved.)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Теперь вы можете изменить файл crontab для настройки ежедневного интервала. Чтобы запускать скрипт каждый день в полдень, например, вы должны изменить последнюю строку файла, которая должна выглядеть следующим образом:
[label crontab]
...
0 12 * * * /home/<^>sammy<^>/wordpress/ssl_renew.sh >> /var/log/cron.log 2>&1
Также вы можете изменить параметр --dry-run из скрипта ssl_renew.sh:
[label ~/wordpress/ssl_renew.sh]
#!/bin/bash
COMPOSE="/usr/local/bin/docker-compose --no-ansi"
DOCKER="/usr/bin/docker"
cd /home/<^>sammy<^>/wordpress/
$COMPOSE run certbot renew && $COMPOSE kill -s SIGHUP webserver
$DOCKER system prune -af
Ваше задание cron гарантирует, что ваши сертификаты Let's Encrypt не окажутся устаревшими, обновляя их в случае истечения срока действия. Также вы можете настроить замену журнала с помощью утилиты Logrotate, которая будет выполнять ротацию и сжатие файлов журнала.
Заключение
В этом руководстве вы использовали Docker Compose для создания установки WordPress с веб-сервером Nginx. В рамках этого рабочего процесса вы получили сертификаты TLS/SSL для домена, который вы хотите подключить к вашему сайту WordPress. Кроме того, вы создали задание cron для обновления этих сертификатов при необходимости.
В качестве дополнительных мер по повышению производительности сайта и создания запаса мощности, вы можете ознакомиться со следующими статьями, посвященными передаче и поддержке активов WordPress:
Если вы заинтересованы в изучении контейнеризированного рабочего процесса с помощью Kubernetes, вы также можете ознакомиться со следующими материалами: