WordPress .htaccess guide

The .htaccess file is a configuration file for the Apache web server. It can be used to accomplish many things for a WordPress website. For instance, by adding rules to the file you can block certain IP addresses, force your website to use HTTPS, enable caching, compress the contents of your website for increased speed and much more.

Where is it?

The file is located in your root folder or the public_html folder. To access it with cPanel go to File Manager and then open the public_html folder. You may need to click the settings button then check the Show Hidden Files (dotfiles) checkbox. Files that begin with a . are hidden by default.

It can also be accessed with FTP, located in the root of your public_html folder. If using FTP you will need to download the file, make the edits mentioned below and upload it back to the server, replacing the old .htaccess file.

If you have the Yoast SEO plugin you can access the file directly from your WordPress dashboard by going to SEO > Tools > File Editor. If it’s not in there you may need to contact your hosting provider for help.

Make a backup

Since it’s such a powerful file you should always back up .htaccess before making changes. Incorrect rule configurations within the file can easily make your website inaccessible or provide unexpected behavior. Download a copy of the file or copy its contents into a text editor for safe keeping before making any changes. This way it can be replaced if you make a mistake or want to revert back to the previous version.

Why not use a plugin for all this?

Most, if not all of the things you can do mentioned below can be done with plugins. The problem is that you will need a plugin for each one. It’s best to use as few plugins as possible to keep your site from slowing down. None of these rules are very difficult and you can get the same features of a plugin without the added load on your website.

Editing .htaccess

The file should have the following syntax for WordPress already. The # means that line is a comment and won’t be evaluated by the web server when looking over the file. The section between “BEGIN WordPress” and “END WordPress” are comments used for clarity.

When adding your own rules to .htaccess make sure not to put them between the those comments. Rules can go above or below the WordPress section, just not in it.

# 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]
# END WordPress

What can .htaccess do for your WordPress website?

Force https

You will need an SSL certificate installed on your website before forcing your site to use HTTPS. Once you have the certificate though, HTTPS redirection will make sure users are taken to the secure version of your WordPress website, not the unsecured HTTP version.

Add the following rule to your .htaccess file to force your website to use HTTPS.

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

Any HTTP request will be redirected to the HTTPS version of your website. This makes sure your users don’t end up on unsecured pages.

Redirect changed or moved URLs (301 Redirect)

A Permanent 301 Redirect will tell search engines that a URL has permanently changed. It can be used to redirect individual files or an entire domain.

This is useful if your old post has outdated content and creating a new post make more sense than updating the original one.

If a particular post has been indexed by Google and shared across the internet there may be many backlinks to it. By deleting the post without redirecting it, your visitors will get a 404 Not Found error. This provides a bad experience for visitors and negatively effects search engine optimization and search engine rankings. It’s like telling customers your business address has moved and not giving them the new address.

If you move a post or page to a new URL, use the rule below.

RewriteEngine On
Redirect 301 /oldpost /newpost

When a visitor tries to access the old post the browser will automatically redirect them to the new post.

To redirect an entire website to a new domain use the rule below.

RewriteEngine On
RewriteRule ^(.*)$ http://newdomain.com/ [R=301]

All URLs for a specific domain will be redirected to the home page of the new domain.

Redirecting URLS in a 1-to-1 manner to a new domain, such as http://olddomain.com/post1 to http://newdomain.com/post1 is done a little differently.

RewriteEngine On
Redirect 301 / http://newdomain.com/

Force downloads

Instead of allowing visitors to files within their browser you can force certain file types to be downloaded. When someone clicks on a link to a PDF it would download instead of displaying in the browser.  This can be useful if you have mp3 file and don’t want them to play in the broswer when clicked on but download instead.

AddType application/octet-stream .mpeg
AddType application/octet-stream .mp3
AddType application/octet-stream .mov 
AddType application/octet-stream .pdf
AddType application/octet-stream .docx
AddType application/octet-stream .xlsx
AddType application/octet-stream .csv

Specify the file extension at the end of AddType application/octet-stream for force that file type to download.

Block hotlinking

Hotlinking or inline linking is when an item like an image is displayed on a website from another website. The image displayed on one website is actually hosted on another website. This means that the website hosting the image is using server resources to display the image on the other website displaying it.

For a few images on low traffic sites this might not have much of an effect on the hosting website but if there are many images being displayed on high traffic websites it can be a big problem for the website originally hosting the images.

Using the rule below, hotlinking will be disabled, but search engines will still be able to display images from your website. The last line will display an alternate image in place of the hotlinked images (replace the URL with that of an image uploaded to your website), like this example from The Oatmeal.

RewriteEngine on
RewriteCond %{HTTP_REFERER} !^$
RewriteCond %{HTTP_REFERER} !^http(s)?://(www\.)?yourdomain.com [NC]
RewriteCond %{HTTP_REFERER} !^http(s)?://(www\.)?google.com [NC]
RewriteCond %{HTTP_REFERER} !^http(s)?://(www\.)?bing.com [NC]
RewriteCond %{HTTP_REFERER} !^http(s)?://(www\.)?yahoo.com [NC]
RewriteRule \.(jpg|jpeg|png|gif|svg)$ http://yourdomain.com/alternate-image.jpg [NC,R,L]

Limit wp-admin access to certain IP addresses

One way of securing your WordPress login area is to limit access to wp-admin by IP address. If you only login to your WordPress dashboard from certain locations and the IP address of those locations doesn’t change (check with your ISP to make sure this is the case) you can restrict logins to specific addresses. To determine your IP address use What’s my IP.

For this to work you need to create a new .htaccess file and place it in the wp-admin folder of your website. You can access this through File Manager in cPanel or with FTP.

Place the following text into the new .htaccess file, using your IP addresses in place of x.x.x.x, y.y.y.y and z.z.z.z. If you can delete lines 4 and 5 if you only access your admin area from one IP address.

# Block access to wp-admin.
order deny,allow
allow from x.x.x.x 
allow from y.y.y.y 
allow from z.z.z.z 
deny from all

Only the addresses listed above will be able to access the admin area of your website.  

Block specific IP addresses

There may be times when you want to block certain IP addresses from accessing our WordPress website all together. This could be spam commenters (for that you should actually be using reCAPTCHA) or malicious traffic.

You can set up your web server to log and email you a list of login attempts so you can see what IP addresses you need to block. Use the syntax below to block specific IPs from accessing your website.

order allow,deny
deny from x.x.x.x
deny from y.y.y.y
deny from z.z.z.z
allow from all

IP addresses can also be blocked using IP Blocker in cPanel. This will actually add them directly to your .htaccess file without you needing to do anything other than entering the address, if you prefer not to edit .htaccess.

cPanel IP BLocker
cPanel IP Blocker adds IP addresses directly to your .htaccess file.

Enable caching

Plenty of caching plugins for WordPress exist, but you can also enable caching on your website by adding the following rule to your .htaccess file. Plugins do allow more features but using .htaccess is a good way to avoid the extra bloat of adding another plugin to your site.

In the example below the specified resources are set to 1 month with any unspecified resources set to 2 days per the last line. These can be customized to fit your specific needs if you need to set more or less time for file types to be cached.

<IfModule mod_expires.c>
  ExpiresActive On
  ExpiresByType image/jpeg "access plus 1 month"
  ExpiresByType image/gif "access plus 1 month"
  ExpiresByType image/png "access plus 1 month"
  ExpiresByType image/webp "access plus 1 month"
  ExpiresByType image/svg+xml "access plus 1 month"
  ExpiresByType image/x-icon "access plus 1 month"
  ExpiresByType video/mp4 "access plus 1 month"
  ExpiresByType video/mpeg "access plus 1 month"
  ExpiresByType text/css "access plus 1 month"
  ExpiresByType text/javascript "access plus 1 month"
  ExpiresByType application/javascript "access plus 1 month"
  ExpiresByType application/pdf "access plus 1 month"
  ExpiresByType application/x-shockwave-flash "access plus 1 month"
  ExpiresDefault "access 2 days"

Disable caching

Caching can also be disabled on your WordPress website through .htaccess. Like if your site has constantly updated information that you don’t want that data stored in the cache.

There are two ways of disabling browser caching with .htaccess.

Option #1. This will still cache static the resources specified in the first line.

<FilesMatch "\.(css|flv|gif|htm|html|ico|jpe|jpeg|jpg|js|mp3|mp4|png|pdf|swf|txt)$">
	<IfModule mod_expires.c>
		ExpiresActive Off
	<IfModule mod_headers.c>
		FileETag None
		Header unset ETag
		Header unset Pragma
		Header unset Cache-Control
		Header unset Last-Modified
		Header set Pragma "no-cache"
		Header set Cache-Control "max-age=0, no-cache, no-store, must-revalidate"
		Header set Expires "Thu, 1 Jan 1970 00:00:00 GMT"

Option #2. This caches nothing, disabling all caching.  

<IfModule mod_headers.c>
	Header set Cache-Control "no-cache, no-store, must-revalidate"
	Header set Pragma "no-cache"
	Header set Expires 0

Enable gzip compression 

Compressing your website can really speed up load times for your visitors. Enabling gzip compression can reduce page file sizes by up to 70% offering a significant performance improvement.

Add the example below to enable gzip.

<IfModule mod_deflate.c>
  # Compress HTML, CSS, JavaScript, Text, XML and fonts
  AddOutputFilterByType DEFLATE application/javascript
  AddOutputFilterByType DEFLATE application/rss+xml
  AddOutputFilterByType DEFLATE application/vnd.ms-fontobject
  AddOutputFilterByType DEFLATE application/x-font
  AddOutputFilterByType DEFLATE application/x-font-opentype
  AddOutputFilterByType DEFLATE application/x-font-otf
  AddOutputFilterByType DEFLATE application/x-font-truetype
  AddOutputFilterByType DEFLATE application/x-font-ttf
  AddOutputFilterByType DEFLATE application/x-javascript
  AddOutputFilterByType DEFLATE application/xhtml+xml
  AddOutputFilterByType DEFLATE application/xml
  AddOutputFilterByType DEFLATE font/opentype
  AddOutputFilterByType DEFLATE font/otf
  AddOutputFilterByType DEFLATE font/ttf
  AddOutputFilterByType DEFLATE image/svg+xml
  AddOutputFilterByType DEFLATE image/x-icon
  AddOutputFilterByType DEFLATE text/css
  AddOutputFilterByType DEFLATE text/html
  AddOutputFilterByType DEFLATE text/javascript
  AddOutputFilterByType DEFLATE text/plain
  AddOutputFilterByType DEFLATE text/xml

  # Remove browser bugs (only needed for really old browsers)
  BrowserMatch ^Mozilla/4 gzip-only-text/html
  BrowserMatch ^Mozilla/4\.0[678] no-gzip
  BrowserMatch \bMSIE !no-gzip !gzip-only-text/html
  Header append Vary User-Agent

Check your .htaccess for syntax errors

Remember how I mentioned before about incorrect configurations within the file breaking your site? Before uploading a new .htaccess file or making changes to your live version, it should be checked for accuracy. .htaccess check will check your file for syntax errors to prevent your website from going down due to file misconfigurations.

Replace your old file

Now that you have made the necessary changes and checked the file for accuracy it’s time to replace the old .htaccess with a new one. If you made edits directly to the file within the cPanel File Manager or with Yoast you are all done.

If using FTP you will need to upload the new file to your server, replacing the old one. 

That’s all there is to editing the .htaccess file in WordPress. It’s a pretty amazing file that can control many aspects of your WordPress website and allows for all kinds of custom situations and configurations.

Deprecated: Directive 'allow_url_include' is deprecated in Unknown on line 0