Some tips and tricks for your .htaccess file (Apache)
Switch branches/tags
Nothing to show
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Type Name Latest commit message Commit time
Failed to load latest commit information.



Some tips and tricks for your .htaccess file (Apache)

Table of Contents

CSP - Content Security Policy

Be inspired by the following lines:

<IfModule mod_headers.c>

   # Add CSP (Content Security Policy)
   Header set Protected-by "What-you-want-or-just-drop-this-line"

   # Replace XXXXXXXXXXXXXX by your site name like
   Header always set Feature-Policy "camera 'none'; fullscreen 'self'; microphone 'none'; payment 'none'; sync-xhr 'self' XXXXXXXXXXXXXX"

   # Blocks a request if the requested type is
   #    "style" and the MIME type is not "text/css", or
   #    "script" and the MIME type is not a JavaScript MIME type.
   Header set X-Content-Type-Options "nosniff"

   # Prevent from Clickjacking by allowing frame to be displayed only
   # on the same origin as the page itself.
   Header always set X-Frame-Options SAMEORIGIN

   # Force HTTPS (don't use this if you're still on http)
   # env=HTTPS didn't work... but while "expr=%{HTTPS} == 'on'" is well working
   # see
   Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" "expr=%{HTTPS} == 'on'"

   # Enables XSS filtering. Rather than sanitizing the page, the browser
   # will prevent rendering of the page if an attack is detected.
   Header always set X-XSS-Protection "1; mode=block"

   # The Referrer header will be omitted entirely. No referrer information is
   # sent along with requests.
   Header always set Referrer-Policy "no-referrer"

   # CSP : define / whitelist domains where files can be loaded
   # (f.i., ...)
   # This should be done for scripts, images, styles, frame, ...
   # Replace XXXXXXXXXXXXXX by your site name like
   # ----------------------------------------------------------------------
   # ----------------------------------------------------------------------
   #Header set Content-Security-Policy: "default-src 'self'; base-uri 'self'; form-action 'none'; script-src 'self' 'unsafe-eval' 'unsafe-inline'; font-src 'self' data:; style-src 'self' 'unsafe-inline'; img-src 'self' data:; frame-src XXXXXXXXXXXXXX; frame-ancestors 'none'"


Block access to some files based on their names

Refuse requests to these files:

<FilesMatch "(file_1\.gif|file_2\.png)">
    Order Allow,Deny
    Deny from all

Block access to some files based on their extensions

Blocks access to all files except those whose extension is mentioned in the list below:

Option 1

RewriteCond %{REQUEST_FILENAME} !(.*)\.(bmp|css|eot|html?|icon?|jpe?g|js|gif|pdf|png|svg|te?xt|ttf|webp|woff2?|xml|zip)$
RewriteRule . - [F]

Option 2

RewriteCond %{REQUEST_FILENAME} !\.(ico?n|img|gif|jpe?g|png|css|map)$ [NC]
RewriteCond %{REQUEST_FILENAME} !\.js(\?.*)?$ [NC]
RewriteCond %{REQUEST_FILENAME} !\.(eot|svg|ttf|woff2?)(\?.*)?$ [NC]
# Comment this line if you wish to make possible to access the /libraries folder by url.
RewriteRule . - [F]

Block access to hidden files & directories

Don't allow to access to a file or folder when the name start with a dot (i.e. a hidden file / folder):

<IfModule mod_rewrite.c>
    RewriteCond %{SCRIPT_FILENAME} -d [OR]
    RewriteCond %{SCRIPT_FILENAME} -f
    RewriteRule "(^|/)\." - [F]


Force download

Don't allow the browser to download such files but tell him how to display them (text in the example):

<FilesMatch "\.(tex|log|aux)$">
    Header set Content-Type text/plain
Prevent downloading

For instance, force download for pdf files:

<FilesMatch "\.(pdf)$">
    ForceType application/octet-stream
    Header set Content-Disposition attachment

Force https and www, compatible hstspreload

When implemented in your .htaccess, try to get access to or should redirect to

Also, test your site with to verify that your preloading is correct (green).

<IfModule mod_rewrite.c>

	# Rewrite the URL to force https and www.
	RewriteEngine On

	# Compliant with : first redirect to https if needed
	RewriteCond %{HTTPS} !=on
	RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

	#   then redirect to www. when the prefix wasn't mentionned
	# seems to not really like to make the two at once
	RewriteCond %{HTTP_HOST} !^www\.
	RewriteRule ^ https://www.%{HTTP_HOST}%{REQUEST_URI} [L,R=301]



Disable error reporting

Don't show errors (just like a error_reporting=E_NONE does)

<IfModule mod_php5.c>
    php_flag display_errors off
    php_flag log_errors on
    php_flag track_errors on
    php_value error_log error.log

Enable error reporting

Show errors (just like a error_reporting=E_ALL does).

Only use this on a development server otherwise you'll expose sensitive information to your visitor.

<IfModule mod_php5.c>
    php_flag display_errors on
    php_flag log_errors on
    php_flag track_errors on
    php_value error_log error.log

Enable a maintenance mode

Redirect every requests done to your site to a specific page (called maintenance.php here below). Just think to replace the code ADD_YOUR_IP_HERE by your current IP adress.

<IfModule mod_rewrite.c>
    RewriteEngine On
    RewriteCond %{REMOTE_ADDR} ! [NC]
    RewriteCond %{REMOTE_ADDR} !localhost [NC]
    RewriteCond %{REQUEST_FILENAME} !maintenance.php(.*)$ [NC]
    RewriteRule .* /maintenance.php [L,NC,QSA]


Compress files based on their type or extensions.

<IfModule mod_deflate.c>
    SetOutputFilter DEFLATE
    <IfModule mod_filter.c>
        AddOutputFilterByType DEFLATE application/font-otf application/font-ttf application/font-woff application/javascript application/json application/manifest+json application/rss+xml application/ application/xhtml+xml application/xml application/x-javascript image/svg+xml text/css text/csv text/html text/javascript text/plain text/xml

# On somes hosters, mod_deflate isn't installed but well mod_gzip.
<IfModule mod_gzip.c>
    mod_gzip_on Yes
    mod_gzip_dechunk Yes
    mod_gzip_item_include file      \.(html?|txt|css|js|php|pl)$
    mod_gzip_item_include handler   ^cgi-script$
    mod_gzip_item_include mime      ^text/.*
    mod_gzip_item_include mime      ^application/font-otf
    mod_gzip_item_include mime      ^application/font-ttf
    mod_gzip_item_include mime      ^application/font-woff
    mod_gzip_item_include mime      ^application/
    mod_gzip_item_include mime      ^application/x-javascript.*
    mod_gzip_item_exclude mime      ^image/.*
    mod_gzip_item_include mime      ^image/svg+xml*
    mod_gzip_item_exclude rspheader ^Content-Encoding:.*gzip.*

Add expiration (expires headers)

Enable ETAGs

<IfModule mod_headers.c>
    # Keep the connection alive (not really related to expirations but really increase download speed
    Header set Connection keep-alive

<IfModule mod_expires.c>

    ExpiresActive On

    # Default expiration: 1 hour after request
    ExpiresDefault "access plus 1 month"

    # CSS and JS expiration
    ExpiresByType text/css "access 1 month"
    ExpiresByType text/javascript "access 1 month"
    ExpiresByType application/javascript "access 1 month"
    ExpiresByType application/x-javascript "access 1 month"

    # webfonts
    ExpiresByType application/ "access plus 1 month"
    ExpiresByType application/x-font-woff "access 1 year"
    ExpiresByType application/x-font-woff2 "access 1 year"
    ExpiresByType font/eot "access plus 1 month"
    ExpiresByType font/truetype "access 1 year"
    ExpiresByType font/opentype "access 1 year"
    ExpiresByType font/woff "access 1 year"
    ExpiresByType image/svg+xml "access 1 year"
    ExpiresByType application/ "access 1 year"
    ExpiresByType application/font-otf "access 1 year"
    ExpiresByType application/font-ttf "access 1 year"
    ExpiresByType application/font-woff "access 1 year"
    ExpiresByType application/x-font-ttf "access 1 year"

    # Media
    AddType image/ .cur
    ExpiresByType application/ico "access 1 year"
    ExpiresByType audio/ogg "access plus 1 month"
    ExpiresByType image/bmp "access plus 1 month"
    ExpiresByType image/gif "access 1 month"
    ExpiresByType image/ico "access 1 year"
    ExpiresByType image/icon "access 1 year"
    ExpiresByType image/jpg "access 1 month"
    ExpiresByType image/jpeg "access 1 month"
    ExpiresByType image/png "access 1 month"
    ExpiresByType image/svg+xml "access 1 month"
    ExpiresByType image/ "access 1 year"
    ExpiresByType image/webp "access 1 month"
    ExpiresByType image/x-icon "access 1 year"
    ExpiresByType text/ico "access 1 year"
    ExpiresByType video/mp4 "access plus 1 month"
    ExpiresByType video/ogg "access plus 1 month"
    ExpiresByType video/webm "access plus 1 month"

    # Flash
    ExpiresByType application/x-shockwave-flash "access plus 2 months"
    ExpiresByType image/swf "access plus 2592000 seconds"

    # Files
    ExpiresByType application/pdf "access 1 week"
    ExpiresByType application/x-gzip "access 1 month"
    ExpiresByType text/x-component "access 1 month"

    # Data
    ExpiresByType application/atom+xml "access plus 1 hour"
    ExpiresByType application/rdf+xml "access plus 1 hour"
    ExpiresByType application/rss+xml "access plus 1 hour"
    ExpiresByType text/html "access plus 0 seconds"
    ExpiresByType application/json "access plus 0 seconds"
    ExpiresByType application/ld+json  "access plus 0 seconds"
    ExpiresByType application/schema+json "access plus 0 seconds"
    ExpiresByType application/vnd.geo+json "access plus 0 seconds"
    ExpiresByType application/xml "access plus 0 seconds"
    ExpiresByType text/xml "access plus 0 seconds"

# Perhaps the MIME type of SWF is incorrect, in this case, the FileMatch will do the job
<IfModule mod_headers.c>
    <FilesMatch "\.(swf)$">
        Header set Expires "access plus 2592000 seconds"


Deny All Access

## Apache 2.2
Deny from all

## Apache 2.4
# Require all denied

Deny All Access except you

Just replace by your IP adress.

## Apache 2.2
Order deny,allow
Deny from all
Allow from

## Apache 2.4
# Require all denied
# Require ip

Stops a browser from trying to MIME-sniff

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

Avoid Clickjacking and enable XSS-protection for browsers

<FilesMatch "\.(pl|php|cgi|spl)$">
    <IfModule mod_headers.c>
        # security
        Header set X-Frame-Options "DENY"
        Header set X-XSS-Protection "1; mode=block"

Disable script execution

Put these lines in f.i. /tmp/.htaccess to prevent execution of scripts in the /tmp folder.

# secure directory by disabling script execution
AddHandler cgi-script .php .pl .py .jsp .asp .sh .cgi
Options -ExecCGI

##Deny access to all CGI, Perl, PHP and Python
<FilesMatch "\.(asp?x|cgi|php|pl|py)$">
    Deny from all

Disallow listing for directories

Don't allow the webserver to provide the list of files / folders like a dir does.

<IfModule mod_autoindex.c>
    Options -Indexes


File password
AuthName "File access restriction"
AuthType Basic
AuthUserFile /home/your_account/.htpasswd

<Files "">
Require valid-user
Folder password

Place these lines in a file called .htaccess in the folder to protect (f.i. folder_name):

AuthType Basic
AuthName "This folder is protected"
AuthUserFile /home/your_account/folder_name/.htpasswd
Require valid-user

Whitelist - Disallow access to all files except the ones mentioned

# prevent accessing to all files excepted those mentioned (case sensitive!)

<FilesMatch "(?<!\.png|\.jpe?g|\.gif|\.svg|\.icon?)$">
# Apache 2.2
#    deny from all
# Apache 2.4
#    Require all denied


Redirect an entire site

Redirect 301 /

Permanent redirection

RedirectPermanent /old.php

Temporary redirection

Redirect 301 /old.php

Redirect a subfolder

For instance, redirect /category/apple.php to apple.php

RedirectMatch 301 ^/category/(.*)$ /$1

or solve spelling issue by f.i. redirect every requests to the fruit folder to the plural form.

RedirectMatch 301 ^/fruit/(.*)$ /fruits/$1

Search engine

Disallow indexing

Put these lines in f.i. yoursite/administrator to inform search engines that you don't allow him to index files in that folder (and sub-folders).

# Be sure that pages under this folder won't be indexed
<IfModule mod_headers.c>
    Header set X-Robots-Tag "noindex, nofollow"