Skip to content

Use .htaccess files to configure Apache

A .htaccess file allows you to control the behavior of the Apache web server on a per-app and per-directory basis.

Create a .htaccess file in an app’s web root directory to apply the file’s directives to all requests for the app.

apps/APPNAME/public/.htaccess

The directives in a .htaccess file can be overridden by a .htaccess file in a subdirectory.

Long lines can be split into multiple lines by adding a backslash (\) to indicate the following line should be considered part of the same line.

Create and edit .htaccess files

You can create and edit .htaccess files either over SSH or with an SFTP client.

Learn how to edit files over SSH.

Show hidden .htaccess files

Files beginning with a dot (.) are often hidden in directory listings.

To show hidden files when using the ls command, add the -a (all files) flag.

Terminal window
ls -a apps/APPNAME/public/

RewriteRule and RewriteCond

Apache’s RewriteRule and RewriteCond directives are the most commonly used directives in .htaccess files. See the Apache mod_rewrite documentation for all available options.

RewriteRule directive

The RewriteRule directive does one of the following depending on the flags used:

  • Internally change the requested URL. This is the default behavior.
  • Redirect the client to a different URL.
  • Proxy a request to a different URL.

A RewriteRule directive can be used by itself or can be preceded by one or more RewriteCond directive to conditionally apply the rule.

The format of a RewriteRule directive is:

RewriteRule PATH_PATTERN SUBSTITUTION [FLAGS]

where the values of the placeholders above are:

PlaceholderValue
PATH_PATTERNA regular expression that is matched against the requested path.
SUBSTITUTIONThe URL that replaces the original requested path with either a new URL path or a new absolute URL.
FLAGSThe flags that control the behavior of the RewriteRule.

The SUBSTITUTION can include the following:

  • Regular expression back-references such as $1. Use %1 instead of $1 for back-references from a RewriteCond that immediately preceded the RewriteCond.
  • Server variables such as %{REQUEST_URI} and %{QUERY_STRING}.

Commonly used FLAGS for the RewriteRule directive include:

FlagPurpose
R,L or R=code,LRedirect the client to the substitution URL. If the status code is not specified, a 302 status code is used. Always use L with R.
NCMake the pattern comparison case-insensitive.
ENDStop rewriting processing entirely.
LStop rewriting process and hand the rewritten request back to the URL parsing engine, possibly applying more RewriteRule directives.
FReturn a 403 Forbidden response to the client. Use - as the substitution URL when using this flag.
PProxy the request to the substitution URL.
E=VAR:VALSet the value of an environment variable.
UnsafeAllow3FAllows substitutions that may be unsafe if the request URI has an encoded question mark, %3f, and the rewritten result has a ?.

See the full list of available flags.

RewriteCond directive

The RewriteCond directive is used to conditionally apply a RewriteRule.

The format of a RewriteCond directive is:

RewriteCond TEST_STRING COND_PATTERN [FLAGS]

where the values of the placeholders above are:

PlaceholderValue
TEST_STRINGThe string that the COND_PATTERN will be matched against.
COND_PATTERNThe pattern applied to TEST_STRING to determine if the RewriteCond evaluates to true.
FLAGSThe flags that control the behavior of the RewriteCond.

The TEST_STRING can include the following:

  • Server variables such as %{REQUEST_URI}, %{QUERY_STRING}, %{HTTP_HOST}, %{REMOTE_ADDR}.
  • HTTP headers specified as %{HTTP:header} such as %{HTTP:Authorization}.
  • Environment variables as %{ENV:variable} such as %{ENV:FOO}.

The COND_PATTERN can be any of the following:

  • A regular expression.
  • A string comparison if preceded by =.
  • A file attribute test:
    • -d to test if TEST_STRING is a directory.
    • -f to test if TEST_STRING is a regular file.

Any type of COND_PATTERN can be preceded by ! to negate the result of the condition.

The optional FLAGS for the RewriteCond directive can be one of the following:

FlagPurpose
NCMake the test case-insensitive.
ORCombine the RewriteCond with the next RewriteCond using a “logical or”. If not specified, the default is a “logical and”.

Redirect requests

Redirect requests for the domain old.example.com to the same path at the domain new.example.com using a 302 redirect.

RewriteCond %{HTTP_HOST} =old.example.com
RewriteRule (.*) https://new.example.com/$1 [R=302,L]

Redirect requests for any domain other than new.example.com to the same path at the domain new.example.com using a 302 redirect.

RewriteCond %{HTTP_HOST} !=new.example.com
RewriteRule (.*) https://new.example.com/$1 [R=302,L]

Forbid user agents

Reject requests for any path if the user agent matches either of three user agents.

RewriteCond %{HTTP_USER_AGENT} "=BadUserAgentOne/1.0" [OR]
RewriteCond %{HTTP_USER_AGENT} "=BadUserAgentTwo/1.0" [OR]
RewriteCond %{HTTP_USER_AGENT} "=AnotherBadUserAgent/2.2"
RewriteRule .* - [F]

Clean URLs

Send all requests to your app’s index.php file.

RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]

In your PHP code, you can then use the value of $_SERVER['REQUEST_URI'] to determine the requested path.

Set cache expiration

Browsers and CDNs cache responses according to a response’s cache control headers.

Use Apache’s ExpiresActive, ExpiresDefault, and ExpiresByType directives to add cache expiration headers. See the Apache mod_expires documentation for more options.

The following example sets a default cache expiration of 300 seconds and a longer expiration of 3600 seconds for CSS files.

ExpiresActive On
ExpiresDefault A300
ExpiresByType text/css A3600

Password protection

To require a valid username and password for all requests an app, add the following the .htaccess file in the app’s public/ directory. Replace SYSUSER and APPNAME with the name of the app’s system user and the app’s name.

AuthType Basic
AuthName "Authentication Required"
AuthUserFile /srv/users/SYSUSER/apps/APPNAME/public/.htpasswd
Require valid-user

To instead password protect one or more files, use the following. In addition to replacing SYSUSER and APPNAME, replace FILENAME with the name of the file to password protect, for example, sensitive-file.html Use a wildcard to match multiple files, for example, *.csv. See the Files directive documentation for more options.

<Files FILENAME>
AuthType Basic
AuthName "Authentication Required"
AuthUserFile /srv/users/SYSUSER/apps/APPNAME/public/.htpasswd
Require valid-user
</Files>

Next, SSH into the server as the app’s system user and run the following command. Replace APPNAME with the name of the app.

Terminal window
touch ~/apps/APPNAME/public/.htpasswd

Use the htpasswd-sp command to add or update credentials for a user. You’ll be prompted for the password to set for the user. Replace APPNAME with the name of the app and replace AUTH_USER with the name of the user to add.

Terminal window
htpasswd-sp ~/apps/APPNAME/public/.htpasswd AUTH_USER

Restrict IP addresses

Use the Require directive to enforce access control. See the Apache access control documentation for more details.

Allow addresses

Only allow requests from specific addresses, block all other requests.

<RequireAny>
Require ip 203.0.113.0
Require ip 203.0.113.1
</RequireAny>

Allow requests from a range of IP addresses specified as a CIDR block.

<RequireAny>
Require ip 203.0.113.0/24
</RequireAny>

Block addresses

Block requests from specific addresses, allow all other requests.

<RequireAny>
Require all granted
Require not ip 203.0.113.0
Require not ip 203.0.113.1
</RequireAny>

Block requests from a range of IP addresses specified as a CIDR block, allow all other requests.

<RequireAny>
Require all granted
Require not ip 203.0.113.0/24
</RequireAny>

Custom error pages

Use the ErrorDocument directive to change an app’s error pages.

Any of these formats work:

.htaccess
ErrorDocument 403 "Sorry, access to this page is forbidden."
ErrorDocument 500 http://example.com/server_error.html
ErrorDocument 503 /errors/service_unavailable.html

The format that uses an http or https URL will redirect the browser to the specified page.

.htaccess
ErrorDocument 403 "Sorry, access to this page is forbidden."
ErrorDocument 500 http://example.com/server_error.html
ErrorDocument 503 /errors/service_unavailable.html
.htaccess
ErrorDocument 403 "Sorry, access to this page is forbidden."
ErrorDocument 500 http://example.com/server_error.html
ErrorDocument 503 /errors/service_unavailable.html

Custom 404 for .php requests

The ErrorDocument directive will not handle 404 errors for requests where the file name ends in .php. For example, a request for /does-not-exist.php will not be handled by the ErrorDocument.

To show a custom 404 page using a file named 404.php, add the following to your app’s .htaccess file:

RewriteRule ^404\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /404.php [C]
RewriteRule . - [R=404,L]

Add response headers

Add response headers with the Header directive.

Header always set My-Header-Name "header value"

See the Apache mod_headers documentation for more options including conditionally adding headers to responses.

Set environment variables

Use the SetEnv directive to set environment variables that will be available within your PHP app’s code.

SetEnv NAME "value"

Enable directory listing

When directory listing is enabled, requests for directories that do not contain an index.php, index.html, or index.htm file will display a list of the files in the directory.

To enable directory listing for a specific directory, create a .htaccess file in the directory and add the following to the .htaccess file:

Options +Indexes

You can control how the directory listing appears with the IndexOptions directive. For example, the following will display the listing without file type icons and will also display file sizes and modification times.

Options +Indexes
IndexOptions FancyIndexing SuppressIcon

See the Apache IndexOptions documentation for more information on customizing directory listings.

Case-insensitive URLs

Use the CheckSpelling and CheckCaseOnly directives to enable serving files that were requested using a request path that does not match the case of the file name.

CheckSpelling on
CheckCaseOnly on

See the Apache mod_speling documentation for more options.

Replace strings in responses

Replace strings in responses using the AddOutputFilterByType and Substitute directives.

The following replaces all occurrences of the string old.example.com with the string new.sitename.com.

AddOutputFilterByType SUBSTITUTE text/html
Substitute s/old.example.com/new.sitename.com/ni

The options ni tell Apache to use a fixed string rather than a regular expression (n) and to do a case-insensitive search (i).

To perform more than one substitution, add more Substitute directives.

AddOutputFilterByType SUBSTITUTE text/html
Substitute s/sitename.example.com/sitename.com/ni
Substitute s/othersite.example.com/othersite.com/ni

More information is available in the Apache mod_substitute documentation.