Skip to main content
DevOps
Published 8 min read

What Is .htaccess? A Practical Guide for Apache Sites

A per-directory configuration file for Apache: what it can do, where it stops working, and how to avoid the usual mistakes.

An .htaccess file is a small text file that changes how the Apache web server behaves for one directory and everything inside it. It is popular on shared hosting because you can edit it yourself without access to the server's main configuration. It is also a common source of confusing failures, because one wrong character can take a whole site down.

What it is

The name stands for hypertext access. Apache looks for a file called .htaccess in the directory of each request, and in every parent directory up to the document root, and applies the directives it finds. Because the lookup happens on every request, changes take effect immediately with no restart. That convenience is also its main cost: the file is read and parsed repeatedly, which is slower than putting the same rules in the main server configuration.

What you can do with it

TaskTypical directiveNeeds module
Redirect one URL to anotherRedirect 301 /old /newmod_alias
Rewrite or redirect by patternRewriteRulemod_rewrite
Send HTTP response headersHeader setmod_headers
Set cache lifetimesExpiresByTypemod_expires
Compress responsesAddOutputFilterByType DEFLATEmod_deflate
Block or allow accessRequire all denied / Require ipmod_authz_core
Custom error pagesErrorDocument 404 /404.htmlcore
Turn off directory listingsOptions -Indexescore

Redirect HTTP to HTTPS

The most common rule on any site forces secure connections. This version uses mod_rewrite:

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

The condition runs the rule only when the request is not already secure, and R=301 makes the redirect permanent. If the site sits behind a CDN or load balancer that terminates TLS, Apache may see every request as plain HTTP and this rule will loop forever. In that case test the X-Forwarded-Proto header the proxy sets instead of %{HTTPS}.

Redirect www to the bare domain

RewriteEngine On
RewriteCond %{HTTP_HOST} ^www\.example\.com$ [NC]
RewriteRule ^ https://example.com%{REQUEST_URI} [L,R=301]

Pick one canonical hostname and redirect the other to it. Combining the HTTPS and www rules badly is a classic way to create a redirect chain, where a visitor is bounced through several hops; the guide on redirect chains explains how to collapse them into one.

Caching, compression and headers

<IfModule mod_expires.c>
  ExpiresActive On
  ExpiresByType image/png "access plus 1 year"
  ExpiresByType text/css "access plus 1 month"
</IfModule>

<IfModule mod_deflate.c>
  AddOutputFilterByType DEFLATE text/html text/css application/javascript application/json
</IfModule>

<IfModule mod_headers.c>
  Header always set X-Content-Type-Options "nosniff"
</IfModule>

Wrapping directives in IfModule blocks means a missing module skips the block instead of causing a 500 error. That is safer on unfamiliar hosting, though it can also hide the fact that a rule is not doing anything.

Access control

Apache 2.4 uses the Require family of directives:

# Block everyone from this directory
Require all denied

# Allow only one network
Require ip 203.0.113.0/24

# Stop Apache listing files when there is no index page
Options -Indexes

Older tutorials use Order, Allow and Deny, which belong to Apache 2.2 and work today only if the compatibility module is loaded. Mixing the two styles in one file is a frequent cause of unexpected behaviour.

When .htaccess does nothing

  • The server is not Apache. Nginx, and IIS in its default setup, do not read .htaccess. LiteSpeed does read it.
  • AllowOverride is set to None for the directory, or does not permit the directive group you used.
  • The module behind a directive is not enabled, so inside an IfModule block it is skipped silently.
  • The file is in the wrong directory, or is named .htaccess.txt by your editor or operating system.
  • A cache, CDN or browser is serving an old response. Test with a private window or a command-line request.

Common mistakes

  • Editing the live file without a copy. Keep a backup so you can restore it in seconds when a 500 appears.
  • Putting a rewrite rule above a more specific one so that the general rule always matches first.
  • Forgetting the [L] flag, so later rules keep running on a URL you meant to finish.
  • Using a 302 for a permanent move. R by itself sends a 302; add R=301 when the change is permanent.
  • Copying a block from a forum without understanding it. Rules that suit WordPress can break another application.

Treat .htaccess as configuration, not a casual edit

Test on a staging copy where you can. A syntax error does not just break the rule you changed; it can make every page on the site return an error until the file is fixed.

Checking a file before you upload it

Reading rules by eye is error-prone, especially once there are a dozen of them. The .htaccess Analyzer on DevCraftKit reads a pasted file in your browser and reports what each rule appears to do, flags syntax problems, and points out rewrite logic that can loop or chain. It analyses the text only. It cannot know which modules your server has loaded or what AllowOverride allows, so a clean result is a good sign, not a promise. After you deploy, confirm the real behaviour with the Redirect Chain Analyzer or curl.

Conclusion

The .htaccess file is a flexible way to control Apache without touching the server configuration, as long as you keep it small, test every change and remember that its behaviour depends on the server around it. For rewrite syntax in depth, read the companion article on Apache rewrite rules.

Frequently asked questions

Where does the .htaccess file go?
In the directory it should affect, most often the site's document root. Its rules apply to that directory and everything beneath it, unless a deeper .htaccess file overrides them.
Why is my .htaccess file being ignored?
Usually because the server's main configuration does not allow overrides for that directory. The AllowOverride setting decides which directives an .htaccess file may use, and None disables the file entirely. Some hosts also run servers other than Apache, such as Nginx, which never read .htaccess.
Why does a mistake in .htaccess give a 500 error?
Apache reads the file on every request. If it contains a syntax error, or a directive from a module that is not installed, Apache cannot process the request and answers with an internal server error. The error log names the offending line.
Does .htaccess work on Nginx?
No. Nginx does not support .htaccess files. Equivalent behaviour is written in the Nginx server configuration instead.

The tool that pairs with this guide.

Did this help you sort out your server configuration?

If these free developer tools save you time, consider buying me a byte. Your support helps keep DevCraftKit free and growing.

Buy me a byte 💾