What is .htaccess?

An introduction to the .htaccess file in Apache

No, I don’t have a typo in the heading, I really did mean to write .htaccess because that is the way it is written and that is what we are going to be talking about in this article.

It’s important that you know about the .htaccess file, what it does, why you should have one in your website and how you can change it.

What is .htaccess?

.htaccess stands for hypertext access and the name refers back to the original purpose of these files which was to restrict some people’s access to some files on a per-directory basis.

These days a .htaccess file does much more than that and developers are finding more and more ways to use these handy files.

Currently most web designers and website owners use a .htaccess file to control how a server responds to requests … usually requests from a browser. It can be used to keep your website secure, to hide certain files from the browser, allow certain people to see a website while keeping others out, and other things as well.

While .htaccess files can operate on several different types of server they were designed for use on Apache servers and I will be focusing on the Apache / .htaccess combination in this article.

So, if your website resides on a Windows server, and there are still some hosts that offer Windows hosting, this article is not going to be much use to you but you may still find it interesting.

How is a .htaccess file created?

Well, if you’re worried about how you would create a file like this then it’s time to take a deep sigh of relief because WordPress creates it’s own .htaccess file when you install it. Some of the plugins you might use in the site add their little bits to the file and you can always add more to it yourself.

If you have brain-fade and somehow manage to delete the .htaccess file then don’t panic, WordPress will re-create the file for you and the plugins will add their little bits again. However, anything that you added to the file will be gone and you will have to add them again.

Where is your .htaccess file?

Your .htaccess file is usually located in the root folder of your website. So to get to it you log into your server’s c-Panel and look for the link called ‘File Manager’ and click on that link.

how to find your file manager in c-Panel

When you click on that link a screen will open that looks like this … and you need to find the ‘public_html’ file

the root directory structure of a website on a server that uses c-Panel

Click on that link and another screen will open that will display some of the directories and files that make up your website. Don’t worry if the structure of your website doesn’t look exactly like this but if you can see folders called cgi-bin, wp-admin , wp-content, and wp-includes then you’re in the right spot.

The directory structure of a website in c-Panel

You may have noticed that the folders and individual files in this listing are in alphabetical order so where should an individual file with a dot at the beginning of the file name appear? Right at the beginn of the individual file listings but you probably won’t see anything in your listing.

The reason for that is that anything with a dot at the beginning of the file name is usually hidden from view so how can you see it? Click on the Settings link as shown in this image:

the settings tab to open the hidden files in c-panel

Once you click the Settings link an overlay panel will appear that looks like this:

the overlay panel that will open hidden c-panel files

All you need to do is put a tick in the ‘Show Hidden Files’ box and then click ‘Save’ and your .htacess file will appear.

Opening your .htaccess file

If you want to see what’s in your .htacess file there are a couple of simple steps you have to follow.

The first thing to do is to right-click on the file and this popup will open:

the popup that appears when you right-click on the htaccess file link in your WordPress directory

Each item listed there is a link and most of them are self-explanatory so if you want to see what is in your .htaccess file all you have to do is left click on ‘View’. That is one of the safest options in that popup because all it will do is show you everything in your the file but you won’t be able to make any changes to it.

What you see in your .htacess file will depend on what plugins you have in your WordPress site, what you want the search engines and browsers to know about your website and what else you may have added to your .htaccess file.

The file below is for a WordPress website that has just been created. Nothing has been added to the backend of this site and there’s nothing facing the public either.

# BEGIN WordPress
# The directives (lines) between "BEGIN WordPress" and "END WordPress" are
# dynamically generated, and should only be modified via WordPress filters.
# Any changes to the directives between these markers will be overwritten.
<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 WordPress

# php -- BEGIN cPanel-generated handler, do not edit
# Set the “ea-php73” package as the default “PHP” programming language.
<IfModule mime_module>
  AddHandler application/x-httpd-ea-php73 .php .php7 .phtml
</IfModule>
# php -- END cPanel-generated handler, do not edit

On the other hand, the .htaccess file shown below is from a somewhat larger site that has been around for a while and has gone through several changes of plugins that performed various roles.

The file itself has become rather untidy and older some plugins have left bits … and sometimes lots of bits … behind when they were removed.

<!-- wp:code -->
<pre class="wp-block-code"><code># BEGIN WpFastestCache
# Modified Time: 17-02-21 1:31:56
&lt;IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteCond %{HTTPS} =on
RewriteCond %{HTTP_HOST} ^xxxxxxx.xxxx
# Start WPFC Exclude
# End WPFC Exclude
# Start_WPFC_Exclude_Admin_Cookie
RewriteCond %{HTTP:Cookie} !wordpress_logged_in_&#91;^\=]+\=xxxxxxxx
# End_WPFC_Exclude_Admin_Cookie
RewriteCond %{HTTP_HOST} ^railwayvideos.club
RewriteCond %{HTTP_USER_AGENT} !(facebookexternalhit|WP_FASTEST_CACHE_CSS_VALIDATOR|Twitterbot|LinkedInBot|WhatsApp|Mediatoolkitbot)
RewriteCond %{HTTP_USER_AGENT} !(WP\sFastest\sCache\sPreload(\siPhone\sMobile)?\s*Bot)
RewriteCond %{REQUEST_METHOD} !POST
RewriteCond %{REQUEST_URI} !(\/){2}$
RewriteCond %{REQUEST_URI} \/$
RewriteCond %{QUERY_STRING} !.+
RewriteCond %{HTTP:Cookie} !comment_author_
RewriteCond %{HTTP:Cookie} !safirmobilswitcher=mobil
RewriteCond %{HTTP:Profile} !^&#91;a-z0-9\"]+ &#91;NC]
RewriteCond %{HTTP_USER_AGENT} !^.*(\bCrMo\b|CriOS|Android.*Chrome\/&#91;.0-9]*\s(Mobile)?|\bDolfin\b|Opera.*Mini|Opera.*Mobi|Android.*Opera|Mobile.*OPR\/&#91;0-9.]+|Coast\/&#91;0-9.]+|Skyfire|Mobile\sSafari\/&#91;.0-9]*\sEdge|IEMobile|MSIEMobile|fennec|firefox.*maemo|(Mobile|Tablet).*Firefox|Firefox.*Mobile|FxiOS|bolt|teashark|Blazer|Version.*Mobile.*Safari|Safari.*Mobile|MobileSafari|Tizen|UC.*Browser|UCWEB|baiduboxapp|baidubrowser|DiigoBrowser|Puffin|\bMercury\b|Obigo|NF-Browser|NokiaBrowser|OviBrowser|OneBrowser|TwonkyBeamBrowser|SEMC.*Browser|FlyFlow|Minimo|NetFront|Novarra-Vision|MQQBrowser|MicroMessenger|Android.*PaleMoon|Mobile.*PaleMoon|Android|blackberry|\bBB10\b|rim\stablet\sos|PalmOS|avantgo|blazer|elaine|hiptop|palm|plucker|xiino|Symbian|SymbOS|Series60|Series40|SYB-&#91;0-9]+|\bS60\b|Windows\sCE.*(PPC|Smartphone|Mobile|&#91;0-9]{3}x&#91;0-9]{3})|Window\sMobile|Windows\sPhone\s&#91;0-9.]+|WCE;|Windows\sPhone\s10.0|Windows\sPhone\s8.1|Windows\sPhone\s8.0|Windows\sPhone\sOS|XBLWP7|ZuneWP7|Windows\sNT\s6\.&#91;23]\;\sARM\;|\biPhone.*Mobile|\biPod|\biPad|Apple-iPhone7C2|MeeGo|Maemo|J2ME\/|\bMIDP\b|\bCLDC\b|webOS|hpwOS|\bBada\b|BREW).*$ &#91;NC]
RewriteCond %{DOCUMENT_ROOT}/wp-content/cache/all/$1/index.html -f &#91;or]
RewriteCond /home/xxxxxx/public_html/wp-content/cache/all/$1/index.html -f
RewriteRule ^(.*) "/wp-content/cache/all/$1/index.html" &#91;L]
&lt;/IfModule>
&lt;FilesMatch "index\.(html|htm)$">
AddDefaultCharset UTF-8
&lt;ifModule mod_headers.c>
FileETag None
Header unset ETag
Header set Cache-Control "max-age=0, no-cache, no-store, must-revalidate"
Header set Pragma "no-cache"
Header set Expires "Mon, 29 Oct 1923 20:30:00 GMT"
&lt;/ifModule>
&lt;/FilesMatch>
# END WpFastestCache


# BEGIN LBCWpFastestCache
&lt;FilesMatch "\.(webm|ogg|mp4|ico|pdf|flv|jpg|jpeg|png|gif|webp|js|css|swf|x-html|css|xml|js|woff|woff2|otf|ttf|svg|eot)(\.gz)?$">
&lt;IfModule mod_expires.c>
AddType application/font-woff2 .woff2
AddType application/x-font-opentype .otf
ExpiresActive On
ExpiresDefault A0
ExpiresByType video/webm A10368000
ExpiresByType video/ogg A10368000
ExpiresByType video/mp4 A10368000
ExpiresByType image/webp A10368000
ExpiresByType image/gif A10368000
ExpiresByType image/png A10368000
ExpiresByType image/jpg A10368000
ExpiresByType image/jpeg A10368000
ExpiresByType image/ico A10368000
ExpiresByType image/svg+xml A10368000
ExpiresByType text/css A10368000
ExpiresByType text/javascript A10368000
ExpiresByType application/javascript A10368000
ExpiresByType application/x-javascript A10368000
ExpiresByType application/font-woff2 A10368000
ExpiresByType application/x-font-opentype A10368000
ExpiresByType application/x-font-truetype A10368000
&lt;/IfModule>
&lt;IfModule mod_headers.c>
Header set Expires "max-age=A10368000, public"
Header unset ETag
Header set Connection keep-alive
FileETag None
&lt;/IfModule>
&lt;/FilesMatch>
# END LBCWpFastestCache

# BEGIN GD Security Headers
&lt;IfModule mod_headers.c>
	# add header: content-security-policy
	Header set Content-Security-Policy "default-src 'self' 'unsafe-inline' 'unsafe-eval' data: ; script-src 'self' 'unsafe-inline' 'unsafe-eval' data: www.google-analytics.com ssl.google-analytics.com stats.g.doubleclick.net ajax.googleapis.com maps.google.com maps.gstatic.com maps.googleapis.com www.googletagmanager.com; style-src 'self' 'unsafe-inline' data: fonts.googleapis.com maps.googleapis.com; img-src 'self' data: s.w.org ps.w.org ts.w.org www.google-analytics.com stats.g.doubleclick.net i.ytimg.com www.googletagmanager.com; connect-src 'self' www.google-analytics.com; font-src 'self' data: fonts.gstatic.com; frame-src 'self' data: www.youtube.com; child-src 'self' data: www.youtube.com; upgrade-insecure-requests; report-uri https://xxxxxx.xxx?gdsih-csp-report;"
	# add header: x-xss-protection
	Header set X-XSS-Protection "1; mode=block; report=https://xxxxxx.xxxx?gdsih-xxp-report;"
	# add header: x-content-type-options
	Header always set X-Content-Type-Options "nosniff"
	# add header: x-frame-options
	Header always set X-Frame-Options "SAMEORIGIN"
	# add header: strict-transport-security
	Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
	# add header: referrer-policy
	Header always set Referrer-Policy "strict-origin-when-cross-origin"
&lt;/IfModule>
# END GD Security Headers



# BEGIN WordPress
# The directives (lines) between "BEGIN WordPress" and "END WordPress" are
# dynamically generated, and should only be modified via WordPress filters.
# Any changes to the directives between these markers will be overwritten.
&lt;IfModule mod_rewrite.c>
RewriteEngine On
RewriteRule .* - &#91;E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
RewriteBase /
RewriteRule ^index\.php$ - &#91;L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php &#91;L]
&lt;/IfModule>

# BEGIN Protect XML-RPC
&lt;Files "xmlrpc.php">
Order Deny,Allow
Deny from all
&lt;/Files>
# END Protect XML-RPC


# END WordPress

# BEGIN HttpHeaders
# The directives (lines) between "BEGIN HttpHeaders" and "END HttpHeaders" are
# dynamically generated, and should only be modified via WordPress filters.
# Any changes to the directives between these markers will be overwritten.
# END HttpHeaders

# BEGIN HttpHeadersAuth
# The directives (lines) between "BEGIN HttpHeadersAuth" and "END HttpHeadersAuth" are
# dynamically generated, and should only be modified via WordPress filters.
# Any changes to the directives between these markers will be overwritten.
# END HttpHeadersAuth

# BEGIN HttpHeadersCompression
# The directives (lines) between "BEGIN HttpHeadersCompression" and "END HttpHeadersCompression" are
# dynamically generated, and should only be modified via WordPress filters.
# Any changes to the directives between these markers will be overwritten.
# END HttpHeadersCompression

# BEGIN HttpHeadersContentType
# The directives (lines) between "BEGIN HttpHeadersContentType" and "END HttpHeadersContentType" are
# dynamically generated, and should only be modified via WordPress filters.
# Any changes to the directives between these markers will be overwritten.
# END HttpHeadersContentType

# BEGIN HttpHeadersExpires
# The directives (lines) between "BEGIN HttpHeadersExpires" and "END HttpHeadersExpires" are
# dynamically generated, and should only be modified via WordPress filters.
# Any changes to the directives between these markers will be overwritten.
# END HttpHeadersExpires

# BEGIN HttpHeadersTiming
# The directives (lines) between "BEGIN HttpHeadersTiming" and "END HttpHeadersTiming" are
# dynamically generated, and should only be modified via WordPress filters.
# Any changes to the directives between these markers will be overwritten.
# END HttpHeadersTiming

# BEGIN HttpHeadersCookieSecurity
# The directives (lines) between "BEGIN HttpHeadersCookieSecurity" and "END HttpHeadersCookieSecurity" are
# dynamically generated, and should only be modified via WordPress filters.
# Any changes to the directives between these markers will be overwritten.
# END HttpHeadersCookieSecurity

# php -- BEGIN cPanel-generated handler, do not edit
# Set the “ea-php73” package as the default “PHP” programming language.
&lt;IfModule mime_module>
  AddHandler application/x-httpd-ea-php73 .php .php7 .phtml
&lt;/IfModule>
# php -- END cPanel-generated handler, do not edit</code></pre>
<!-- /wp:code -->

Editing your .htaccess file

Should you clean up a .htaccess file that looks like the one above? If you don’t know what you are doing then maybe you should leave it alone but if you do want to edit your .htaccess file, even just to clean out some of the rubbish that gets left behind when a plugin is deleted, then DON’T use the ‘Edit’ link in c-Panel. Sure it’s the quick and easy way to change things but it’s also the most dangerous way to change things.

One slip of the mouse and you may delete something without even noticing it … and if you don’t know what you deleted then how are you going to fix the problem.

The safe way to edit the .htaccess file is to use the ‘Download’ link to obtain a copy and file that somewhere safe.

Copy the file that you have downloaded and then open the copy in Notepad … .htaccess files are written in Apache Machine Language and you can edit that using Notepad.

Definitely do not try to make changes to the file using Wordpad or Word because both of those options will add hidden files that will totally disrupt your .htaccess file and produce results that will be nothing like what you wanted to achieve.

Once you have made the changes then you can upload the amended file via c-Panel or you can FTP it to your site. In both cases the amended file should overwrite the old file.

When the amended file is in place check your site to make sure you haven’t made any mistakes