WordPress .htaccess: what it does and how to fix common problems
8 min read · 05-Sept-2024
villagehosting.in team
5 September 2024
A corrupted or missing .htaccess is behind many mysterious WordPress issues — 404 errors on all inner pages, redirect loops, admin lockouts. Here is how to fix each one.
Always test .htaccess changes with a backup copy
A single syntax error in .htaccess makes your entire site return a 500 Internal Server Error. Before editing, download a copy via cPanel File Manager or FTP. If something breaks, re-upload the backup immediately. cPanel's File Manager also has a built-in text editor — use it rather than uploading from a Windows machine that might add Windows line endings.
What .htaccess does in WordPress
.htaccess is a configuration file for Apache web server. WordPress uses it primarily to:
- Enable pretty permalinks — without it, post URLs revert to
?p=123format - Redirect HTTP to HTTPS — send all plain HTTP requests to the secure version
- Protect sensitive files — block direct access to
wp-config.php,xmlrpc.php - Enable GZIP compression — compress responses before sending to the browser
- Set browser caching headers — tell browsers how long to cache static files
.htaccess lives at the root of your WordPress installation (/public_html/.htaccess in cPanel).
The default WordPress .htaccess
A fresh WordPress installation creates this:
# BEGIN WordPress
# The directives (lines) between "BEGIN WordPress" and "END WordPress" are
# dynamically generated, and should only be modified via WordPress filters.
<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
This tells Apache: "If a requested file or folder doesn't exist, pass the request to index.php". WordPress then reads the URL and loads the correct post or page. Without this, WordPress can't find anything except the homepage.
Fix: 404 on all pages except homepage
This is the most common .htaccess problem. Causes:
- Missing or corrupted .htaccess
mod_rewritenot enabled on the server- WordPress permalinks set to "Plain"
Fix 1: Regenerate .htaccess from WordPress admin
Settings → Permalinks → select any structure (e.g., "Post name") → click Save Changes.
WordPress regenerates .htaccess automatically. If it fails with a permissions error, it shows you the content to add manually.
Fix 2: Manually create .htaccess
In cPanel File Manager, navigate to public_html/, create a file named .htaccess (not .htaccess.txt), and paste the default WordPress content above.
Make sure the file has 644 permissions (readable by web server, writable only by owner).
Fix 3: Check if .htaccess file is hidden
In cPanel File Manager, click Settings (top right) → check "Show Hidden Files (dotfiles)". Files starting with . are hidden by default.
Fix: Redirect loop
You've added HTTPS redirect to .htaccess but the browser shows "ERR_TOO_MANY_REDIRECTS".
Cause 1: Cloudflare SSL mode is "Flexible" (Cloudflare sends HTTPS to your server, your server redirects to HTTPS, infinite loop).
Fix: Set Cloudflare SSL to "Full" or "Full (Strict)".
Cause 2: WordPress siteurl or home option is http:// while you're redirecting everything to https://.
Fix: In phpMyAdmin, update:
UPDATE wp_options SET option_value='https://yourdomain.in' WHERE option_name='siteurl';
UPDATE wp_options SET option_value='https://yourdomain.in' WHERE option_name='home';
Add HTTPS redirect to .htaccess
Add this before the # BEGIN WordPress block:
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
If behind a load balancer or Cloudflare, use the forwarded header instead:
RewriteEngine On
RewriteCond %{HTTP:X-Forwarded-Proto} !https
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
Enable GZIP compression
Add before # BEGIN WordPress:
<IfModule mod_deflate.c>
AddOutputFilterByType DEFLATE text/plain
AddOutputFilterByType DEFLATE text/html
AddOutputFilterByType DEFLATE text/css
AddOutputFilterByType DEFLATE application/javascript
AddOutputFilterByType DEFLATE application/json
AddOutputFilterByType DEFLATE image/svg+xml
AddOutputFilterByType DEFLATE application/xml
</IfModule>
Test GZIP is working: use webpagetest.org or GTmetrix — a "Use compression" warning means GZIP isn't active.
Enable browser caching
<IfModule mod_expires.c>
ExpiresActive On
ExpiresByType text/css "access plus 1 month"
ExpiresByType application/javascript "access plus 1 month"
ExpiresByType image/png "access plus 6 months"
ExpiresByType image/jpg "access plus 6 months"
ExpiresByType image/jpeg "access plus 6 months"
ExpiresByType image/webp "access plus 6 months"
ExpiresByType image/gif "access plus 6 months"
ExpiresByType image/svg+xml "access plus 1 year"
ExpiresByType application/pdf "access plus 1 month"
ExpiresByType font/woff2 "access plus 1 year"
</IfModule>
Protect sensitive WordPress files
Block direct access to files that should never be accessed via a browser:
# Block access to wp-config.php
<Files wp-config.php>
Require all denied
</Files>
# Block access to .htaccess itself
<Files .htaccess>
Require all denied
</Files>
# Block xmlrpc.php (common attack vector)
<Files xmlrpc.php>
Require all denied
</Files>
# Block PHP execution in uploads
<Directory /public_html/wp-content/uploads/>
<FilesMatch "\.php$">
Require all denied
</FilesMatch>
</Directory>
Protect wp-admin with IP whitelist
If your office has a static IP, block all other IPs from accessing wp-admin:
<Files wp-login.php>
Require ip 203.0.113.1 # Replace with your IP
Require ip 203.0.113.0/24 # Or allow a subnet
</Files>
Check your current IP: visit whatismyip.com from your office connection.
Fix: .htaccess file won't save / 500 error after editing
If editing .htaccess causes a 500 error, you have a syntax error. Apache is strict about .htaccess syntax.
Debug steps:
- In cPanel File Manager, rename
.htaccessto.htaccess.bak - Create a fresh
.htaccesswith only the WordPress default content - Test that the site works
- Add your additional directives back one section at a time
- Test after each addition — when the site breaks, that section has the error
Always back up .htaccess before editing. A broken .htaccess takes down the entire site.
.htaccess and WordPress Multisite
Subdirectory Multisite requires a different .htaccess (WordPress generates it):
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^ - [L]
RewriteRule ^(wp-(content|admin|includes).*) $1 [L]
RewriteRule ^(.*\.php)$ $1 [L]
RewriteRule . index.php [L]
When you enable Multisite, WordPress shows you the exact content to add during the setup wizard.