Categories
WordPress

Almost perfect htaccess file for WordPress

A million years ago I wrote an article titled “Almost perfect htaccess file for WordPress” which while far from an accurate statement proved to be very popular. Many years, tens of thousands of views, and $0 earned I decided to resurrect the old article and update it for 2022.

While my hosting platform of choice WP Engine is phasing out htaccess file support (because they run Nginx), much of the WordPress hosting world (running Apache) still relies on this configuration file.

Before we add things to .htaccess we need to know what *should be* there on a default WordPress website.

Thanks to a very helpful and concise WordPress htaccess support article, this answer was easy.

# BEGIN WordPress

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]

# END WordPress

What should you add to your WordPress htaccess file?

I can’t answer that, but I can give you some ideas.

  1. Disable directory browsing for improved security. This ability (to browse directories from the public web) should already by disabled by your web host.
Options All -Indexes

2. Redirects – While I personally like using a plugin like Redirection for redirects to allow monitoring of usage, you can also create 301 redirects manually with htaccess.

Redirect 301 /oldpagename http://yourdomain.com/newpagename

3. Force SSL – For users visiting your site to access via https.

RewriteCond %{HTTPS} !=on
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

4. Block an IP address – If you need to block an IP address for abuse or lulz use the following rule. I prefer to block individual users/IPs with something like Cloudflare, or even a WordPress security plugin like Defender.

Deny from 123.123.123.123

5. Enable GZIP compression to improve the loading speed of your website assets. This is another rule that I don’t bother with, and instead utilize Cloudflare’s compression feature.

# BEGIN GZIP COMPRESSION
<IfModule mod_gzip.c>
mod_gzip_on Yes
mod_gzip_dechunk Yes
mod_gzip_item_include file \.(html?|txt|css|js|php|pl)$
mod_gzip_item_include handler ^cgi-script$
mod_gzip_item_include mime ^text/.*
mod_gzip_item_include mime ^application/x-javascript.*
mod_gzip_item_exclude mime ^image/.*
mod_gzip_item_exclude rspheader ^Content-Encoding:.*gzip.*
</IfModule>
# END GZIP COMPRESSION

6. Enable caching. Different from traditional WordPress page caching, asset caching instructs the user’s browser in how long to store each file (CSS/JS/JPG/GIF etc.)

## Enable Browser Caching ##
<IfModule mod_expires.c>
    FileETag MTime Size
    AddOutputFilterByType DEFLATE text/plain text/html text/xml text/css application/xml application/xhtml+xml application/rss+xml application/javascript application/x-javascript
    ExpiresActive On
    ExpiresByType text/html "access 500 seconds"
    ExpiresByType application/xhtml+xml "access 500 seconds"
    ExpiresByType text/css "access 1 month"
    ExpiresByType text/javascript "access 1 month"
    ExpiresByType text/x-javascript "access 1 month"
    ExpiresByType application/javascript "access 1 month"
    ExpiresByType application/x-javascript "access 1 month"
    ExpiresByType application/x-shockwave-flash "access 1 month"
    ExpiresByType application/pdf "access 1 month"
    ExpiresByType image/x-icon "access 1 year"
    ExpiresByType image/jpg "access 1 year"  
    ExpiresByType image/jpeg "access 1 year"
    ExpiresByType image/png "access 1 year"
    ExpiresByType image/gif "access 1 year"
    ExpiresDefault "access 1 month"
</IfModule>
## Enable Browser Caching ##

7. Increase the max upload size, memory limit and server timeouts. If your website host allows, you can increase the maximum size of uploads to the WordPress media library as well as the memory limit and timeout limits.

php_value upload_max_filesize 32M
php_value post_max_size 64M
php_value memory_limit 128M
php_value max_execution_time 300
php_value max_input_time 300

8. Protect wp-config.php A very important file, wp-config.php should and can be protected with this simple code.

# Protect the wp-config.php file
<files wp-config.php>
order allow,deny
deny from all
</files>

9. Disable access to XML-RPC for improved security. Unlesss you’re using an app or third party connection that requires this service, you should disable it:

# Block WordPress xmlrpc.php requests
<Files xmlrpc.php>
order deny,allow
deny from all
</Files>

Other WordPress htaccess options:

  • Password protect wp-admin
  • Stop Username Enumeration Attacks
  • Prevent Image Hotlinking
  • Force Files to Download
  • Protect Your Site Against Script Injections
  • Secure the wp-includes Directory

Tell me why I'm wrong...