
Every WordPress installation on Apache or LiteSpeed ships with a small, unglamorous file called .htaccess sitting in the site root. Most people only touch it when a plugin asks them to, or when something breaks and a forum post says “add this to your .htaccess.” That’s a reasonable way to survive, but it leaves you copying rules you don’t understand into a file that controls real security and performance behavior. Here’s what the file actually does, the recipes worth trusting, and the moment it becomes irrelevant.
What .htaccess Actually Controls
.htaccess is a per-directory configuration file read by the Apache web server (and by LiteSpeed, which supports it for Apache compatibility). It lets you override server behavior without editing the main server configuration, which matters on shared and managed hosting where you don’t have access to that main config at all.
On a WordPress site it typically handles:
- URL rewriting, most importantly the permalink structure (turning
?p=123into/2024/my-post/) - Redirects, like forcing HTTPS or collapsing www and non-www to one canonical domain
- Access control, blocking specific files, directories, or request patterns
- Response headers, such as security headers or browser caching hints
- Some server-level tweaks, like disabling directory listing
It does not control PHP execution speed, database performance, or object caching. Those live elsewhere: PHP 8.3 with OPcache handles code execution, and a Redis or Memcached drop-in handles persistent object caching. .htaccess is strictly about how the web server routes and responds to requests, not how WordPress itself performs internally.
The WordPress Core Block
If you open a stock .htaccess file, you’ll see something like this between two comment markers:
# BEGIN WordPress
<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 WordPressThis block is what makes pretty permalinks work: it tells the server to hand off any request that isn’t a real file or folder to index.php, where WordPress figures out what to actually serve. WordPress regenerates this block automatically when you change your permalink settings. If you’re comfortable at the command line, wp rewrite flush --hard via wp-cli rewrites this section cleanly, which is the safest way to fix a mangled permalink block instead of hand-editing it.
Add your own custom rules above or below this block, never inside it. WordPress will overwrite the block’s contents on the next flush, and anything you nested inside will vanish with it.
Safe Recipes Worth Keeping
Force a single canonical domain. Pick either www or non-www and redirect the other, so search engines and browsers never treat them as two separate sites:
RewriteCond %{HTTP_HOST} ^www\.example\.com$ [NC]
RewriteRule ^(.*)$ https://example.com/$1 [L,R=301]Force HTTPS at the origin. If Cloudflare sits in front of your site, its “Always Use HTTPS” setting is usually the cleaner place to enforce this, since Cloudflare terminates SSL at the edge. But if you need a belt-and-suspenders rule at the origin:
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]Set basic security headers. These cost nothing and reduce a few classes of attack surface:
<IfModule mod_headers.c>
Header always set X-Content-Type-Options "nosniff"
Header always set X-Frame-Options "SAMEORIGIN"
Header always set Referrer-Policy "strict-origin-when-cross-origin"
</IfModule>Block access to sensitive files. No visitor ever needs to load these directly:
<FilesMatch "^(wp-config\.php|\.htaccess|readme\.html|license\.txt)$">
Require all denied
</FilesMatch>Turn off directory listing. If a folder has no index file, you don’t want its contents browsable:
Options -IndexesDisable XML-RPC if you don’t use it. Many sites don’t need XML-RPC at all (it’s mostly used by the old WordPress mobile apps and some legacy integrations). If nothing on your site depends on it, blocking it removes a common target for brute-force login attempts:
<Files xmlrpc.php>
Require all denied
</Files>Check first, though. Some plugins (certain SEO pingback tools, some remote publishing setups) genuinely rely on it.
Where .htaccess Stops Being the Right Tool
Two situations matter here.
First, Nginx does not read .htaccess at all. If your stack runs on Nginx, every rule above has to live in the server block configuration instead, usually managed by your host. Rules copied from a WordPress forum into a .htaccess file on an Nginx server simply do nothing, and nothing will warn you about it. LiteSpeed is different: it reads .htaccess natively for Apache compatibility, which is one reason LiteSpeed-based hosting feels familiar if you’ve worked with Apache before.
Second, even on Apache or LiteSpeed, the server administrator has to allow .htaccess overrides in the main configuration (the AllowOverride directive) for any of this to take effect. On some locked-down shared hosts, overrides are restricted, and your rules will silently be ignored. If a rule doesn’t seem to work, that’s the first thing worth ruling out before you assume you wrote it wrong.
There’s also a performance argument for pushing certain rules further up the stack. Full-page caching is better handled by LiteSpeed Cache working with the server than by clever .htaccess rewrites. Bot mitigation, rate limiting, and firewall rules are better handled by a WAF at the edge, like Cloudflare’s, which can block a malicious request before it ever reaches your origin server, saving PHP execution time entirely. .htaccess only acts once a request has already arrived at your server: useful, but it’s the last line, not the first.
Testing Changes Without Breaking Your Site
Always keep a backup copy of your working .htaccess before editing. A single misplaced bracket in a rewrite rule can produce a full site outage (often a 500 error) with no obvious cause in the WordPress admin.
- Copy the current file somewhere safe before changing anything.
- Add one rule at a time and reload the site.
- If something breaks, restore the backup rather than debugging live.
- After permalink changes, let WordPress regenerate the core block via the Permalinks settings page or
wp rewrite flush, rather than hand-editing it.
Takeaway
.htaccess is a small file with real, specific power: routing, redirects, headers, and access control at the server level. Learn the handful of rules above, keep your own additions outside the WordPress core block, and remember that on Nginx it’s simply not read, and on any server it only works if overrides are allowed. For everything upstream of the origin, like caching and bot filtering, the edge and the server’s own caching layer will usually do a better job than a rewrite rule ever could.