WordPress .htaccess Rules Guide

The .htaccess file is one of the most powerful configuration files on an Apache web server. For WordPress sites, it handles URL rewrites, security restrictions, performance optimizations, and access control. A well-tuned .htaccess can significantly improve both security and page load speed with no plugin required.

Always back up your .htaccess before making changes. A syntax error can make your entire site return a 500 Internal Server Error. Keep a copy of the working file so you can restore it quickly.

1. Standard WordPress .htaccess (Default)

WordPress generates this basic .htaccess automatically. Never remove it — it's required for pretty permalinks:

# 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

Add all custom rules outside the # BEGIN WordPress / # END WordPress block so updates don't overwrite them.

2. Force HTTPS (HTTP → HTTPS Redirect)

<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
</IfModule>

3. Protect Sensitive Files

Protect wp-config.php

<Files wp-config.php>
  Order Allow,Deny
  Deny from all
</Files>

Protect .htaccess Itself

<Files .htaccess>
  Order Allow,Deny
  Deny from all
</Files>

Block XML-RPC

<Files xmlrpc.php>
  Order Allow,Deny
  Deny from all
</Files>

Disable Directory Browsing

Options -Indexes

4. Add Security Headers

<IfModule mod_headers.c>
  Header always set X-Frame-Options "SAMEORIGIN"
  Header always set X-Content-Type-Options "nosniff"
  Header always set X-XSS-Protection "1; mode=block"
  Header always set Referrer-Policy "strict-origin-when-cross-origin"
  Header always set Permissions-Policy "geolocation=(), microphone=(), camera=()"
</IfModule>

5. Hotlink Protection

Prevent other sites from embedding your images directly (stealing bandwidth):

<IfModule mod_rewrite.c>
RewriteEngine on
RewriteCond %{HTTP_REFERER} !^$
RewriteCond %{HTTP_REFERER} !^https://(www\.)?yourdomain\.com/ [NC]
RewriteRule \.(jpg|jpeg|png|gif|webp|svg)$ - [F,NC]
</IfModule>

Replace yourdomain.com with your actual domain.

6. Enable GZIP Compression

GZIP typically reduces HTML, CSS, and JS file sizes by 60–80%, significantly improving page load times:

<IfModule mod_deflate.c>
  AddOutputFilterByType DEFLATE text/html text/plain text/xml
  AddOutputFilterByType DEFLATE text/css text/javascript
  AddOutputFilterByType DEFLATE application/javascript application/x-javascript
  AddOutputFilterByType DEFLATE application/json application/xml
  AddOutputFilterByType DEFLATE image/svg+xml
</IfModule>

7. Browser Caching (Cache-Control Headers)

Tell browsers how long to cache static assets, reducing repeat load times:

<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 image/gif "access plus 1 year"
  ExpiresByType image/svg+xml "access plus 1 year"
  ExpiresByType text/css "access plus 1 month"
  ExpiresByType application/javascript "access plus 1 month"
  ExpiresByType application/x-javascript "access plus 1 month"
  ExpiresByType text/html "access plus 1 day"
</IfModule>

8. Block Common Bad Bots

<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{HTTP_USER_AGENT} (AhrefsBot|SemrushBot|DotBot|MJ12bot) [NC]
RewriteRule .* - [F,L]
</IfModule>

Note: Blocking SEO crawlers like Ahrefs and Semrush prevents them from including your site in their index databases, which can reduce the number of inbound link analyses. Only block them if server load is a concern.

8.5. Protect wp-login.php from Brute Force

The WordPress login page is a constant target for brute-force attacks. Restricting it by IP address is the most effective server-level protection:

# Allow only specific IPs to access wp-login.php
<Files wp-login.php>
  Order Deny,Allow
  Deny from all
  Allow from YOUR.IP.HERE
</Files>

Replace YOUR.IP.HERE with your actual IP address. If you have a dynamic IP (changes with each connection), use a plugin such as Limit Login Attempts Reloaded instead, or change the login URL with WPS Hide Login to make it unreachable by bots in the first place.

8.6. Block Malicious Bots and Vulnerability Scanners

Automated bots that probe for vulnerabilities consume server resources and inflate your traffic logs. Block them by User-Agent string:

<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{HTTP_USER_AGENT} (masscan|nikto|sqlmap|havij|netsparker|ZmEu) [NC]
RewriteRule .* - [F,L]
</IfModule>

To block a specific IP range that is actively attacking your site:

<RequireAll>
  Require all granted
  Require not ip 185.220.101.0/24
</RequireAll>

Note: Blocking popular SEO crawlers (Ahrefs, Semrush) prevents them from indexing your backlink profile in their databases. Only block bots that are causing real performance problems — check your access logs first.

8.7. Disable PHP Execution in Upload Directories

A common attack vector involves uploading a PHP file disguised as an image, then executing it through the browser. Prevent this by disabling PHP execution inside the WordPress uploads folder:

# Place this in a new .htaccess inside wp-content/uploads/
<FilesMatch "\.php$">
  Order Allow,Deny
  Deny from all
</FilesMatch>

Create a separate .htaccess file with this rule and place it inside your wp-content/uploads/ directory. Even if a PHP file is uploaded, it cannot be executed — it will return a 403 Forbidden error instead.

Strongly recommended: This single rule eliminates an entire category of WordPress shell upload attacks. It takes less than 30 seconds to implement and requires no plugin.

9. Custom Error Pages

ErrorDocument 404 /404.html
ErrorDocument 403 /403.html
ErrorDocument 500 /500.html

10. How to Test That Your .htaccess Rules Are Working

After adding any new rule, test it immediately rather than waiting to notice a problem. Here is how to verify each common rule type:

Test HTTPS redirect

Type http:// (without the "s") before your domain in the browser address bar. The URL should immediately change to https://. Alternatively, run curl -I http://yourdomain.com — a 301 status code confirms the redirect is working.

Test directory browsing protection

Navigate to a folder on your site that has no index file, for example https://yourdomain.com/wp-content/. With Options -Indexes in effect, you should see a 403 Forbidden error instead of a file listing.

Test security headers

Visit securityheaders.com, enter your domain, and click Scan. The report shows which headers are present and gives an overall grade. A well-configured WordPress site with the rules in this guide should receive grade A or A+.

Test GZIP compression

Run your site through GTmetrix or Google PageSpeed Insights. If GZIP is active, you will not see a "Enable text compression" recommendation in the results.

11. Common .htaccess Mistakes and How to Fix Them

Immediate 500 error after saving

A syntax error causes Apache to reject the entire file. Restore your backup immediately, then review the new rule line by line. Common causes: missing closing </IfModule>, incorrect spacing, or an unrecognized directive.

Redirect loop (ERR_TOO_MANY_REDIRECTS)

This happens when a rewrite rule redirects to itself. For the HTTPS rule, always include RewriteCond %{HTTPS} off so the redirect only fires for HTTP requests, not for HTTPS requests that have already been redirected.

WordPress permalinks stop working

If a custom rule interferes with WordPress routing, go to WordPress Admin → Settings → Permalinks and click Save. WordPress will regenerate the # BEGIN WordPress block with the correct rewrite rules.

Security headers not appearing

Apache must have mod_headers enabled for Header always set directives to work. Most managed hosting providers have it enabled by default. If headers are missing after adding the rules, contact your hosting provider to confirm the module is active.

WordPress Hosting with Apache & DirectAdmin

AsiaGB Hosting runs on Apache with full .htaccess support. Manage your site through DirectAdmin — no command line required. Starting at 500 THB/year.

View Hosting Plans →