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.
ls -a apps/APPNAME/public/
To show hidden files in the Cyberduck SFTP client:
- Open Cyberduck.
- Click View in the menu bar.
- Select Show hidden files.
To show hidden files in the Filezilla SFTP client:
- Open Filezilla.
- Click Server in the menu bar.
- Select Force showing hidden files.
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:
Placeholder | Value |
---|---|
PATH_PATTERN | A regular expression that is matched against the requested path. |
SUBSTITUTION | The URL that replaces the original requested path with either a new URL path or a new absolute URL. |
FLAGS | The 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 aRewriteCond
that immediately preceded theRewriteCond
. - Server variables such as
%{REQUEST_URI}
and%{QUERY_STRING}
.
Commonly used FLAGS
for the RewriteRule
directive include:
Flag | Purpose |
---|---|
R,L or R=code,L | Redirect the client to the substitution URL. If the status code is not specified, a 302 status code is used. Always use L with R . |
NC | Make the pattern comparison case-insensitive. |
END | Stop rewriting processing entirely. |
L | Stop rewriting process and hand the rewritten request back to the URL parsing engine, possibly applying more RewriteRule directives. |
F | Return a 403 Forbidden response to the client. Use - as the substitution URL when using this flag. |
P | Proxy the request to the substitution URL. |
E=VAR:VAL | Set the value of an environment variable. |
UnsafeAllow3F | Allows 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:
Placeholder | Value |
---|---|
TEST_STRING | The string that the COND_PATTERN will be matched against. |
COND_PATTERN | The pattern applied to TEST_STRING to determine if the RewriteCond evaluates to true. |
FLAGS | The 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 ifTEST_STRING
is a directory.-f
to test ifTEST_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:
Flag | Purpose |
---|---|
NC | Make the test case-insensitive. |
OR | Combine 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.comRewriteRule (.*) 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.comRewriteRule (.*) 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} !-fRewriteCond %{REQUEST_FILENAME} !-dRewriteRule . /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 OnExpiresDefault A300ExpiresByType 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 BasicAuthName "Authentication Required"AuthUserFile /srv/users/SYSUSER/apps/APPNAME/public/.htpasswdRequire 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.
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.
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.0Require 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 grantedRequire not ip 203.0.113.0Require 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 grantedRequire 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:
ErrorDocument 403 "Sorry, access to this page is forbidden."ErrorDocument 500 http://example.com/server_error.htmlErrorDocument 503 /errors/service_unavailable.html
The format that uses an http
or https
URL will redirect the browser
to the specified page.
ErrorDocument 403 "Sorry, access to this page is forbidden."ErrorDocument 500 http://example.com/server_error.htmlErrorDocument 503 /errors/service_unavailable.html
ErrorDocument 403 "Sorry, access to this page is forbidden."ErrorDocument 500 http://example.com/server_error.htmlErrorDocument 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} !-fRewriteCond %{REQUEST_FILENAME} !-dRewriteRule . /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 +IndexesIndexOptions 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 onCheckCaseOnly 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/htmlSubstitute 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/htmlSubstitute s/sitename.example.com/sitename.com/niSubstitute s/othersite.example.com/othersite.com/ni
More information is available in the Apache mod_substitute documentation.