
Аудит .htaccess: чому сайт віддає 500 і які правила не працюють
Перетягніть файл — інструмент знайде BOM, мертві директиви, правила з високим ризиком помилки 500 та ознаки стороннього втручання. Файл читається у вашому браузері й нікуди не надсилається.
Текст вставлено вручну, тому байтовий блок перевірок пропущено. Щоб побачити BOM, CRLF і невидимі символи — перетягніть сам файл.
Чистий .htaccess не лікує злам. Якщо сайт скомпрометовано, шкідливий код живе у PHP, а .htaccess — лише його наслідок: дропер перепише файл назад за хвилини після того, як ви його почистите. Порядок дій зворотний — спершу знайти виконуваний код, потім наводити лад у конфігу.
Тут з’явиться вихідний файл із номерами рядків.
Знаком ! позначені рядки зі знахідками: червоні — помилки, бурштинові — попередження. Невидимі та недруковані символи показані крапкою · — у самому файлі на їхньому місці порожньо.
Очищення прибирає BOM, переводить переноси на LF, вилучає недруковані символи, замінює нерозривні пробіли на звичайні й дописує перенос у кінці. Директиви не змінюються. Файл зберігається як htaccess-clean.txt — перейменуйте його на .htaccess перед завантаженням на сервер.
# BEGIN WordPress
# The directives (lines) between "BEGIN WordPress" and "END WordPress" are
# dynamically generated, and should only be modified via WordPress filters.
# Any changes to the directives between these markers will be overwritten.
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>
# END WordPress
Рівно це WordPress записує сам. Свої правила ставте вище рядка # BEGIN WordPress: усе між маркерами перезаписується щоразу, коли ви зберігаєте налаштування постійних посилань.
# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
RewriteBase /
RewriteRule ^index\.php$ - [L]
# add a trailing slash to /wp-admin
RewriteRule ^([_0-9a-zA-Z-]+/)?wp-admin$ $1wp-admin/ [R=301,L]
RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^ - [L]
RewriteRule ^([_0-9a-zA-Z-]+/)?(wp-(content|admin|includes).*) $2 [L]
RewriteRule ^([_0-9a-zA-Z-]+/)?(.*\.php)$ $2 [L]
RewriteRule . index.php [L]
</IfModule>
# END WordPress
Для multisite на піддоменах блок той самий, але без префікса ^([_0-9a-zA-Z-]+/)? у трьох останніх правилах: RewriteRule ^(wp-(content|admin|includes).*) $1 [L] і RewriteRule ^(.*\.php)$ $1 [L].
Заміна блоку не відновлює пермалінки сама по собі: після правки зайдіть у Налаштування → Постійні посилання і натисніть «Зберегти» — WordPress перевірить блок і за потреби перепише його.
Файл читається у вашому браузері — його вміст нікуди не надсилається і ніде не зберігається.
Чому саме файл, а не вставлений текст
Найчастіша причина помилки 500 після редагування .htaccess узагалі не видно в тексті. Це BOM — три невидимі байти на початку файлу, які додає Блокнот Windows при збереженні в UTF-8. Apache вважає їх частиною першої директиви і не може її розібрати. Тому інструмент приймає саме файл: тільки так можна прочитати байти й побачити BOM, переноси у стилі Windows та невидимі символи всередині рядків. Друга група проблем — директиви, які нічого не роблять, але виглядають робочими. mod_gzip_on — це синтаксис Apache 1.3, на сучасних серверах він мовчки ігнорується, а люди роками вважають, що стиснення ввімкнене. Блок ExpiresByType, загорнутий у перевірку mod_headers.c замість mod_expires.c, теж не спрацює — і без підказки цього не помітити. Третє — php_value і php_flag. Вони працюють тільки коли PHP підключений як модуль Apache. На сучасних хостингах з PHP-FPM такий рядок або ігнорується, або одразу дає 500. І окремо про безпеку: якщо у файлі знайдено правила, що редиректять відвідувачів залежно від того, з якого пошуковика вони прийшли, або приховують редирект від адміністратора — це типова ознака компрометації. Але чистий .htaccess не лікує злам: майже завжди десь у файлах живе PHP-скрипт, який перепише його назад.
