Если WordPress нужен для локальной разработки или закрытого тестового стенда, не обязательно устанавливать PHP, MariaDB и веб-сервер на хост. Ниже — небольшой Compose-стек, в котором база не торчит наружу, пароли не записаны прямо в YAML, а WordPress начинает запускаться только после готовности MariaDB.
Что будет в проекте
wordpress-local/
├── compose.yaml
└── secrets/
├── db_password
└── db_root_password
Создайте каталог и два разных случайных пароля:
mkdir -p wordpress-local/secrets
cd wordpress-local
umask 077
openssl rand -base64 36 > secrets/db_password
openssl rand -base64 36 > secrets/db_root_password
umask 077 нужен, чтобы новые файлы мог читать только их владелец. Не добавляйте каталог secrets в Git. Для него достаточно строки secrets/ в .gitignore.
Готовый compose.yaml
services:
db:
image: mariadb:lts
restart: unless-stopped
environment:
MARIADB_DATABASE: wordpress
MARIADB_USER: wordpress
MARIADB_PASSWORD_FILE: /run/secrets/db_password
MARIADB_ROOT_PASSWORD_FILE: /run/secrets/db_root_password
secrets:
- db_password
- db_root_password
volumes:
- db_data:/var/lib/mysql
healthcheck:
test: ["CMD-SHELL", "healthcheck.sh --connect --innodb_initialized"]
interval: 10s
timeout: 5s
retries: 10
start_period: 30s
wordpress:
image: wordpress:php8.3-apache
restart: unless-stopped
depends_on:
db:
condition: service_healthy
environment:
WORDPRESS_DB_HOST: db:3306
WORDPRESS_DB_NAME: wordpress
WORDPRESS_DB_USER: wordpress
WORDPRESS_DB_PASSWORD_FILE: /run/secrets/db_password
secrets:
- db_password
ports:
- "127.0.0.1:8080:80"
volumes:
- wordpress_data:/var/www/html
cli:
image: wordpress:cli-php8.3
profiles:
- tools
user: "33:33"
depends_on:
db:
condition: service_healthy
environment:
WORDPRESS_DB_HOST: db:3306
WORDPRESS_DB_NAME: wordpress
WORDPRESS_DB_USER: wordpress
WORDPRESS_DB_PASSWORD_FILE: /run/secrets/db_password
secrets:
- db_password
volumes:
- wordpress_data:/var/www/html
secrets:
db_password:
file: ./secrets/db_password
db_root_password:
file: ./secrets/db_root_password
volumes:
db_data:
wordpress_data:
В современном Compose поле version не требуется: актуальная Compose Specification определяется самим Docker Compose. Старое version: "3" ничего полезного этому файлу не добавит.
Почему конфигурация устроена именно так
У db нет секции ports. WordPress обращается к базе по имени сервиса db внутри сети Compose. Для работы сайта публиковать MariaDB на всех интерфейсах хоста не нужно.
Порт WordPress привязан к 127.0.0.1. Поэтому страница доступна на том же компьютере по адресу http://127.0.0.1:8080, но не открывается всей локальной сети. Если стенд должен быть публичным, лучше поставить перед ним reverse proxy с HTTPS, а не менять привязку на 0.0.0.0 без дополнительной защиты.
Пароли передаются как Compose secrets и внутри контейнера читаются из /run/secrets/.... Это не делает локальную машину неуязвимой, но убирает пароль из compose.yaml, вывода docker inspect с environment и истории команд.
depends_on сам по себе задаёт только порядок запуска контейнеров. Условие service_healthy вместе с официальным healthcheck.sh MariaDB ждёт не просто запущенный процесс, а инициализированный InnoDB и рабочее подключение.
Именованные volumes переживают пересоздание контейнеров. db_data хранит базу, wordpress_data — ядро, плагины, темы и загрузки. Это удобно для стенда, но не заменяет резервную копию.
Первый запуск
Проверьте итоговую конфигурацию и запустите два постоянных сервиса:
docker compose config
docker compose up -d db wordpress
docker compose ps
Откройте http://127.0.0.1:8080 и пройдите обычную установку WordPress. Если страница не появилась, сначала смотрите состояние и последние сообщения:
docker compose ps
docker compose logs --tail=100 db wordpress
Не начинайте с удаления volumes: в большинстве случаев причина видна в журнале — неверные права на secret, незавершённая инициализация базы или занятый порт.
Как запускать WP-CLI
Сервис cli находится в профиле tools, поэтому постоянно не работает. Команда создаёт временный контейнер, подключает тот же volume и после выполнения удаляет контейнер:
docker compose run --rm cli core version
docker compose run --rm cli plugin list
docker compose run --rm cli option get home
UID 33:33 совпадает с пользователем www-data Debian-образа WordPress. Без этого файлы, созданные CLI-контейнером, могут получить другого владельца, и веб-контейнер не сможет их обновить.
Обновление без потери данных
Сначала сделайте и проверьте резервную копию базы и wordpress_data. Затем загрузите свежие образы и пересоздайте сервисы:
docker compose pull
docker compose up -d
docker compose ps
Не используйте docker compose down -v как обычную команду перезапуска: ключ -v удаляет именованные volumes этого проекта вместе с данными.
Что проверить перед использованием в production
- закрепить выбранную версию или digest образа и обновлять его по плану;
- поставить reverse proxy с HTTPS и корректными заголовками;
- настроить отдельные резервные копии базы и каталога WordPress;
- не хранить secrets в репозитории и ограничить права на файлы;
- включить обновления WordPress и плагинов по контролируемому процессу;
- не публиковать порт MariaDB в интернет.
Официальные источники