The .htaccess file in the WordPress root directory is small, rarely edited, and critical — it controls URL routing, HTTPS redirects, security headers, caching rules, and access restrictions for Apache web servers. When it breaks, WordPress URLs stop working. When it is misconfigured, sites become vulnerable. When it is missing, clean URLs return 404 errors. Understanding the WordPress htaccess file — what it does, what the default content should be, and how to safely extend it — prevents the most common and disruptive web server configuration problems on WordPress sites. We go deeper on the whole subject in our Complete Guide to WordPress How.
WordPress Htaccess — The Default Content and What It Does
Every WordPress installation on an Apache server requires an .htaccess file in the root directory. The default WordPress htaccess content generated when permalinks are saved consists of a single block:
# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>
# END WordPress
These seven lines do one critical thing: they tell Apache to route all requests that do not match an existing file or directory through WordPress’s index.php front controller. This is what makes human-readable URLs work — without this block, /blog/my-post/ would return a 404 because Apache cannot find a physical file at that path. With the block, Apache passes the request to index.php, WordPress queries the database for the post with that slug, and returns the correct content. The WordPress htaccess is the bridge between the URL the visitor sees and the PHP execution that generates the page. WordPress regenerates this block automatically when Settings → Permalinks → Save Changes is clicked — never manually edit inside the # BEGIN WordPress and # END WordPress comments, as those changes are overwritten on the next permalink save.
If the .htaccess file is missing entirely, WordPress creates a new one when permalinks are saved. If the file exists but is not writable by the web server user, WordPress displays a warning in Settings → Permalinks and shows the .htaccess content that needs to be manually added. The file permissions for .htaccess should be 644 on most servers — writable by the owner, readable by the web server. Some security guides recommend 444 (read-only) to prevent modification, but this also prevents WordPress from automatically updating the WordPress htaccess when plugins register new rewrite rules. The practical tradeoff: 644 permissions for development and staging environments, 444 for production sites with stable permalink structures where no rewrite rule changes are expected. Our guide on fixing WordPress 404 errors covers the .htaccess repair that resolves URL resolution failures when the htaccess content is missing or incorrect.
Adding Security Rules to WordPress Htaccess
The WordPress htaccess file is the most effective place for server-level security rules that block malicious requests before WordPress PHP even executes — reducing server load from attacks and stopping threats that PHP-level security plugins cannot prevent because the request never reaches PHP.
Block direct access to sensitive WordPress files — add these rules above the # BEGIN WordPress comment:
# Block access to sensitive files
<FilesMatch "^(wp-config.php|xmlrpc.php|readme.html|license.txt)$">
Order Allow,Deny
Deny from all
</FilesMatch>
# Block access to hidden files (starting with .)
<FilesMatch "^.">
Order Allow,Deny
Deny from all
</FilesMatch>
# Disable directory browsing
Options -Indexes
These three rules prevent wp-config.php from being directly accessed (it contains database credentials), block xmlrpc.php from all requests (eliminating the XML-RPC brute force attack surface), prevent the readme.html from revealing the WordPress version to attackers, and disable directory listing that would expose file names in directories without an index file. The WordPress htaccess file processes these rules at the Apache level — requests blocked by these rules return 403 Forbidden and never reach PHP, consuming minimal server resources compared to WordPress-level blocking. Adding these rules after generating a fresh .htaccess is a recommended security hardening step for all new WordPress deployments. According to the OWASP security framework, blocking direct access to configuration files and disabling directory listing are foundational web server hardening measures that prevent the most common information disclosure vulnerabilities.
HTTPS Redirect and WWW Redirect Rules
The WordPress htaccess file handles HTTP-to-HTTPS redirects at the Apache level and www/non-www canonicalisation at the Apache level, which is faster and more reliable than equivalent redirect plugins or WordPress-level redirect logic. These rules should be placed above the # BEGIN WordPress comment.
Force HTTPS for the entire site:
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
</IfModule>
Force the non-www canonical (redirect www to non-www):
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{HTTP_HOST} ^www.(.+)$ [NC]
RewriteRule ^ https://%1%{REQUEST_URI} [R=301,L]
</IfModule>
Important for WordPress htaccess on Cloudflare: do not add HTTPS redirect to .htaccess — Cloudflare handles HTTPS enforcement at its edge and an origin-level redirect causes a redirect loop. On non-Cloudflare sites with Let’s Encrypt SSL, the .htaccess HTTPS redirect is the correct implementation. After adding redirect rules to the WordPress htaccess, test using an incognito browser window where no redirect is cached, and use a redirect checker tool (redirect-checker.org) to verify the redirect chain shows only a single 301 redirect rather than a redirect chain. A chain of two or more redirects (HTTP → HTTPS → www redirect, or vice versa) produces unnecessary latency — the rules should be combined so any non-canonical URL redirects to the canonical HTTPS non-www URL in a single 301.
Performance Rules — Browser Caching and Compression
The WordPress htaccess enables browser caching and compression and Gzip/Brotli compression directly, improving performance for all visitors without requiring separate caching plugin configuration. These rules are complementary to but independent from page caching plugins — they control how static assets (CSS, JavaScript, images, fonts) are delivered to browsers.
Enable Gzip compression for text-based assets:
<IfModule mod_deflate.c>
AddOutputFilterByType DEFLATE text/html text/plain text/css
AddOutputFilterByType DEFLATE application/javascript application/json
AddOutputFilterByType DEFLATE image/svg+xml application/xml
AddOutputFilterByType DEFLATE font/woff2 font/woff
</IfModule>
Set browser cache Expires headers for static assets:
<IfModule mod_expires.c>
ExpiresActive On
ExpiresByType image/jpeg "access plus 1 year"
ExpiresByType image/png "access plus 1 year"
ExpiresByType image/webp "access plus 1 year"
ExpiresByType text/css "access plus 1 month"
ExpiresByType application/javascript "access plus 1 month"
ExpiresByType font/woff2 "access plus 1 year"
</IfModule>
These WordPress htaccess performance rules reduce load times for returning visitors (browser-cached assets are not re-downloaded) and initial page load times (Gzip-compressed assets transfer faster). Caching plugins typically generate these WordPress htaccess rules automatically when their “Browser Caching” and “GZIP Compression” features are enabled — verify by checking .htaccess after enabling those features in the plugin. If the caching plugin already manages these rules, do not add them manually to avoid duplication. Our guide on the complete WordPress caching guide covers how .htaccess browser caching headers fit into the full caching strategy alongside page caching and CDN.
Troubleshooting WordPress Htaccess Issues
A corrupted or misconfigured WordPress htaccess causes different visible symptoms depending on which part of the file has the problem: missing WordPress block causes 404 on all pages; incorrect HTTPS redirect causes redirect loops; incorrect security blocks cause 403 errors on legitimate content; syntax errors cause 500 Internal Server errors for the entire site.
Diagnose a broken .htaccess quickly: rename .htaccess to .htaccess_backup → reload the site. If the site loads correctly (with plain URL permalinks not working), .htaccess was causing the problem. Test each section of the file by progressively re-adding its content and reloading. The section that re-introduces the error when added back is the problematic section. Fix that section and rename the file back. A fresh default .htaccess can always be generated by navigating to Settings → Permalinks → Save Changes in the WordPress admin — this overwrites the file with the correct default content, removing any corrupted rules while preserving the standard WordPress routing configuration.
Syntax errors in WordPress htaccess are immediately visible in the server error log (cPanel → Logs → Error Log) when they cause 500 errors. The error message quotes the problematic line number and the specific syntax error, making diagnosis precise. Common syntax issues: unclosed brackets in mod_rewrite conditions, incorrect whitespace in directive values, and adding rules inside the # BEGIN WordPress / # END WordPress comments rather than outside them. Always test .htaccess changes on a staging site before applying to production — a single character syntax error takes the entire site offline on Apache, while Nginx reads its configuration on reload rather than on every request, making Nginx configuration errors less immediately catastrophic but equally important to test first. Reviews from major web development publications confirm that the WordPress htaccess file’s security rules for blocking xmlrpc.php and wp-config.php access are among the most impactful single-file security improvements available for Apache-hosted WordPress sites.
The WordPress htaccess file location changes when WordPress is installed in a subdirectory rather than the site root. If WordPress is at https://yoursite.com/wordpress/ but the site’s public URL is https://yoursite.com/, there are two .htaccess files: one in the site root (for the public URL routing) and one in the /wordpress/ subdirectory (for WordPress’s internal URL handling). The site root .htaccess handles the URL-to-WordPress routing using RewriteBase /; the WordPress subdirectory .htaccess handles WordPress’s internal rewrites. WordPress’s own documentation covers this subdirectory installation scenario explicitly — the Setup → WordPress in a directory page provides the exact .htaccess content for each file. Keeping both files correctly configured is necessary when this installation structure is used, and any security or performance rules must be added to the appropriate .htaccess file based on which URLs they should affect.
Rate limiting via WordPress htaccess on Apache requires the mod_ratelimit or mod_evasive modules — not available on all shared hosting. When available, rate limiting the wp-login.php endpoint prevents brute force attacks directly in the web server before they reach PHP: <Location /wp-login.php> SetOutputFilter RATE_LIMIT SetEnv rate-limit 400 </Location> limits login page responses to 400 bytes/second, making brute force attacks extremely slow. More practically, mod_evasive provides IP-based rate limiting with automatic temporary blocks for IPs that exceed request thresholds — contact the hosting provider to confirm which Apache security modules are available before attempting to implement rate limiting rules in .htaccess. On hosts where mod_evasive is unavailable, Cloudflare WAF rate limiting rules provide equivalent protection at the CDN level, as described in the WordPress Cloudflare guide.
Version control for the WordPress htaccess file prevents accidental overwrites from becoming unrecoverable problems. Add .htaccess to the site’s Git repository alongside the theme and custom plugin files — commit the file after every intentional change with a descriptive commit message explaining what changed and why. With Git history, any accidental .htaccess modification (from a plugin that writes its own rules incorrectly, or an admin who edited the wrong server’s file) can be immediately reverted to the last known-good state with a single command. For sites without Git, maintaining a backup copy of the .htaccess file on the server as .htaccess.backup provides a quick reference for restoration when the main file is modified or corrupted, though a proper version control system is significantly more maintainable for sites that receive ongoing development and configuration changes.
Password-protecting directories via the WordPress htaccess file provides a simple but effective access control layer for staging environments, development instances, and admin-facing directories that should not be publicly accessible. A basic directory-level password protection: create a .htpasswd file (using the htpasswd command-line tool or an online generator) containing username:hashed-password pairs → create or edit the .htaccess in the directory to protect: AuthType Basic, AuthName "Restricted Area", AuthUserFile /path/to/.htpasswd, Require valid-user. Place the .htpasswd file outside the web root (above the public_html directory) so it cannot be directly accessed via HTTP. For WordPress staging sites, protecting the entire site root with HTTP Basic Auth prevents search engines and casual visitors from indexing or accessing the staging environment while development is ongoing, providing a simple access gate before the staging site is ready for client review.
The WordPress htaccess file on Nginx servers does not exist — Nginx does not read .htaccess files at all. Nginx’s equivalent configuration lives in server block files (typically at /etc/nginx/sites-available/yoursite) and requires root server access to edit. WordPress-specific Nginx configuration — the equivalent of the Apache try_files rewrite — uses: location / { try_files $uri $uri/ /index.php?$args; } in the server block. Security rules, rate limiting, and gzip compression are also configured in the Nginx server block rather than in .htaccess. On managed WordPress hosts that use Nginx (Kinsta, WP Engine, Cloudways), these configurations are pre-configured and not directly editable — contact support to request server-level configuration changes rather than attempting to create .htaccess files that are silently ignored on Nginx environments.
Custom error pages via the WordPress htaccess file provide branded error responses instead of the generic Apache error pages for 404, 403, and 500 errors. Add to .htaccess: ErrorDocument 404 /404.php, ErrorDocument 403 /403.php, ErrorDocument 500 /500.php. WordPress handles its own 404s through the 404.php template, so the Apache-level 404 redirect is only needed for files not handled by WordPress — direct file requests that do not match any WordPress route. For 500 errors (PHP crashes), WordPress cannot render its own error page because PHP has crashed; the Apache ErrorDocument serves a static HTML fallback page that tells visitors the site is temporarily unavailable without exposing raw Apache error output. You might also run into WordPress Robots Txt.






