Common causes
- A directive from a module that is not loaded (Header needs mod_headers, Expires needs mod_expires)
- php_value or php_flag used when PHP runs as PHP-FPM or CGI, not mod_php
- Unclosed <IfModule> or <Files> blocks
- Bad RewriteRule flags, such as spaces inside [L, R=301]
- A directive that is not allowed in .htaccess under the current AllowOverride setting
- Smart quotes or Windows encoding introduced by a word processor
How to fix it
- Restore the site first. Rename .htaccess to .htaccess.broken or re-upload your last working copy. The site should load again, which confirms the edit caused the 500.
- Read the exact error. Check the Apache error log or cPanel > Errors. It names the file, and usually the directive that failed, such as Invalid command 'Header'.
- Remove php_value lines on PHP-FPM. If the log says php_value or php_flag is invalid, PHP is not running as an Apache module. Move those settings into .user.ini or the host's PHP settings.
- Wrap module directives in IfModule. Put Header lines inside <IfModule mod_headers.c> and Expires lines inside <IfModule mod_expires.c>, or enable the module with a2enmod headers expires.
- Fix flag and block syntax. Write flags with no spaces, for example [L,R=301,NC]. Make sure each <IfModule> has a matching </IfModule>.
- Re-add changes one at a time. Add the new lines back in small groups and reload after each. When the 500 returns, the last group contains the bad line.
Safe pattern: module directives guarded by IfModule
<IfModule mod_headers.c>
Header always set X-Content-Type-Options "nosniff"
</IfModule>
<IfModule mod_expires.c>
ExpiresActive On
ExpiresByType image/webp "access plus 1 month"
</IfModule> How to stop it happening again
- Keep a backup copy before every .htaccess edit
- Edit with a plain text editor, never a word processor
- Validate the file before uploading
- Use .user.ini for PHP settings on PHP-FPM hosts