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
| Task | Typical directive | Needs module |
|---|---|---|
| Redirect one URL to another | Redirect 301 /old /new | mod_alias |
| Rewrite or redirect by pattern | RewriteRule | mod_rewrite |
| Send HTTP response headers | Header set | mod_headers |
| Set cache lifetimes | ExpiresByType | mod_expires |
| Compress responses | AddOutputFilterByType DEFLATE | mod_deflate |
| Block or allow access | Require all denied / Require ip | mod_authz_core |
| Custom error pages | ErrorDocument 404 /404.html | core |
| Turn off directory listings | Options -Indexes | core |
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 -IndexesOlder 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.
Try it yourself
The tool that pairs with this guide.
.htaccess Analyzer
Analyze Apache .htaccess configuration, rewrite rules, redirects, security settings and common server issues.
Redirect Chain Analyzer
Analyze URL redirects, detect redirect chains and loops, and inspect HTTP status behavior.
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.
Related articles
Apache Rewrite Rules Explained: RewriteRule, RewriteCond and Flags
Understand how RewriteRule and RewriteCond fit together, what the flags do, and why per-directory rules behave differently.
Published
Cron Syntax Explained: A Complete Guide to Cron Expressions
What each cron field means, how ranges and steps are matched, and how to read an expression without guessing.
Published
Five-Field vs. Six-Field Cron Expressions
The number of fields does not identify a cron dialect. Here is what changes between schedulers and why you cannot just add or drop a field.
Published