Какой у вас сервер: проверка до правки .htaccess

Заголовки ответа

Начните с одного запроса и прочитайте заголовок server. Инструменты здесь: curl, SSH, grep.

curl -sSI https://example.com/

HTTP/2 200 content-type: text/html; charset=UTF-8 server: Apache

Заголовок - подсказка, а не диагноз. Прокси спереди скрывает настоящий сервер, а хостинг может заменить или убрать заголовок. Он не говорит, работает PHP как mod_php или отдельным процессом, а именно от этого зависит, превратится ли рабочий .htaccess в 500.

PHP-файл-зонд

На остальное отвечает крошечный PHP-файл. Дайте ему имя, которое никто не угадает, и удалите после проверки:

vi ~/example.com/probe-7f3a.php

<?php echo "HTTPS=", var_export($_SERVER['HTTPS'] ?? null, true), " XFP=", var_export($_SERVER['HTTP_X_FORWARDED_PROTO'] ?? null, true), " SERVER_SOFTWARE=", $_SERVER['SERVER_SOFTWARE'] ?? '', " sapi=", PHP_SAPI, "\n";

curl -sS https://example.com/probe-7f3a.php

На FastCGI-хостинге (DreamHost) зонд отвечает:

HTTPS='on' XFP=NULL SERVER_SOFTWARE=Apache sapi=cgi-fcgi

rm ~/example.com/probe-7f3a.php

В этом ответе TLS заканчивается в Apache (HTTPS=on), заголовка прокси нет (XFP=NULL), а PHP не модуль Apache (sapi=cgi-fcgi). Следующий раздел объясняет три значения SAPI.

Что значит PHP_SAPI

ЗначениеКак работает PHPЧто это значит для .htaccess
apache2handler mod_php внутри Apache php_flag и php_value работают.
cgi-fcgi процесс CGI или FastCGI, часто mod_fcgid или обёртка вроде php85.cgi php_flag неизвестен: защитите его или перенесите настройку в .user.ini или файл хостинга.
fpm-fcgi PHP-FPM php_flag неизвестен: используйте .user.ini или настройки пула.
cli командная строка, а не веб-запрос .htaccess тут вообще нет: зонд из оболочки ничего не доказывает про веб-сервер.

Эти же значения решают, куда класть настройки PHP. mod_php читает php_flag из .htaccess; CGI, FastCGI и PHP-FPM читают .user.ini или ini файл хостинга. Точные файлы и команды перезапуска: Безопасные правила.

Модули Apache

На локальном Docker php:8.5-apache с mod_php спросите сам Apache, какие модули загружены:

apache2ctl -M | grep -i -E 'php|rewrite|alias|headers|version'

version_module (static) alias_module (shared) headers_module (shared) php_module (shared) rewrite_module (shared)

php_module (shared) - это mod_php. На хостинге с FastCGI строки php_module нет, хотя Apache остаётся Apache. alias_module нужен для Redirect и RedirectMatch, rewrite_module для RewriteRule, headers_module для Header, а version_module для IfVersion. Отсутствующий модуль - ровно то, для чего нужны защитные блоки из Безопасных правил. Общий хостинг обычно не даёт apache2ctl, поэтому там остаются файл-зонд и панель хостинга.

Какой процесс PHP работает

Когда Apache только фронтенд, у процесса PHP своё имя. На FastCGI-хостинге (DreamHost) это выглядит так:

pgrep -l -u user php

2745746 php85.cgi

ls /usr/sbin/apache2*

/usr/sbin/apache2 /usr/sbin/apache2ctl

php85.cgi - рабочий процесс FastCGI, значит PHP не внутри Apache. Хостинг с PHP-FPM показывает процесс php-fpm. Наличие apache2ctl подтверждает Apache, но не подтверждает mod_php.

Где журнал ошибок

Сломанное правило не молчит. Apache пишет имя файла и директиву в журнал ошибок:

tail -n 1 ~/logs/example.com/https/error.log

[Fri Nov 06 23:29:54 2026] [example.com] [alert] [client 203.0.113.7:37118] [pid 3064457] config.c(2045): /home/user/example.com/.htaccess: Invalid command 'php_flag', perhaps misspelled or defined by a module not included in the server configuration

На общем хостинге журнал обычно лежит в домашней папке, по папке на протокол; в Debian и Ubuntu это часто /var/log/apache2/error.log; панель управления показывает путь в просмотре журналов. Если ничего из этого нет, спросите хостинг. Строка config.c значит, что Apache остановился при чтении конфигурации, а путь после неё называет точный файл. Настоящий разбор такого 500: Разбор ошибок PHP.

Читается ли .htaccess вообще

nginx вообще не читает .htaccess, а Apache можно заставить его игнорировать через AllowOverride None. Проверяйте во временной подпапке, никогда на главной странице. Намеренно неверная строка ответит 500 только там:

mkdir -p ~/example.com/test-htaccess

vi ~/example.com/test-htaccess/.htaccess

ThisDirectiveDoesNotExist on

На локальном Apache 2.4.68 с mod_php тестовая папка /test-htaccess/ на http://localhost:8080 отвечает 500, а её родитель по-прежнему 200:

curl -sS -o /dev/null -w "%{http_code}\n" http://localhost:8080/test-htaccess/

500

curl -sS -o /dev/null -w "%{http_code}\n" http://localhost:8080/

200

500 в тестовой папке и 200 у её родителя значат, что сервер читает .htaccess здесь: причина только в неверной строке. 500 на обеих страницах указывает на конфигурацию сервера; 200 на обеих - .htaccess в этой папке игнорируется, и никакой редирект там не заработает. В любом случае удалите тестовую папку:

rm -rf ~/example.com/test-htaccess

Второй безопасный зонд - редирект: добавьте одно правило в тестовую папку и спросите его источник через curl -sI. Ответ 301 доказывает, что файл читается; 404 - что нет. Этот тест меняет ответ только одной папки.

Где заканчивается TLS

Зонд отвечает на это без догадок:

Полная история Apache за прокси, лишний шаг на http и два условия, которые останавливают цикл: Редиректы за HTTPS-прокси.

Автор статьи: Arthur Isaev