Using .htaccess files with Apache httpd 2.4

Updated November 2026

An .htaccess file is a small piece of Apache configuration that you put in a folder of your website. Its directives apply to that folder and everything below it, and changes work at once, without a reload. Apache reads them only where AllowOverride allows. If you can edit the main server configuration, put your rules there: it is faster and easier to keep track of.

What an .htaccess file is

A .htaccess file in /var/www/example.com/public/docs/ does exactly the same as this section in the server configuration:

<Directory "/var/www/example.com/public/docs">
    # ...the same directives...
</Directory>

The syntax is the same as in the main files. The difference is when the file is read. The main configuration is read once, at startup. A .htaccess file is read again on every request. That is why changes take effect immediately, and also why it costs time. You can change the file name with AccessFileName, but a non-standard name confuses anyone else who works on the site: they will not know where to look.

.htaccess exists for people who cannot touch the server configuration: customers on shared hosting, or applications such as WordPress that ship their own rules. If you run the server yourself, you rarely need one.

Switching .htaccess on: AllowOverride

The default is AllowOverride None. Apache then does not even look for .htaccess files. Debian, Ubuntu, RHEL and Fedora all keep that default for /var/www, so a fresh install ignores your file completely. To allow it, add AllowOverride to the <Directory> block for the site, in the vhost file:

<Directory /var/www/example.com/public>
    Options FollowSymLinks
    AllowOverride FileInfo AuthConfig Indexes
    Require all granted
</Directory>

Then sudo apachectl configtest and reload. AllowOverride works only in a plain <Directory> section, not in <Location>, <Files> or <DirectoryMatch>. Never put it on <Directory />: that makes Apache look for .htaccess files all the way up to the root of the disk.

What each AllowOverride value permits
ValueAllows, for example
Nonenothing; files are not read at all
AuthConfigAuthType, AuthName, AuthUserFile, Require
FileInfoErrorDocument, Redirect, RewriteRule, Header, AddType, SetHandler, SetEnvIf
IndexesDirectoryIndex, FallbackResource, IndexOptions, ExpiresByType
Limitthe old Order, Allow, Deny (2.2 syntax)
Options or Options=Indexes,MultiViewsOptions, optionally only the listed ones
Allevery directive allowed in .htaccess context

For finer control, AllowOverrideList names single directives. This allows redirects and nothing else:

AllowOverride None
AllowOverrideList Redirect RedirectMatch

A directive that is not allowed produces a 500 Internal Server Error, and the error log says “… not allowed here”. Sections such as <Files>, <FilesMatch> and <If> are allowed whenever overrides are on at all; the directives inside them still need their own class.

The cost in speed

With overrides on, Apache checks for a .htaccess file in every folder of the path, on every request, whether or not one exists. Suppose overrides are on from /var/www down, and a browser asks for /blog/2026/post.html in /var/www/example.com/public. Apache checks five folders: /var/www, example.com, public, blog and 2026. At 200 requests a second that makes 200 × 5 = 1,000 extra file lookups a second, even if no .htaccess file exists anywhere. Files it does find are read and parsed each time, and mod_rewrite rules in .htaccess are recompiled on every request instead of once. The operating system caches most of this, so a small site will not notice. A busy one will. Enable overrides only on the folders that need them.

When to use the main config

Common examples

Each example below works in a .htaccess file on httpd 2.4, provided the override class shown is allowed and the module is loaded. On Debian and Ubuntu, mod_headers, mod_expires and mod_rewrite are off by default (sudo a2enmod headers expires rewrite); RHEL and Fedora load them.

Custom error pages (FileInfo)

ErrorDocument 404 /errors/not-found.html
ErrorDocument 403 /errors/forbidden.html

Redirect a moved page (FileInfo)

Redirect permanent "/old-page.html" "https://www.example.com/new-page.html"

The target can be a full URL or a path starting with /. Anything after the matched path is added to the target: Redirect permanent "/docs" "/manual" also sends /docs/intro.html to /manual/intro.html. More patterns are in Redirects.

Turn off folder listings (Options)

Options -Indexes

With a + or - the option is added to or removed from the inherited set. Without a sign (Options Indexes) the line replaces the whole set and silently switches off everything else, including FollowSymLinks. Mixing signed and unsigned options in one line is a syntax error.

Send every unknown URL to one script (Indexes)

FallbackResource /index.php

Content management systems and frameworks use this pattern. One line of mod_dir replaces the usual block of rewrite rules: existing files are served as they are, and everything else goes to index.php.

Password-protect a folder (AuthConfig)

AuthType Basic
AuthName "Staff only"
AuthUserFile "/etc/apache2/passwords/example.com"
Require valid-user

Create the password file outside the web root with bcrypt hashing (htpasswd is in apache2-utils on Debian and httpd-tools on RHEL):

sudo mkdir -p /etc/apache2/passwords
sudo htpasswd -c -B /etc/apache2/passwords/example.com alice

On RHEL, use a folder such as /etc/httpd/passwords instead. Leave out -c when you add more users, or the file is overwritten. Basic authentication sends the password unencrypted, so use it only over HTTPS. Details are in Authentication.

Allow only some addresses (AuthConfig)

Require ip 192.0.2.0/24 2001:db8::/32

In old files you will see Order deny,allow with Deny from all and Allow from …. That is the 2.2 syntax. It needs AllowOverride Limit and mod_access_compat, and mixing it with Require gives confusing results. See Access control.

Block backup and config files (AuthConfig)

<FilesMatch "\.(bak|old|sql|ini|log|sh)$">
    Require all denied
</FilesMatch>

Both default configurations already refuse to serve files whose names start with .ht, so .htaccess and .htpasswd cannot be downloaded. Keep that rule.

Security header and browser caching (FileInfo, Indexes)

Header always set X-Content-Type-Options "nosniff"

ExpiresActive On
ExpiresByType image/webp "access plus 1 month"
ExpiresByType text/css "access plus 1 week"

The first line needs mod_headers, the others mod_expires. Caching and compression explains cache lifetimes, and Hardening checklist the other security headers.

Force HTTPS with mod_rewrite (FileInfo)

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

In .htaccess, mod_rewrite works only if FollowSymLinks or SymLinksIfOwnerMatch is enabled for the folder. Patterns in .htaccess match the path without the folder prefix and leading slash: in the document root, RewriteRule "^images/(.+)\.jpg$" …, not ^/images/…. If you control the server, a Redirect in the port-80 vhost does this job better. See mod_rewrite.

Which setting wins

Troubleshooting

Nothing happens
The file is probably not being read. Add a line with a made-up word such as TestMe and reload the page. No 500 error means AllowOverride None is in effect for that folder, or the file is in a different folder than you think, or it has the wrong name (htaccess.txt, .htaccess.txt).
500 Internal Server Error
Read the error log (/var/log/apache2/error.log or /var/log/httpd/error_log). “… .htaccess: Header not allowed here” means the override class is missing. “Invalid command 'Header', perhaps misspelled or defined by a module not included in the server configuration” means the module is not loaded. Other messages point to a syntax error in the line they name.
Rules work in .htaccess but not after moving them
Rewrite patterns must change: in the server configuration, they see the full path with the leading slash.

Hacked sites. Attackers who get write access often add .htaccess rules that redirect visitors or make uploaded files run as PHP. If you find unexpected rules, see Hacked site recovery. Do not allow overrides on upload folders.

Sources