Предыдущая статья разложила конфигурацию сайта на пять слоёв и показала, кто кого переопределяет. Здесь — практика того же: три текстовых конфига, которые администратор WordPress держит в руках каждый день (wp-config.php, .env, php.ini), где у каждого правильный набор директив и почему править их наугад дороже, чем кажется. Разберём пограничную путаницу («адрес сайта — в базу или в wp-config?», «зачем в WordPress .env, если ядро его не читает?», «лимит памяти — в php.ini или в пуле?»), покажем рабочий паттерн разделения dev/staging/prod через переменные окружения и объясним, почему сгенерированный конфиг всегда приходит с плейсхолдерами вместо паролей, а не с боевыми секретами.
Часть I. Три конфига и границы их ответственности
Начнём с главного, что путают: это три разных файла, и настройка попадает «не туда» не из-за ошибки ввода, а из-за неверной модели. Одна таблица:
| Файл | Где лежит | Ответственность | Читается кем | Когда правится |
|---|---|---|---|---|
wp-config.php | в корне WordPress | константы ядра: креды БД, адрес сайта, соли, префикс таблиц, WP_DEBUG, FS_METHOD | WordPress-ядро, до подключения к БД | при установке и миграции |
.env | рядом с проектом (не обязателен) | ключ=значение для разделения секретов/параметров между окружениями | обёртка (Docker / mu-plugin / wp-cli env), не ядро | при настройке dev/staging/prod |
php.ini | /etc/php/…/fpm/php.ini и копия в пуле | лимиты движка: memory_limit, upload_max_filesize, max_execution_time, Opcache | PHP-FPM (и отдельно — CLI) | при смене нагрузок/лимитов |
Мнемоника для границы: wp-config отвечает «как WordPress находит себя», php.ini — «сколько движку можно», .env — «что меняется между окружениями». Лимит загрузки 64 МБ — это php.ini (движок), а не wp-config (там такой константы нет). Название сайта, который виден в админке — это база (слой опций), а не wp-config. Адрес продакшна, который нельзя менять без деплоя — как раз кандидатур в .env. Если настройка «не нашла своего файла» — вернитесь к таблице слоёв в предыдущей статье.
Ещё одна пограничная ловушка: php.ini и пул — это один и тот же слой, но два файла (базовый слой против точечного на сайт). Не путайте их с wp-config: директива memory_limit в php.ini не имеет отношения к константе WP_MEMORY_LIMIT, которая просит у PHP больше памяти для ядра WordPress. У каждой из них свой адресат.
Часть II. wp-config.php: константы, которые нельзя править наугад
Ключевое свойство этого файла: он исполняется до того, как WordPress что-либо прочитал из базы. Значит, всё, что здесь объявлено, доступно ядру в самый ранний момент — и всё, что здесь неверно, ломает загрузку сайта целиком, а не отдельную страницу.
Базовый набор:
<?php
// подключение к базе — без этих четырёх сайт не стартует вовсе
define( 'DB_NAME', 'wp_database' );
define( 'DB_USER', 'wp_user' );
define( 'DB_PASSWORD', 'REPLACE_ME' ); // см. Часть V: боевой пароль подставляет человек
define( 'DB_HOST', 'localhost' );
// префикс таблиц — у стоковой установки 'wp_'
$table_prefix = 'wp_';
// уникальный «отпечаток» установки: 8 ключей-солей
define( 'AUTH_KEY', 'REPLACE_ME' );
define( 'NONCE_SALT', 'REPLACE_ME' );
// … (остальные шесть)
// поведение ядра
define( 'WP_DEBUG', false );
define( 'WP_DEBUG_LOG', true ); // писать ошибки в файл, не на экран гостя
define( 'WP_DEBUG_DISPLAY', false );
define( 'DISALLOW_FILE_EDIT', true ); // запретить правку тем/плагинов из админки
define( 'FS_METHOD', 'direct' ); // ставить обновления напрямую, без FTPТри правила, нарушение которых стоит часов диагностики:
1. Адрес сайта — в одном месте, а не в двух. Либо home/siteurl в базе (обычный случай), либо константы в wp-config:
<?php
// ЭТИ строки перекроют поле в базе. Держать и базу, и константы — значит рассинхронить их при миграции.
define( 'WP_HOME', 'https://example.test' );
define( 'WP_SITEURL', 'https://example.test' );Если решили жить на константах — помните: wp search-replace по базе на них не действует. Разбор замены URL при переезде — в Миграция WordPress между серверами.
2. Соли и ключи — генерируются, не выдумываются. Они уникальны на всю установку; их смена выкидывает из сессий всех залогиненных (и ломает active-nonce у форм). Генерируются официальным WordPress-генератором salts, а не «на глаз». Почему нельзя терять соли в открытом виде и как они работают с паролями — в Шифрование данных и хранение паролей.
3. В wp-config нет «бытовых» настроек. Часовой пояс, «показывать N записей», категория по умолчанию — этого здесь быть не должно; это опции в базе. Критерий из предыдущей статьи: «можно ли это задать в админке?» — если да, дом в базе, а не здесь.
Отдельная, самая дорогая грабля: wp-config.php — shared-файл между релизами, его нельзя перезаписывать кодом из репозитория. Иначе новый выкат затрёт креды. Как выкатывать код, не трогая wp-config — в Деплой без боли.
Часть III. .env в WordPress: где уместен, а где нет
Самый частый вопрос серии: «зачем WordPress нужен .env, если ядро его не читает?» Честный ответ: ядро действительно не читает .env. Файл работает только тогда, когда есть обёртка, которая его грузит и передаёт переменные в PHP. Отсюда и правила применения.
Где .env уместен
Когда у вас несколько окружений (dev на ноутбуке, staging, prod на VPS) и вы хотите один код, но разные секреты/параметры. Тогда:
- окружение (Docker, systemd, nginx→php-fpm
env[...], wp-cli) загружает.envи делает переменные доступными PHP; wp-config.phpчитает их черезgetenv()с фолбэком — и сам становится окруженчески-нейтральным:
<?php
// wp-config.php читает переменные окружения; боевые значения приходят из .env, а не хардкодом
function wpc_env( string $name, ?string $default = null ): ?string {
$v = getenv( $name );
return ( $v === false || $v === '' ) ? $default : $v;
}
define( 'DB_NAME', wpc_env( 'DB_NAME', 'wp_database' ) );
define( 'DB_USER', wpc_env( 'DB_USER', 'wp_user' ) );
define( 'DB_PASSWORD', wpc_env( 'DB_PASSWORD', 'REPLACE_ME' ) );
define( 'DB_HOST', wpc_env( 'DB_HOST', 'localhost' ) );
define( 'WP_HOME', wpc_env( 'WP_HOME', 'https://example.test' ) );
define( 'WP_SITEURL', wpc_env( 'WP_SITEURL', 'https://example.test' ) );
define( 'WP_DEBUG', wpc_env( 'WP_DEBUG' ) === '1' ); // 1 в dev, пусто/0 в prod# .env (для локальной разработки) — НЕ коммитить в git
DB_NAME=wp_database
DB_USER=wp_user
DB_PASSWORD=REPLACE_ME_WITH_REAL_DEV_PASSWORD
DB_HOST=localhost
WP_HOME=https://example.test
WP_DEBUG=1
Практическая польза ровно одна: wp-config.php и код больше не содержат секретов и адресов — те живут в .env, у которого свои права (chmod 600) и который лежит в .gitignore. При переезде между окружениями меняется только .env.
Где .env бесполезен и вреден
На голом shared-хостинге без доступа к переменным окружения и без Docker — .env просто нечем загрузить. Попытка «прикрутить» его ради совместности с модой добавляет лишний слой, который молча не работает: getenv() вернёт пусто, сайт возьмёт фолбэк, а вы будете думать, что сменили пароль, хотя .env не читался. В этом случае wp-config.php с константами — и есть правильный, единственный дом значений.
Минимальный вывод: .env имеет смысл ровно тогда, когда есть загрузчик (Docker/systemd/nginx-env/mu-plugin с Dotenv) и есть ≥2 окружения. Иначе — константы в wp-config, а про переменные окружения забудьте. Генератор форматов это различает: .env-выход — это пары КЛЮЧ=ЗНАЧЕНИЕ верхним регистром, а не PHP-константы.
Часть IV. php.ini: лимиты движка и связь с пулом
php.ini задаёт «сколько разрешено PHP», и это тот слой, где чаще всего «поставил лимит — а он не подействовал». Причин ровно две, обе из предыдущей статьи, здесь — применение к трём типичным директивам.
Что реально задаётся в php.ini (базовый слой для всех пулов):
; /etc/php/8.2/fpm/php.ini
memory_limit = 256M ; сколько памяти на один процесс
upload_max_filesize = 64M ; размер одного загружаемого файла
post_max_size = 68M ; всё POST-тело; обязано быть ≥ upload_max_filesize
max_execution_time = 300 ; сек на обработку запроса
max_input_time = 300
display_errors = Off ; в prod ошибки гостю не показывают
log_errors = On ; и пишутся в error_log
Три правила:
post_max_size≥upload_max_filesize— иначе большой файл отсекается раньше, чем PHP увидит его как «upload». Дефолтная инверсия (upload 64M при post 8M) — классика «прикрепляю видео, а оно не грузится».- у CLI и FPM разные копии
php.ini. Правки в…/cli/php.iniне касаются сайта, работающего через…/fpm/php.ini. «Проверил в терминале — лимит есть, на сайте — нет» это и есть. - пул перебивает
php.ini. Если вwww.confестьphp_admin_value[memory_limit]— базовый слой над ним не действует, и правкаphp.ini«не подействовала» ровно потому, что значение вбито выше.
Границы этой статьи: сам разбор пулов, php_admin_value против php_value, Opcache и slowlog — не здесь, а в PHP-FPM: движок под WordPress. Тут php.ini фигурирует как один из трёх форматов конфига и в разрезе «что задаёт кто».
Часть V. Генерировать конфиг, не выдумывая ключи: плейсхолдеры и preflight
Собрать три файла связно — механика, где цена ошибки не «вылет», а тихий переопределяющий слой из Части I. Ручная генерация типично даёт два дефекта: выдуманную директиву/константу, которую ядро проигнорирует, и реальный секрет, случайно вписанный в файл, который уедет в git. Второй — дороже. Отсюда два правила, на которых стоит любой ответственный генератор.
Правило 1: секреты всегда плейсхолдерами. Ни модель, ни шаблон не знают ваших паролей, солей и ключей API. Поэтому на месте секрета обязан быть явный маркер вроде REPLACE_ME / CHANGE_ME_WITH_REAL_VALUE, а не «выглядящее правдоподобно» значение. Значение, похожее на настоящий пароль и не помеченное как плейсхолдер, опаснее пустого: его заливают в прод и не меняют.
Правило 2: безопасные дефолты по окружению. Генератор, знающий, для какого окружения строит конфиг, подставляет разное:
- production —
WP_DEBUG=false,display_errors=Off/log_errors=On, лимиты консервативные; - staging — отладку можно включить, но секреты отдельными плейсхолдерами;
- development —
WP_DEBUG=true, мягкие лимиты, заметки-комментарии.
Preflight: чек-лист «что заменить перед запуском». Финальный шаг — приложить к сгенерированному файлу список того, что обязательно надо поправить руками: секреты, пути, домены. Он превращает «получил готовый конфиг» в «получил конфиг с известными дырами, которые надо закрыть до запуска». Это ровно то же мышление, что в Диагностике: система говорит правду о текущем состоянии, а не о том, что вы хотели задать.
Итого, боевой цикл такой: описал окружение → получил три связных конфига только с реальными директивами → получил плейсхолдеры вместо секретов и пометку «где дефолт» → получил preflight → заменил секреты и сохранил .env в .gitignore. Всё, кроме ручной замены секретов, — снимается с человека.
Инструменты под задачу
Описать окружение и получить связный wp-config.php / .env / php.ini — это как раз то, что в codestack.space делает ИИ-генератор конфигураций. Вы описываете окружение словами, выбираете формат (.env, wp-config.php, php.ini) и окружение (development / staging / production), а он отдаёт один конфиг-файл и соблюдает правила из Части V:
- только реальные директивы и константы — не выдуманные ключи, которые ядро бы проигнорировало;
- секреты всегда плейсхолдерами (
REPLACE_ME) с явным предупреждением «проверьте каждую строку и замените значения перед применением», потому что модель не знает ваших паролей; - безопасные значения по умолчанию — для production отладка и verbose выключены,
display_errors=Off/log_errors=On; - опции «комментарии / группировка по секциям / чек-лист что заменить» — включая preflight из Части V.
Попробуйте собрать конфиг под своё боевое окружение прямо здесь:
Он собирает один файл за прогон (.env отдельно от wp-config отдельно от php.ini) — поэтому три конфига из Части I делают тремя прогонами с одним и тем же описанием окружения. Решение, в какой из файлов положить настройку, остаётся за вами (Часть I); генератор снимает ручную часть — не забыть директиву, не выдумать ключ, не оставить реальный пароль в файле.
Чек-лист граблей
- Положили лимит загрузки в `wp-config` → такой константы нет, ядро игнорирует; дом `upload_max_filesize` — в `php.ini`.
- Держите адрес сайта и в базе, и в `WP_HOME` → рассинхрон при миграции; выберите один источник.
- Сменили соли/`AUTH_KEY` на живом сайте → всех выкинуло из сессий, формы с nonce сломались; соли генерируются раз при установке.
- Прикрутили `.env` на shared-хостинге без загрузчика → `getenv()` пусто, сайт взял фолбэк; `.env` работает только с Docker/systemd/nginx-`env`/mu-plugin.
- Закоммитили `.env` в git → боевые креды утекли; `.env` обязан быть в `.gitignore`, права `chmod 600`.
- Поставили `post_max_size` < `upload_max_filesize` → большой файл отсекается до «upload»; первый ≥ второго.
- Правите `…/cli/php.ini`, а сайт на `…/fpm/php.ini` → «в терминале работает, на сайте нет»; у CLI и FPM разные копии.
- Ждёте, что правка `php.ini` применится, а в пуле есть `php_admin_value` → базовый слой перебит; правьте пул (разбор — в статье про PHP-FPM).
- В сгенерированном конфиге значение похоже на реальный пароль и не помечено плейсхолдером → его не меняют и льют в прод; проверяйте, что секрет = явный `REPLACE_ME`.
- Прогнали генератор один раз и решили, что «конфиг готов» → он собирает один файл; нужно три конфига — три прогона с одним описанием окружения.
- Перезаписали `wp-config` при выкате из репозитория → затёрли креды; `wp-config` и `.env` — shared-файлы, не часть кода.
- Не закрыли preflight-чеклист перед запуском → секреты/пути/домены остались плейсхолдерами на проде; прогоните список «что заменить».
👤 Зарегистрируйтесь, чтобы добавить материал в закладки.
