Введение
WordPress — одна из самых популярных систем управления контентом (CMS). По статистике, она работает на более чем 39% всех веб-сайтов в глобальной сети. Это популярный выбор благодаря возможности расширения с помощью плагинов и гибкой системе шаблонов. Она позволяет изменить внешний вид за считанные секунды. Более того, администрирование можно осуществлять через веб-интерфейс, что не требует глубоких технических знаний.
Кроме того, WordPress является бесплатным программным обеспечением с открытым исходным кодом и построен на базе базы данных MySQL с обработкой на PHP. Вы можете развернуть WordPress на стеке LAMP (Linux, Apache, MySQL и PHP) или стеке LEMP (Linux, Nginx, MySQL и PHP). Однако настройка стека каждый раз при развертывании оказывается трудоемкой задачей.
К счастью, современные методы доставки программного обеспечения, такие как облачные вычисления, Docker, и Docker Compose упростили процесс разработки в целом. Эти инструменты упрощают процесс настройки любого стека, избавляя от необходимости каждый раз устанавливать и настраивать отдельные компоненты при развертывании приложения. Вместо этого вы пишете конфигурационные файлы, которые будут использоваться для загрузки и создания образов и их запуска в контейнерах Docker, что позволяет развернуть приложение всего одной командой.
Контейнеры представляют собой легковесные, виртуализированные, портативные, программно определяемые стандартизированные среды, которые позволяют программному обеспечению работать изолированно от другого ПО, запущенного на физическом хосте. Docker Compose позволяет управлять несколькими контейнерами и обеспечивать их взаимодействие. Например, исходный код приложения и база данных должны взаимодействовать друг с другом.
В этом руководстве мы будем создавать контейнеризированное приложение WordPress из нескольких контейнеров. Для полноценного приложения WordPress требуются три контейнера: база данных MySQL, сервер Nginx и исходный код WordPress. Поскольку безопасность является приоритетом для современных веб-сайтов, мы получим SSL-сертификат от Let’s Encrypt для защиты вашей установки. Затем мы настроим задачу cron для периодической проверки и обновления сертификатов, чтобы безопасность вашего веб-сайта поддерживалась непрерывно.
Предварительные требования
- Поскольку это практическое руководство, в качестве начальной операционной среды у вас должна быть установлена Ubuntu 20.04. Также вам понадобится пользователь без прав root, но с привилегиями sudo. Вот пошаговое руководство, которое поможет вам настроить сервер Ubuntu.
- Также вам необходимо установить Docker. Вы можете обратиться к этому руководству по теме как установить и использовать Docker на Ubuntu 18.04.
- Установка Docker Compose. Вы можете выполнить шаг 1 из руководства Как установить и настроить Docker Compose на Ubuntu 20.04.
- Для получения TLS/SSL-сертификата от Let’s Encrypt требуется зарегистрированное доменное имя. В рамках этого руководства мы будем использовать
example.com. - Настройте DNS-записи, чтобы направить трафик на ваш VPS. Вам понадобятся две DNS-записи:
- Запись типа A для
example.com, указывающая на публичный IP-адрес вашего сервера. - Запись типа A для
www.example.com, указывающая на публичный IP-адрес вашего сервера.
- Запись типа A для
Шаг 1. Определение конфигурации веб-сервера
Веб-сервер хранит файлы вашего сайта и позволяет пользователям получать доступ к вашему веб-приложению. Поэтому вполне логично, что на первом шаге мы определим конфигурацию веб-сервера. Мы настроим файл конфигурации сервера Nginx, который будет включать специфичные для WordPress блоки location. Мы также добавим блоки location для перенаправления запросов на верификацию Let’s Encrypt клиенту Certbot для автоматического продления сертификата.
Начнем с создания директории для проекта. Вы можете выбрать любое имя директории. В этом руководстве мы будем использовать wordpress_docker для этого проекта. Введите следующую команду, чтобы создать директорию и перейти в нее:
|
1 |
mkdir wordpress_docker && cd wordpress_docker |
Затем создайте директорию для хранения конфигурационных файлов Nginx с помощью команды:
|
1 |
mkdir nginx-conf |
Используйте nano для открытия файла с помощью следующей команды:
|
1 |
nano nginx-conf/nginx.conf |
В этом файле мы определим базовые директивы для конфигурации блока сервера Nginx. К ним относятся директивы для имени сервера, корневого каталога документов и блоков location для перенаправления запросов плагина Certbot на получение сертификатов, статических файлов и обработки PHP. Вы можете прочитать наше руководство по Как защитить Nginx с помощью Let’s Encrypt, чтобы узнать больше. Добавьте следующий код в файл, заменив example.com на ваше зарегистрированное доменное имя:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
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 app: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; } } |
Давайте определим разделы, которые вы добавили:
-
Directives:
listen: указывает Nginx прослушивать порт80. Это позволяет использовать webroot-плагин Certbot для отправки запросов на получение сертификатов. Как только мы получим SSL-сертификат, мы обновим эту конфигурацию для использования порта443.server_name: это определяет доменное имя, которое должна обрабатывать эта конфигурация. Трафик на указанное здесь доменное имя будет направляться в этот конкретный блок сервера и, следовательно, в корневой каталог документовroot.root: определяет корневой каталог для запросов к указанному выше доменному имени. Обычно это каталог, содержащий файлы нашего веб-сайта. Мы установили этот каталог как/var/www/html. Он будет создан как точка монтирования Docker во время сборки контейнера. Мы определим инструкции для этого процесса внутри WordPress Dockerfile.index: определяет файлы, которые будут использоваться в качестве индексных файлов или точки входа на ваш веб-сервер при обработке запросов. Мы переместили index.php перед index.html, чтобы Nginx отдавал приоритетindex.php.
-
Блоки location:
location ~ /.well-known/acme-challenge: обрабатывает запросы к известной директории (well-known), куда Certbot добавляет временный файл для подтверждения того, что DNS для указанного домена указывает на конкретный сервер, у которого мы запрашиваем SSL-сертификаты. Вот почему для работы этого шага вам следует добавить действительный домен вместоexample.com, который мы используем в этом руководстве.location /: принимает URI-запросы и передает управление WordPressindex.phpдля запроса аргументов для обработки.location ~ \.php$: обрабатывает PHP и передает запрос в контейнер WordPress (мы определим конфигурационный файл для этого на более позднем этапе). Мы определили конфигурации, специфичные для протокола FastCGI здесь, потому что Docker-образ WordPress будет основан на образе php:fpm. Nginx использует независимый PHP-процессор для PHP-запросов. Мы будем использовать процессорphp-fpm, который поставляется сphp:fpmDocker-образом.location ~ /\.ht: обрабатывает файлы.htaccess, которые Nginx не использует. Директиваdeny allгарантирует, что эти файлы никогда не будут отдаваться посетителям сайта.location = /favicon.ico, location = /robots.txt: как видно из определения, это предотвращает логирование запросов к файлам/favicon.icoи/robots.txt.location ~* \.(css|gif|ico|jpeg|jpg|js|png)$: отключает логирование запросов к статическим файлам и обеспечивает их кэширование для снижения нагрузки на сервер.
Теперь вы можете сохранить и закрыть файл, нажав CTRL+X, Y, затем ENTER. На этом первый шаг завершен.
Шаг 2: Определение переменных окружения
Переменные окружения необходимы для облегчения взаимодействия между приложением WordPress и базой данных. Они также обеспечивают сохранение данных приложения. Переменные окружения включают конфиденциальную информацию, такую как учетные данные базы данных, и неконфиденциальную информацию, такую как имя базы данных и хост.
В целях безопасности всегда рекомендуется не добавлять конфиденциальную информацию в репозитории проектов. Поэтому вместо того, чтобы задавать конфиденциальные значения в файле Docker Compose, мы определим учетные данные MySQL внутри файлов .env, которые не будут закоммичены в репозиторий проекта и не подвергнутся риску публичного раскрытия. В корневой директории проекта root ~/wordpress_docker откройте файл .env:
|
1 |
nano .env |
|
1 2 3 |
MYSQL_ROOT_PASSWORD=your_strong_root_password MYSQL_USER=your_wordpress_database_user MYSQL_PASSWORD=strong_wordpress_database_password |
Следующее, что вам нужно сделать, это добавить файл .env в файлы .gitignore и .dockerignore, чтобы гарантировать, что он не попадет в ваши репозитории или Docker-образы соответственно.
Это необязательно для данного руководства, но если вы хотите работать с Git для контроля версий, введите следующую команду, чтобы инициализировать текущую директорию как репозиторий git:
|
1 |
git init |
Откройте .gitignore с помощью nano:
|
1 |
nano .gitignore |
Добавьте следующую строку:
|
1 |
.env |
Сохраните и закройте файл. Затем откройте .dockerignore с помощью nano:
|
1 |
nano .dockerignore |
Добавьте следующую строку:
|
1 |
.env |
Попутно вы можете по желанию добавить другие файлы и директории, связанные с разработкой вашего приложения:
|
1 2 3 |
.env .git docker-compose.yml |
Сохраните и закройте файл, когда закончите. Это все для этого шага. Перейдем к определению Docker Compose.
Шаг 3: Настройка служб с помощью Docker Compose
Docker Compose использует docker-compose.yml файл для сборки образов. Этот файл содержит определения служб для полной настройки приложения. Определения служб — это, по сути, инструкции по запуску контейнера. Служба — это фактически запущенный контейнер.
Docker Compose позволяет определять различные службы для многоконтейнерных приложений, связывая их друг с другом с помощью общих сетей и томов. Вы увидите это в действии, так как мы определим три контейнера для нашего приложения: веб-сервер, установку WordPress и базу данных. Мы добавим четвертый контейнер для запуска клиента Certbot для продления сертификатов.
Введите следующую команду, чтобы создать docker-compose.yml файл:
|
1 |
nano docker-compose.yml |
Первая строка в файле docker-compose.yml — это строка определения версии. Для нашей мы установили значение 3. Затем вы можете начать определять свои службы. Добавьте следующий фрагмент кода в файл, чтобы определить службу db:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
version: '3' services: #MySQL Service 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: определяет образ, на котором будет основан контейнер. Всегда лучше указывать конкретную версию (mysql:8.0), чем использовать тег latest (mysql:latest), так как будущие версии образов MySQL могут конфликтовать с нашим приложением, если мы решим пересобрать этот образ. Вы можете найти дополнительную информацию о лучших практиках Dockerfile в официальной документации Dockerfile Docs.container_name: здесь мы указываем имя контейнера.restart: эта директива определяет поведение контейнера при перезапуске. По умолчанию установлено значениеno, но мы настроили его на постоянныйперезапуск, если только он не будет остановлен вручную.env_file: эта директива используется для указания пути к файлу с переменными окружения (.env), используемыми нашим приложением.environment: используется для указания дополнительных переменных окружения. В этом руководстве мы указали переменнуюMYSQL_DATABASEдля хранения имени базы данных нашего приложения. Имя базы данных может быть включено вdocker-compose.yml.volumes: используется для указания мест монтирования. В нашем примере мы примонтировали именованный том с именем dbdata к директории/var/lib/mysqlв контейнере, которая обычно является стандартным каталогом данных для MySQL.command: эта директива указывает команду, которая переопределит стандартную инструкцию CMD для образа. Мы добавили опцию к стандартной командеmysqldобраза Docker, которая запускает сервер MySQL внутри контейнера. Мы добавили опцию--default-authentication-plugin=mysql_native_password, которая обновляет плагин аутентификации по умолчанию для MySQL для использования аутентификации по паролю (mysql_native_password). Это необходимо для работы вашего PHP-приложения (WordPress), поскольку оно использует имя пользователя и пароль для доступа к базе данных. В более новых версиях MySQL плагин аутентификации по умолчанию изменился. Однако большинство приложений используют аутентификацию по паролю. Таким образом, вы должны изменить эту настройку, чтобы приложение работало.networks: эта директива используется для указания того, что службаdbдолжна быть подключена к сетиapp-network, которую мы определим далее в руководстве.
Далее давайте определим конфигурацию службы для нашего приложения WordPress. Мы назовем службу и container_name app. Добавьте следующий фрагмент кода под определением службы db, помня о правильных отступах:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
#Служба кода приложения WordPress app: depends_on: - db image: wordpress:5.1.1-fpm-alpine container_name: app 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: - app:/var/www/html networks: - app-network |
Как и в случае со службой db, мы назвали наш контейнер и определили политику перезапуска. Некоторые другие добавленные нами параметры описаны ниже:
depends_on: эта директива гарантирует, что контейнеры запускаются в порядке зависимости. В нашем случае контейнерappзависит от контейнераdb. Следовательно, он запустится после того, как запустится контейнерdb. Это должно происходить именно в таком порядке, поскольку для работы приложения WordPress требуется наличие базы данных MySQL.image: как видно из фрагмента кода, мы будем использовать WordPress версии 5.1.1 fpm alpine образ. Мы уже объясняли работу процессораphp-fpm, который требуется Nginx для обработки PHP. Этот образ берет это на себя. Образ alpine, основанный на проекте Alpine Linux, помогает уменьшить размер образа. Если вам нужна дополнительная информация о разновидностях образов, вы можете перейти по этой ссылке на образы WordPress на Docker Hub.env_file: указывает расположение файла.env, содержащего учетные данные базы данных.environment: эта директива определяет дополнительные переменные окружения. В нашем случае мы определяем переменные, которые ожидает WordPress, и присваиваем им значения переменных из нашего файла.env. ЭтоWORDPRESS_DB_USER,WORDPRESS_DB_PASSWORD, иWORDPRESS_DB_HOST, который ссылается на сервер MySQL, работающий в контейнереdb, доступный через порт MySQL по умолчанию3306. Наконец, вы видитеWORDPRESS_DB_NAME, для которого мы установили значение wordpress. Это же значение указано в определении службы MySQL в контейнере db:MYSQL_DATABASE=wordpress.volumes: эта директива монтирует том с именем app в точку монтирования/var/www/html, созданную образом WordPress. Именование томов позволяет совместно использовать код приложения с другими контейнерами.networks: наконец, мы добавляем контейнер app в сетьapp-network, чтобы обеспечить его связь с другими контейнерами в сети.
На этом все со службой контейнера app для образа WordPress. Теперь давайте определим службу webserver для образа Nginx. Сначала добавьте следующий фрагмент кода под определением службы app в ваш файл docker-compose.yml:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
#Служба веб-сервера Nginx webserver: depends_on: - app image: nginx:1.15.12-alpine container_name: webserver restart: unless-stopped ports: - "80:80" volumes: - app:/var/www/html - ./nginx-conf:/etc/nginx/conf.d - certbot-etc:/etc/letsencrypt networks: - app-network |
Мы уже объясняли параметр depends_on. В случае этой службы webserver контейнер запустится после запуска контейнера app. Контейнер веб-сервера основан на образе alpine Nginx. Он имеет аналогичную политику перезапуска, что и предыдущие определения служб. Другие параметры в определении службы webserver включают в себя:
ports: связывает порты хост-машины и контейнера. В Шаге 1, мы определили порт80в файлеnginx.conf. Этот порт сопоставлен с портом80на контейнере.volumes: у нас есть комбинация монтирований привязки и именованных томов в этом параметре:app:/var/www/html: это определение тома монтирует приложение WordPress в директорию/var/www/html, которую ранее мы установили в качестве корневой в блоке сервера Nginx../nginx-conf:/etc/nginx/conf.d: это определение монтирует директорию конфигурации Nginx на хост-машине в директорию конфигурации Nginx, определенную для контейнера. Таким образом, любые изменения на хост-машине автоматически отражаются в контейнере.certbot-etc:/etc/letsencrypt: это определение монтирует сертификаты и ключи Let’s Encrypt для домена в соответствующую директорию в контейнере.
networks: как и в предыдущих определениях служб, директиваnetworksдобавляет службу webserver вapp-networks.
Поскольку мы закончили с определением веб-сервера, давайте добавим инструкции для службы Certbot. Она будет отвечать за получение ваших сертификатов TLS/SSL от Let’s Encrypt. Если вы хотите узнать больше об обеспечении безопасности сервера Nginx, это руководство по обеспечению безопасности Nginx с помощью Let’s Encrypt является хорошим источником.
Затем добавьте следующий фрагмент кода под службой webserver. Не забудьте указать правильное доменное имя и адрес электронной почты:
|
1 2 3 4 5 6 7 8 9 10 |
#certbot service certbot: depends_on: - webserver image: certbot/certbot container_name: certbot volumes: - certbot-etc:/etc/letsencrypt - app:/var/www/html command: certonly --webroot --webroot-path=/var/www/html --email hackins@cloudsigma.com --agree-tos --no-eff-email --staging -d example.com -d www.example.com |
Образ certbot запустится только после того, как запустится webserver, из-за директивы depends_on. Docker Compose загрузит образ Certbot из Docker Hub, как определено.
В определении томов контейнер Certbot будет совместно использовать сертификаты и ключ домена в certbot-etc с контейнером Nginx webserver и код приложения с контейнером app.
В определении command мы указали подкоманду для запуска стандартной команды Certbot контейнера certonly с дополнительными параметрами, перечисленными ниже:
-
--webroot: указывает на использование плагина webroot, который помещает файлы в папку webroot для аутентификации.--webroot-path: указывает путь к директории webroot.--agree-tos: указывает, что вы соглашаетесь с Условиями обслуживания ACME.--no-eff-email: указывает, что вы не хотите делиться своим адресом электронной почты с EFF. Вы можете опустить это, если хотите поделиться.--staging: указывает Certbot, что вы хотите сначала получить тестовые сертификаты из промежуточной среды (staging) Let’s Encrypt для тестирования вашей конфигурации перед получением фактического сертификата. У Let’s Encrypt есть ограничение частоты запросов для доменов. Поэтому предварительное тестирование конфигурации поможет вам избежать ограничений для вашего домена.-d: этот параметр принимает доменные имена для запроса сертификата. В этом руководстве мы включилиexample.comиwww.example.com. Пожалуйста, укажите ваш фактический зарегистрированный домен.
Наш файл docker-compose.yml почти готов. Однако вы также должны добавить определения сетей и томов под службой Certbot:
|
1 2 3 4 5 6 7 8 9 10 |
#Volumes volumes: certbot-etc: app: dbdata: #Networks networks: app-network: driver: bridge |
Ключ volumes определяет тома, которые будут совместно использоваться всеми службами (контейнерами), определенными в этом файле compose: certbot-etc, app, и dbdata. Содержимое томов, создаваемых Docker, хранится в директории, управляемой Docker в файловой системе хоста: /var/lib/docker/volumes/. Затем содержимое каждого тома монтируется в любой контейнер, использующий этот том. Это делает возможным совместное использование данных и кода между контейнерами.
Ключ networks определяет мост сети (bridge network), который позволяет контейнерам взаимодействовать друг с другом. Контейнеры в одной сети-мосте, такие как webserver и db могут безопасно взаимодействовать через порты, не открывая трафик для внешней сети. Мы открываем только порт 80 для обеспечения доступа к страницам фронтенд-сайта.
Полный файл docker-compose.yml будет выглядеть следующим образом:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 |
version: '3' services: #Служба MySQL 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 app: depends_on: - db image: wordpress:5.1.1-fpm-alpine container_name: app 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: - app:/var/www/html networks: - app-network #Служба веб-сервера Nginx webserver: depends_on: - app image: nginx:1.15.12-alpine container_name: webserver restart: unless-stopped ports: - "80:80" volumes: - app:/var/www/html - ./nginx-conf:/etc/nginx/conf.d - certbot-etc:/etc/letsencrypt networks: - app-network #Служба certbot certbot: depends_on: - webserver image: certbot/certbot container_name: certbot volumes: - certbot-etc:/etc/letsencrypt - app:/var/www/html command: certonly --webroot --webroot-path=/var/www/html --email hackins@cloudsigma.com --agree-tos --no-eff-email --staging -d example.com -d www.example.com #Тома volumes: certbot-etc: app: dbdata: #Сети networks: app-network: driver: bridge |
Вы можете сохранить и закрыть файл. На следующем шаге мы запустим и протестируем контейнер и запросы сертификатов.
Шаг 4. Запуск контейнеров и получение SSL-сертификатов
Самое большое преимущество Docker Compose заключается в том, что после определения всех служб в файле docker-compose.yml файле вы можете запустить все контейнеры всего одной командой: docker-compose up. Эта команда выполняет каждую указанную инструкцию. Если запросы к домену прошли успешно, вы должны увидеть правильный статус выхода в своем терминале. Введите следующую команду для создания контейнеров. Флаг -d предназначен для запуска контейнеров в фоновом режиме:
|
1 |
docker-compose up -d |
Если вы видите вывод, как на скриншоте ниже, значит, службы были успешно созданы:
Чтобы подтвердить статус служб, выполните команду docker-compose ps:
|
1 |
docker-compose ps |
Вывод команды будет таким, как показано ниже, если все прошло успешно. Состояние контейнеров app, db, и webserver должно быть up, а контейнер certbot должен иметь статус Exit0:
Если вы видите что-либо, кроме Up в столбце состояния для app, db или webserver, или статус Exit, отличный от 0 для certbot контейнера, значит, что-то пошло не так. Вы можете проверить логи каждого контейнера с помощью команды docker-compose logs, указав service_name:
|
1 |
docker-compose logs service_name |
Например, вы можете проверить логи контейнера certbot, введя следующую команду:
|
1 |
docker-compose logs certbot |
Чтобы проверить, были ли смонтированы сертификаты в контейнер webserver, используйте команду docker-compose exec:
|
1 |
docker-compose exec webserver ls -la /etc/letsencrypt/live |
Если вы использовали реальное зарегистрированное доменное имя вместо example.com и запросы на получение сертификатов прошли успешно, вы должны увидеть вывод, похожий на этот:
После того как вы убедитесь, что запрос сертификата прошел успешно, вы можете отредактировать файл docker-compose.yml и удалить флаг --staging. Откройте файл с помощью nano:
|
1 |
nano docker-compose.yml |
Прокрутите вниз до раздела определения службы Certbot, найдите опцию command и замените флаг --staging флагом --force-renewal. Это указывает Certbot, что вы запрашиваете обновление сертификата для того же домена. Теперь определение вашей службы Certbot должно выглядеть следующим образом:
|
1 2 3 4 5 6 7 8 9 10 |
#certbot service certbot: depends_on: - webserver image: certbot/certbot container_name: certbot volumes: - certbot-etc:/etc/letsencrypt - app:/var/www/html command: certonly --webroot --webroot-path=/var/www/html --email hackins@cloudsigma.com --agree-tos --no-eff-email --force-renewal -d example.com -d www.example.com |
Сохраните файл после завершения редактирования.
Введите следующую команду, чтобы пересоздать контейнер certbot. Включенный флаг --no-deps указывает Compose пропустить перезапуск службы веб-сервера, так как она уже запущена:
|
1 |
docker-compose up --force-recreate --no-deps Certbot |
Команда выведет результат, как на следующем скриншоте, показывающий, что запрос сертификата прошел успешно:
На этом данный шаг завершен. На следующем шаге вы измените конфигурационный файл Nginx, чтобы добавить SSL-сертификат.
Шаг 5. Включение SSL в конфигурации Nginx и определении службы
Чтобы Nginx обслуживал трафик по безопасному протоколу SSL, сначала вы измените конфигурационный файл Nginx, добавив перенаправление с HTTP на HTTPS. Затем вам нужно будет указать расположение сертификата и ключа, и, наконец, добавить параметры безопасности и заголовки.
Перед изменением конфигурационного файла вам следует получить рекомендуемые параметры безопасности Nginx из репозитория Certbot на GitHub с помощью curl следующей командой:
|
1 |
curl -sSLo nginx-conf/options-ssl-nginx.conf |
Команда выполняется и сохраняет полученные параметры в файл с именем options-ssl-nginx.conf, внутри директории nginx-conf. Удалите конфигурационный файл Nginx, чтобы мы могли создать новый с помощью следующих команд:
|
1 2 |
rm nginx-conf/nginx.conf nano nginx-conf/nginx.conf |
В теперь уже пустой файл nginx.conf, добавьте следующий код, который включает перенаправление с HTTP на HTTPS, SSL протоколы учетных данных и заголовки безопасности. Как вы делали ранее, замените домен example.com вашим собственным зарегистрированным доменом:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 |
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-Безопасность-Policy "default-src * data: 'unsafe-eval' 'unsafe-inline'" always; # add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always; # включайте strict transport security только в том случае, если вы понимаете последствия location / { try_files $uri $uri/ /index.php$is_args$args; } location ~ \.php$ { try_files $uri =404; fastcgi_split_path_info ^(.+\.php)(/.+)$; fastcgi_pass app: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; } } |
В первом блоке server, который обрабатывает незащищенные запросы через порт 80, мы указываем корневую веб-директорию (webroot) для запросов на продление Certbot. Мы также добавляем директиву перенаправления, которая перенаправляет запросы HTTP на HTTPS.
Второй блок server обрабатывает защищенный трафик HTTPS, поступающий на порт 443. Как видите, мы также включаем SSL и HTTP2. HTTP/2 повышает производительность вашего сервера. Вы можете узнать об этом подробнее в официальной документации Nginx по HTTP/2.
В этом блоке мы также указали, что Nginx включает пути к SSL-сертификату и ключу, а также рекомендуемые параметры безопасности Certbot, которые curl сохранил в nginx-conf/options-ssl-nginx.conf директорию.
Дополнительные заголовки безопасности служат для повышения рейтинга вашего сайта на ресурсах для тестирования безопасности, таких как Security Headers и SSL Labs. Вы можете перейти по ссылкам на эти заголовки, чтобы узнать больше: X-Frame-Options, Referrer Policy, X-Content-Type-Options, X-XSS-Protection, Content-Security-Policy. Мы закомментировали заголовок HTTP Strict Transport Security (HSTS). Вы можете прочитать о его функции предварительной загрузки (preload) и решить, хотите ли вы его включить.
Остальные директивы, такие как root, index, и специфичные для WordPress блоки location остаются такими же, как мы обсуждали на Шаге 1. Теперь вы можете сохранить и закрыть файл после завершения редактирования.
Теперь, когда мы включили трафик HTTPS, использующий порт 443,, мы также должны включить этот порт в определении службы веб-сервера. Введите следующую команду, чтобы открыть файл docker-compose.yml с помощью nano:
|
1 |
nano docker-compose.yml |
В разделе webserver в параметре ports добавьте сопоставление для порта 443, как показано ниже:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
webserver: depends_on: - app image: nginx:1.15.12-alpine container_name: webserver restart: unless-stopped ports: - "80:80" - "443:443" volumes: - app:/var/www/html - ./nginx-conf:/etc/nginx/conf.d - certbot-etc:/etc/letsencrypt networks: - app-network |
Полный файл docker-compose.yml теперь должен выглядеть следующим образом:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 |
version: '3' services: #Сервис MySQL 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 app: depends_on: - db image: wordpress:5.1.1-fpm-alpine container_name: app 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: - app:/var/www/html networks: - app-network #Сервис веб-сервера Nginx webserver: depends_on: - app image: nginx:1.15.12-alpine container_name: webserver restart: unless-stopped ports: - "80:80" - "443:443" volumes: - app:/var/www/html - ./nginx-conf:/etc/nginx/conf.d - certbot-etc:/etc/letsencrypt networks: - app-network #Сервис certbot certbot: depends_on: - webserver image: certbot/certbot container_name: certbot volumes: - certbot-etc:/etc/letsencrypt - app:/var/www/html command: certonly --webroot --webroot-path=/var/www/html --email hackins@cloudsigma.com --agree-tos --no-eff-email --force-renewal -d example.com -d www.example.com #Тома volumes: certbot-etc: app: dbdata: #Сети networks: app-network: driver: bridge |
Убедившись, что всё выглядит правильно, сохраните и закройте файл. После этого выполните следующую команду, чтобы пересоздать webserver сервис:
|
1 |
docker-compose up -d --force-recreate --no-deps webserver |
|
1 |
docker-compose ps |
Теперь, когда все ваши контейнеры запущены, можно перейти к настройке WordPress через веб-интерфейс.
Шаг 6. Завершите настройку WordPress через веб-интерфейс
Перейдите по доменному имени вашего сервера, чтобы продолжить установку. Вы должны увидеть домашнюю страницу настройки WordPress. Она предлагает вам выбрать язык перед продолжением:
Выберите язык и нажмите Продолжить, чтобы перейти на следующую страницу:
На этой странице укажите название вашего сайта, выберите запоминающееся имя пользователя и надежный пароль. В целях безопасности не рекомендуется использовать Admin в качестве имени пользователя. Введите свой адрес электронной почты и нажмите кнопку Установить WordPress, чтобы начать установку WordPress.
После завершения установки вы будете перенаправлены на экран входа, где вам нужно будет ввести имя пользователя и пароль, которые вы установили. После ввода правильных учетных данных вы увидите панель управления WordPress:
Вы успешно установили WordPress! Далее вам необходимо предпринять шаги для обеспечения автоматического продления SSL-сертификатов.
Шаг 7. Настройка автоматического продления SSL-сертификатов
TLS/SSL-сертификаты Let’s Encrypt действительны только в течение 90 дней. Вам необходимо настроить автоматическое продление, чтобы срок их действия не истек. Вы можете сделать это, создав скрипт и запланировав его выполнение с помощью утилиты задачи cron. На этом шаге мы покажем вам, как создать скрипт для продления сертификатов. Затем мы запланируем его с помощью утилиты задач cron, чтобы периодически запускать его и продлевать сертификаты, если приближается дата окончания их действия.
Внутри директории проекта wordpress_docker откройте скрипт с именем ssl_renewer.sh с помощью nano:
|
1 |
nano ssl_renewer.sh |
Добавьте следующий код в скрипт для автоматического продления и перезапуска конфигурации Nginx. Не забудьте заменить выделенное имя пользователя на ваше имя пользователя без прав root:
|
1 2 3 4 5 6 7 8 |
#!/bin/bash COMPOSE="/usr/local/bin/docker-compose –ansi never" DOCKER="/usr/bin/docker" cd /home/hackins/wordpress_docker/ $COMPOSE run certbot renew --dry-run && $COMPOSE kill -s SIGHUP webserver $DOCKER system prune -af |
В этом скрипте мы присваиваем исполняемый файл docker-compose переменной с именем COMPOSE. Мы также добавляем опцию –ansi never, которая указывает скрипту запускать команды docker-compose без управляющих символов ANSI. Далее мы присваиваем исполняемый файл Docker переменной с именем DOCKER.
Затем скрипт переходит в директорию нашего проекта wordpress_docker и выполняет следующие команды:
docker-compose run: запускает контейнер certbot и переопределяет команду, указанную в определении службы certbot. Вместо запуска подкоманды certonly запускается подкоманда renew, которая продлит SSL/TLS-сертификаты Let’s Encrypt, если срок их действия подходит к концу.docker-compose kill: отправляет сигнал SIGHUP контейнеруwebserverдля перезапуска конфигураций Nginx. Возможно, вы захотите ознакомиться с этим руководством от Docker о том, как использовать официальный Docker-образ Nginx.docker system prune: эта команда удаляет все неиспользуемые контейнеры и образы.
Сохраните и закройте файл после завершения редактирования. Затем выполните следующую команду, чтобы сделать его исполняемым:
|
1 |
chmod +x ssl_renewer.sh |
После того как вы сделали его исполняемым, откройте файл crontab суперпользователя root, чтобы запускать скрипт периодически с заданным интервалом:
|
1 |
sudo crontab -e |
Утилита crontab предложит вам выбрать предпочитаемый редактор, если вы используете ее впервые:
Выберите предпочитаемый редактор и нажмите Enter, чтобы открыть файл. В самый конец файла добавьте следующую строку:
|
1 |
*/5 * * * * /home/hackins/wordpress_docker/ssl_renewer.sh >> /var/log/cron_docker.log 2>&1 |
Это устанавливает пятиминутный интервал, чтобы мы могли проверить, работает ли наш скрипт продления. Мы также указали лог-файл, в который будет записываться вывод задачи: cron_docker.log.
Подождите пять минут и проверьте cron.log, чтобы проверить, был ли запрос на продление успешным:
|
1 |
tail -f /var/log/cron_docker.log |
Если запросы прошли успешно, вы должны увидеть что-то похожее на скриншот ниже:
Теперь, когда мы протестировали и подтвердили работоспособность, вы можете изменить файл crontab, чтобы настроить ежедневное продление. Например, вы можете указать, чтобы скрипт запускался каждый день в 18:00. Для этого измените последнюю строку crontab, чтобы она выглядела следующим образом:
|
1 |
0 18 * * * /home/hackins/wordpress_docker/ssl_renewer.sh >> /var/log/cron_docker.log 2>&1 |
Кроме того, вам нужно удалить флаг –dry-run из скрипта ssl_renewer.sh, чтобы при его запуске происходило реальное продление. Он должен выглядеть так:
|
1 2 3 4 5 6 7 8 |
#!/bin/bash COMPOSE="/usr/local/bin/docker-compose --ansi never" DOCKER="/usr/bin/docker" cd /home/hackins/wordpress_docker/ $COMPOSE run certbot renew && $COMPOSE kill -s SIGHUP webserver $DOCKER system prune -af |
Затем сохраните и закройте файл. После этого задача cron будет поддерживать ваши сертификаты в актуальном состоянии, продлевая их до истечения 90-дневного срока.
Заключение
Если вы дошли до этого момента в руководстве, вы можете считать себя на шаг ближе к тому, чтобы стать DevOps-инженером. Вы смогли создать конфигурационный скрипт Nginx, создали файл docker-compose.yml и определили несколько служб, необходимых для запуска приложения WordPress с помощью Docker & Compose. Вы получили сертификаты SSL/TLS от Let’s Encrypt, чтобы обеспечить безопасность вашего веб-сервера. Наконец, вы создали задачу cron, чтобы гарантировать, что срок действия сертификатов не истечет. Отличная работа!
Если вы хотите глубже погрузиться в DevOps, ознакомьтесь с другими ресурсами по контейнерам в нашем блоге:
- Знакомство с Kubernetes
- Как развернуть приложение Node.js (Express.js) с помощью Docker на Ubuntu 20.04
- Развертывание PHP-приложения в кластере Kubernetes на Ubuntu 18.04.
- Развертывание Laravel, Nginx и MySQL с помощью Docker Compose
Приятной работы!










Комментарии
Комментариев пока нет. Будьте первым.