htaccess is a special file that only works on Apache servers. WordPress also uses the .htaccess file to rewrite links when configuring Permalink. This article will provide you with code samples that can be used in .htaccess files for many different purposes for your WordPress website such as redirecting paths, security, blocking IPs, anti-comment spam…
Table of Contents
- 1 What is a htaccess file?
- 2 Where is .htaccess file?
- 3 .htaccess file location
- 4 Why You Can’t Find .htaccess File?
- 5 Common uses for .htaccess files
- 6 WordPress .htaccess
- 7 Advanced Mod_Rewrites
- 7.1 Directory Protection
- 7.2 Password Protect wp-login.php
- 7.3 Password Protect wp-admin
- 7.4 Protect wp-content
- 7.5 Protect wp-includes
- 7.6 Common Exploits
- 7.7 Stop Hotlinking
- 7.8 Safe Request Methods
- 7.9 Forbid Proxies
- 7.10 Real wp-comments-post.php
- 7.11 HTTP PROTOCOL
- 7.12 SPECIFY CHARACTERS
- 7.13 BAD Content-Length
- 7.14 BAD Content-Type
- 7.15 Missing HTTP_HOST
- 7.16 Bogus Graphics Exploit
- 7.17 No UserAgent, Not POST
- 7.18 No Referer, No Comment
- 7.19 Trackback Spam
- 7.20 Map all URIs except those corresponding to existing files to a handler
- 7.21 Map any request to a handler
- 7.22 And for CGI scripts:
- 7.23 Map URIs corresponding to existing files to a handler instead
- 7.24 Deny access if var=val contains the string foo.
- 7.25 Removing the Query String
- 7.26 Adding to the Query String
- 7.27 Rewriting For Certain Query Strings
- 7.28 Modifying the Query String
- 7.29 Forcing Non-WWW with HTTPS Site Addresses
- 7.30 Forcing WWW with HTTPS Site Addresses with .htaccess
- 7.31 Creating a Custom 404 Error Page with .htaccess
- 7.32 Denying and Allowing Access
- 7.33 Prevent Image Hotlinking
- 7.34 Redirect a Single Page
- 7.35 Alias a Single Directory
- 7.36 Redirect an Entire Site
- 7.37 Deny Access to Hidden Files and Directories
- 7.38 Deny Access to Backup and Source Files
- 7.39 Disable Directory Browsing
- 7.40 Performance
- 7.41 Set Expires Headers
- 7.42 Set PHP Variables
What is a htaccess file?
htaccess files, also known as “distributed config files”, allow you to make configuration changes per directory. One or more configuration directives are placed in a specific document directory. The directives will apply to all subdirectories and that particular directory.
Apache uses .htaccess to handle configuration changes per directory.
The Apache Access Configuration file extension HTACCESS is a file with the HTACCESS extension. It stands for “hypertext access” These files are used to invoke an exception from the global settings which apply to all directories in an Apache website.
The global settings will be overridden if the file is placed in one directory. You can create HTACCESS files to redirect a URL, prevent directory listing, ban specific IP addresses, prevent hotlinking, etc.
This file can also be used to point to an htpasswd directory that stores credentials that prevent visitors from accessing the particular directory.
The .htaccess (hypertext access) file is a file located in the root directory of the hosting and managed and authorized by Apache. The .htaccess file can control and configure many things with a variety of parameters, it can change the default set values of Apache.
If exploited well, .htaccess will help you a lot with very little effort, just a few lines of command. The way you use the .htaccess file is also very simple, just open it with an editor, edit it, and save it as a .htaccess file.
Where is .htaccess file?
Your WordPress root directory contains the WordPress .htaccess file. The root directory could be labeled with a number of different names depending on the hosting provider. It can be found using File Manager within your hosting account’s control panel.
To create a .htaccess file in WordPress, you can use a text editor or a WordPress plugin.
Using a text editor
- Connect to your website using an FTP client, such as FileZilla.
- Navigate to the root directory of your WordPress installation.
- Create a new file called .htaccess.
- Open the .htaccess file in a text editor.
- Add the following code to the .htaccess file:
# BEGIN WordPress <IfModule mod_rewrite.c> RewriteEngine On RewriteBase / RewriteRule ^index\.php$ - [L] RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule . /index.php [L] </IfModule> # END WordPress
This code is the default .htaccess file for WordPress. It tells Apache to enable the rewrite engine and to rewrite all requests to index.php
.
- Save the .htaccess file.
- Upload the .htaccess file back to your website using your FTP client.
Using a WordPress plugin
There are a number of WordPress plugins that can help you create a .htaccess file. One popular plugin is Htaccess File Editor: https://wordpress.org/plugins/htaccess-file-editor/.
To use the Htaccess File Editor plugin, you will need to:
- Install and activate the plugin.
- Go to Settings > Htaccess File Editor.
- Click on the Create .htaccess button.
- The plugin will create a new .htaccess file with the default WordPress code.
- You can then make your own changes to the .htaccess file.
- Click on the Save Changes button.
Once you have saved your changes, the plugin will automatically update the .htaccess file on your website.
.htaccess file location
The .htaccess file is usually found in the root directory (usually public_html, www, htdocs …) and is on par with the robots.txt file. However, there are special cases where it is located outside the root directory of the website and affects all directories and websites located in that user.
You can find the .htaccess file in the following way:
- For DirectAdmin host, you can go to File > select public_html > .htaccess
- For the Cpanel host, select File Manager > select public_html > .htaccess
Note that some hosts will hide the .htaccess file. You must select “show hidden files” mode to see the .htaccess file
Why You Can’t Find .htaccess File?
There are 2 cases where you cannot find the .htaccess file.
Case 1: The .htaccess file has not been created.
Normally, WordPress will automatically create the htaccess file when you enable the Permalinks function. However, when you have not enabled this function, it will not create and you can create an htaccess file by going to WordPress Dashboard >> Settings >> Permalinks and then choosing one of 5 options:
- Custom Structure,
- Post name,
- numeric, Month, and name,
- Day and name
then click Save
Case 2: The .htaccess file has been hidden
Files that start with a dot are special files and are often hidden by the operating system or Files Explorer. .htaccess is often also hidden by popular FTP programs. Depending on the FTP program, you need to check the Force Showing Hidden Files box to show hidden files.
Common uses for .htaccess files
There are many uses for the .htaccess
files. These are the most popular examples:
- Redirections to certain URLs
- Load custom error pages, like 404 pages
- Forcing your website to use HTTPS over HTTP
- Allow or deny access to specific IP addresses on your website
- Password-protect specific directories on your server
These are just a few examples. This is the most requested section on this page. This section is frequently updated.
301 redirect htaccess
A 301 Permanent redirect permanently redirects one URL from another. To send visitors to a different URL, you can use .htaccess. This will tell search engines that a page moved to allow them to properly index the page.
A 301 redirect with the .htaccess is a common use:
- You can redirect visitors to your new site by using a 301 redirect from the old domain after you move to a new domain.
- You can use 301 redirects for users to go to new pages after moving pages from an old site to a new structure.
- You can use 301 redirects after combining two websites to make sure visitors go to the new pages.
To create and manage redirects on HostPapa websites, you can use.htaccess file. You can either create a.htaccess files using File Manager in cPanel or upload a.htaccessfile you have created using a text editor on your own computer using FTP.
Note: The .htaccess files are hidden files so you will need to set up the cPanel File Manager and an FTP client to view hidden files on your computer. You can find out how to do this by following the steps below.
Developer tip To restore functionality to a site after adding or updating .htaccess files, rename or delete the file.
Redirecting a single URL
This code can be used to redirect a single URL. Make sure to substitute “old page”, for “new page”, in your page names. ):
301 RedirectMatch /oldpage/ /newpage/
Redirecting a single folder
The following steps can be used to redirect a folder to a different location:
RewriteRule/?folder [R,L]
For example, we used “folder” & “location”. Substitute folder and location names
Redirecting old URLs to new URLs
You can change the filenames of specific pages by entering the following code. Replace “oldpage”, “example” and “newpage” with your information:
redirect 301 /oldpage.html htto://www.example.com/abc/newpage.html
Redirecting www to Non-www using a 301 .htaccess redirect
You might want to create a redirect to avoid using a subdomain of www. If that is the case, then you will need to redirect to a version other than www. This is what you will need: Simply replace “example.” with your domain.
Redirecting Domain Names
Use the following code to redirect an entire domain to another domain:
RewriteEngine on RewriteCond ^(?:www. )oldsite\.com$ [NC] RewriteRule ^https://newsite.com%REQUEST_URI [L,R=301]
WordPress .htaccess
This file is used by WordPress to control how Apache serves files from its root and subdirectories. WP modifies the file in order to allow for pretty permalinks.
This page can be used to repair a corrupted .htaccess file (e.g. A misbehaving plugin).
The .htaccess is either in the root directory of your webpage or in the directory you want to protect. If you are using Cpanel, htaccess file location is found in your website’s public_html
folder (/home/username/public_html
).
Because htaccess is a system configuration file and starts with a dot (.htaccess), so in some cases, you can’t see the file but you have to turn on showing hidden files to see it. That’s Why sometimes you Can’t Find the .htaccess file on your WordPress site.
For other FTP clients, you will find the option to show hidden files in-app settings or the preferences menu.
After enabling this option, you would be able to view all hidden files including the .htaccess file. In case you can’t find it, maybe it doesn’t exist. You can create it manually or by saving the setting in Permalink in WordPress Settings » Permalinks page.
There are several use cases for the .htaccess file. The most common examples include:
- Add redirections for certain URLs or folders
- Change default server error pages, like 500 pages, 501 pages, 404 pages,…
- Force your site to use HTTPS instead of HTTP
- Password-protect certain directories on your server
- Prevent hotlinking
Using .htaccess files is a powerful tool for managing your server, but it can be tricky. Make sure you are familiar with making changes to your server before you start editing .htaccess files.
Please note that the default WordPress htaccess file only contains the following code, other code you found in your .htaccess file may be added by other plugins or server configurations.
# BEGIN WordPress <IfModule mod_rewrite.c> RewriteEngine On RewriteRule .*[E=HTTP_AUTHORIZATION:%{HTTP:Authorization}] RewriteBase / RewriteRule ^index\.php$[L] RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule . /index.php [L] </IfModule> # END WordPress
If you want to add other code to your .htaccess file, please ADD IT OUTSIDE of the above code snippet. Otherwise, it may lose when you update the WordPress setting.
For example:
Wrong:
# BEGIN WordPress <IfModule mod_rewrite.c> RewriteEngine On RewriteRule .*[E=HTTP_AUTHORIZATION:%{HTTP:Authorization}] RewriteBase / RewriteRule ^index\.php$[L] RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule . /index.php [L] </IfModule> Options +FollowSymLinks RewriteEngine on RewriteCond %{HTTP_HOST} . RewriteCond %{HTTP_HOST} !^huyhoa\.net RewriteRule (.*) https://huyhoa.net/$1 [R=301,L] # END WordPress
The Right Way to Add to .htaccess in WordPress CMS:
Options +FollowSymLinks RewriteEngine on RewriteCond %{HTTP_HOST} . RewriteCond %{HTTP_HOST} !^mysite\.com RewriteRule (.*) https://mysite.com/$1 [R=301,L] # BEGIN WordPress <IfModule mod_rewrite.c> RewriteEngine On RewriteRule .*[E=HTTP_AUTHORIZATION:%{HTTP:Authorization}] RewriteBase / RewriteRule ^index\.php$[L] RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule . /index.php [L] </IfModule> # END WordPress
How to locate and edit the .htaccess file in WordPress
The .htaccess file is usually hidden. WordPress hides the .htaccess file because it is very important and can be accidentally deleted.
To locate the .htaccess file, log in to your WordPress hosting account. Next, navigate to the Cpanel. Launch the File Manager, then choose the Public_html folder.
You will need to make the .htaccess file visible. To do this, select Setting. This is usually located in the right-hand corner of the cPanel Folder Manager. A window will appear once you have selected Settings. Select the option Show hidden files.
Go back to the public_html folder. The .htaccess should now be visible.
Editing the .htaccess file can be done in many ways. We will show you all in the following paragraphs.
- Edit htaccess WordPress File from cPanel
- Edit htaccess WordPress File using FTP Client
- Or Edit htaccess WordPress File with a Plugin
Backups
Take a complete backup before you make any changes to WordPress .htaccess files. It is important to keep the file safe and avoid accidentally deleting it. You may not see the desired modification on your site if you make changes to the .htaccess file.
It could even cause the site to be unusable. No matter what happens, you can restore your site quickly to its original state if you have a backup. It’s easy.
Let’s now show you how to edit your .htaccess file.
Editing .htaccess File from cPanel
First:
Log in to your hosting account. Next, navigate to Cpanel and choose File Manager.
2nd Step:
Go to the Public_html folder in the File Manager. This folder contains the .htaccess file. Right-click to locate it and choose Edit.
Right-click to select Edit
That’s it. You can now insert code snippets to modify your website.
Edit htaccess WordPress File using FTP Client
FTP clients are another way to edit the .htaccess files. FTP clients are a tool that connects your website and your computer. Filezilla is an FTP client that allows you to access your website’s files from any computer on your network. This is how an FTP client can edit the file .htaccess.
Step 1: First, install Filezilla
Download Filezilla and install it on your computer. This is the most popular FTP client. Open it once you have it installed.
Step 2 – Find Your FTP Credentials
You will need your FTP credentials to connect Filezilla to your website. It’s possible to ask your hosting provider, but you can also search for it yourself.
FTP credentials are made up of hostname and username, password, and port number.
Filezilla offers several options in the top window that allow you to insert your FTP credentials. After you’ve done this, click Quickconnect to connect the software to your website.
Insert your hostname, username, and password, as well as the port number.
Step 3: Locate and Edit the .htaccess file
Filezilla can be divided into two parts. The local section shows you a collection of files from your computer. The remote shows you a collection of files from your website.
Select public_html from the remote section. The Filename section, located below the Remote site section, will contain the contents of the folder.
Right-click on the .htaccess file and choose Edit.
Go to Remote site > Filename>.htaccess
Next, we will show you how to modify your .htaccess file with a plugin.
Editing .htaccess File with a Plugin
Editing the .htaccess files via cPanel or via FTP client can be a little risky as you need to access the site’s backup and then edit the file. It can be overwhelming for website owners to access WordPress files. It wouldn’t surprise you to find yourself in this situation. A plugin is a safer option.
Although there are many plugins available to edit .htaccess files, we decided on Htaccess Editor after careful consideration. This plugin has more than 50,000 active installations and has received over 20 5-star ratings. It’s also frequently updated, according to the repository page. Htaccess Editor meets all requirements for selecting the correct plugin.
To ensure compatibility, you should first stage your website before installing the plugin. Compatibility issues could cause problems such as misbehaving sites and the inability to use certain plugins.
After you have tested it, you can edit the .htaccess file using a plugin.
First:
Install and activate HTML Access Editor on your WordPress website.
2nd Step:
Next, navigate to Settings and then choose WP HTMLaccess Editor. This will take you directly to the .htaccess file. You can insert any code snippet, but you must save the changes.
To edit the .htaccess file in WordPress, you can use a text editor or a WordPress plugin.
Using a text editor
- Connect to your website using an FTP client, such as FileZilla.
- Navigate to the root directory of your WordPress installation.
- Locate the .htaccess file.
- Open the .htaccess file in a text editor.
- Make your changes to the .htaccess file.
- Save the .htaccess file.
- Upload the .htaccess file back to your website using your FTP client.
Using a WordPress plugin
There are a number of WordPress plugins that can help you edit the .htaccess file. One popular plugin is Htaccess File Editor
To use the Htaccess File Editor plugin, you will need to:
- Install and activate the plugin.
- Go to Settings > Htaccess File Editor.
- Click on the Edit .htaccess button.
- Make your changes to the .htaccess file.
- Click on the Save Changes button.
Once you have saved your changes, the plugin will automatically update the .htaccess file on your website.
Default WordPress htaccess
WordPress should create a.htaccess for you automatically – but sometimes it’s not able to due to file permissions issues. Follow the below steps if that happens.
Log in to your WordPress dashboard, and then go to \
Scroll to the bottom, and then click Save Changes.
WordPress will now attempt to create a.htaccess. file. WordPress will now attempt to generate a .htaccess file. If it fails, you’ll get an error message at the bottom saying “.htaccess files are not writeable”.
The .htaccess file must be manually created. Log in to the control panel of your hosting account.
Start the File Manager.
Click on the public_html folder in the navigation menu located on the lefthand-hand side of the screen.
Click the +File button in the toolbar near the top of the screen.
In the New File Name input box, type “.htaccess”.
Click on Create New File.
To edit the file, right-click it.
You can add one of these codes.
You can use Basic WordPress if you only have WordPress on 1 domain.
The default WordPress .htaccess file can be found in the root directory of your WordPress installation. If you don’t have a .htaccess file, you can create one using a text editor.
Here is the content of the default WordPress .htaccess file:
# BEGIN WordPress RewriteEngine On RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}] RewriteBase / RewriteRule ^index\.php$ - [L] RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule . /index.php [L] # END WordPress
This .htaccess file includes the following rules:
- The
RewriteEngine On
directive tells Apache to enable the rewrite engine. - The
RewriteBase /
directive tells Apache that the root directory of the website is/
. - The
RewriteRule ^index\.php$ - [L]
directive tells Apache to rewrite any request forindex.php
itself. This is useful for preventing people from accessing the WordPress core files directly. - The
RewriteCond %{REQUEST_FILENAME} !-f
directive tells Apache to only rewrite requests for files that do not exist. - The
RewriteCond %{REQUEST_FILENAME} !-d
directive tells Apache to only rewrite requests for directories that do not exist. - The
RewriteRule . /index.php [L]
directive tells Apache to rewrite all other requests toindex.php
. This is how WordPress handles permalinks.
The default WordPress .htaccess file also includes some security settings, such as the following:
- The
Order deny,allow
directive tells Apache to deny access to all files by default, and then allow access to specific files. - The
Allow from all
directive tells Apache to allow access to all files from all IP addresses.
Multisite
WordPress 3.5 and up
If you activated Multisite on WordPress 3.5 or later, use one of these.
Subfolder Example
# BEGIN WordPress Multisite # Using subfolder network type: https://wordpress.org/support/article/htaccess/#multisite RewriteEngine On RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}] RewriteBase / RewriteRule ^index\.php$ - [L] # add a trailing slash to /wp-admin RewriteRule ^([_0-9a-zA-Z-]+/)?wp-admin$ $1wp-admin/ [R=301,L] RewriteCond %{REQUEST_FILENAME} -f [OR] RewriteCond %{REQUEST_FILENAME} -d RewriteRule ^ - [L] RewriteRule ^([_0-9a-zA-Z-]+/)?(wp-(content|admin|includes).*) $2 [L] RewriteRule ^([_0-9a-zA-Z-]+/)?(.*\.php)$ $2 [L] RewriteRule . index.php [L] # END WordPress Multisite
SubDomain Example
# BEGIN WordPress Multisite # Using subdomain network type: https://wordpress.org/support/article/htaccess/#multisite RewriteEngine On RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}] RewriteBase / RewriteRule ^index\.php$ - [L] # add a trailing slash to /wp-admin RewriteRule ^wp-admin$ wp-admin/ [R=301,L] RewriteCond %{REQUEST_FILENAME} -f [OR] RewriteCond %{REQUEST_FILENAME} -d RewriteRule ^ - [L] RewriteRule ^(wp-(content|admin|includes).*) $1 [L] RewriteRule ^(.*\.php)$ $1 [L] RewriteRule . index.php [L] # END WordPress Multisite
Save and close the file.
Now that you know how to create a default .htaccess file for your WordPress site if it doesn’t exist already, you’re ready to edit it. Let’s look at how below.
Some advanced htaccess code for your WordPress site
Here are some specific examples, this is the most popular section of this page. Updated frequently.
Redirect Everyone Except the IP address to an alternate page
ErrorDocument 403 https://www.yahoo.com/ Order deny,allow Deny from all Allow from 123.123.123.123
When developing sites
This lets Google crawl the page, lets me access it without a password, and lets my client access the page WITH a password. It also allows for XHTML and CSS validation! (w3.org)
AuthName "Under Development" AuthUserFile /web/sitename.com/.htpasswd AuthType basic Require valid-user Order deny,allow Deny from all Allow from 208.113.134.190 w3.org htmlhelp.com googlebot.com Satisfy Any
Fix double-login prompt
Redirect non-HTTPS requests to the HTTPS server and ensure that .htpasswd authorization can only be entered across HTTPS
SSLOptions +StrictRequire SSLRequireSSL SSLRequire %{HTTP_HOST} eq "huyhoa.net" ErrorDocument 403 https://huyhoa.net
Set the Timezone of the Server (GMT)
SetEnv TZ America/Indianapolis
Administrator Email for ErrorDocument
SetEnv SERVER_ADMIN [email protected]
ServerSignature for ErrorDocument
ServerSignature off | on | email
Charset and Language headers
AddDefaultCharset UTF-8 DefaultLanguage en-US
Disallow Script Execution
Options -ExecCGI AddHandler cgi-script .php .pl .py .jsp .asp .htm .shtml .sh .cgi
Deny Request Methods
RewriteCond %{REQUEST_METHOD} !^(GET|HEAD|OPTIONS|POST|PUT) RewriteRule .? - [F]
Force “File Save As” Prompt
AddType application/octet-stream .avi .mpg .mov .pdf .xls .mp4
Show CGI Source Code
RemoveHandler cgi-script .pl .py .cgi AddType text/plain .pl .py .cgi
Serve all .pdf files on your site using .htaccess and mod_rewrite with the PHP script.
RewriteCond %{REQUEST_FILENAME} -f RewriteRule ^(.+)\.pdf$ /cgi-bin/pdf.php?file=$1 [L,NC,QSA]
Rewrite to www
RewriteCond %{REQUEST_URI} !^/(robots\.txt|favicon\.ico|sitemap\.xml)$ RewriteCond %{HTTP_HOST} !^www\.yourdomain\.com$ [NC] RewriteRule ^(.*)$ https://www.yourdomain.com/$1 [R=301,L]
Rewrite to www dynamically
RewriteCond %{REQUEST_URI} !^/robots\.txt$ [NC] RewriteCond %{HTTP_HOST} !^www\.[a-z-]+\.[a-z]{2,6} [NC] RewriteCond %{HTTP_HOST} ([a-z-]+\.[a-z]{2,6})$ [NC] RewriteRule ^/(.*)$ https://%1/$1 [R=301,L]
301 Redirect Old File
Redirect 301 /old/file.html https://www.yournewdomain.com/new/file/
301 Redirect Entire Directory
RedirectMatch 301 /blog(.*) https://www.google.com/$1
Protecting your PHP.cgi
<FilesMatch "^php5?\.(ini|cgi)$"> Order Deny,Allow Deny from All Allow from env=REDIRECT_STATUS </FilesMatch>
Set-Cookie based on Request
This code sends the Set-Cookie
header to create a cookie on the client with the value of a matching item in 2nd parentheses.
RewriteRule ^(.*)(de|es|fr|it|ja|ru|en)/$ - [co=lang:$2:.yourdomain.com:7200:/]
Set-Cookie with env variable
Header set Set-Cookie "language=%{lang}e; path=/;" env=lang
Custom ErrorDocuments
ErrorDocument 100 /100_CONTINUE ErrorDocument 101 /101_SWITCHING_PROTOCOLS ErrorDocument 102 /102_PROCESSING ErrorDocument 200 /200_OK ErrorDocument 201 /201_CREATED ErrorDocument 202 /202_ACCEPTED ErrorDocument 203 /203_NON_AUTHORITATIVE ErrorDocument 204 /204_NO_CONTENT ErrorDocument 205 /205_RESET_CONTENT ErrorDocument 206 /206_PARTIAL_CONTENT ErrorDocument 207 /207_MULTI_STATUS ErrorDocument 300 /300_MULTIPLE_CHOICES ErrorDocument 301 /301_MOVED_PERMANENTLY ErrorDocument 302 /302_MOVED_TEMPORARILY ErrorDocument 303 /303_SEE_OTHER ErrorDocument 304 /304_NOT_MODIFIED ErrorDocument 305 /305_USE_PROXY ErrorDocument 307 /307_TEMPORARY_REDIRECT ErrorDocument 400 /400_BAD_REQUEST ErrorDocument 401 /401_UNAUTHORIZED ErrorDocument 402 /402_PAYMENT_REQUIRED ErrorDocument 403 /403_FORBIDDEN ErrorDocument 404 /404_NOT_FOUND ErrorDocument 405 /405_METHOD_NOT_ALLOWED ErrorDocument 406 /406_NOT_ACCEPTABLE ErrorDocument 407 /407_PROXY_AUTHENTICATION_REQUIRED ErrorDocument 408 /408_REQUEST_TIME_OUT ErrorDocument 409 /409_CONFLICT ErrorDocument 410 /410_GONE ErrorDocument 411 /411_LENGTH_REQUIRED ErrorDocument 412 /412_PRECONDITION_FAILED ErrorDocument 413 /413_REQUEST_ENTITY_TOO_LARGE ErrorDocument 414 /414_REQUEST_URI_TOO_LARGE ErrorDocument 415 /415_UNSUPPORTED_MEDIA_TYPE ErrorDocument 416 /416_RANGE_NOT_SATISFIABLE ErrorDocument 417 /417_EXPECTATION_FAILED ErrorDocument 422 /422_UNPROCESSABLE_ENTITY ErrorDocument 423 /423_LOCKED ErrorDocument 424 /424_FAILED_DEPENDENCY ErrorDocument 426 /426_UPGRADE_REQUIRED ErrorDocument 500 /500_INTERNAL_SERVER_ERROR ErrorDocument 501 /501_NOT_IMPLEMENTED ErrorDocument 502 /502_BAD_GATEWAY ErrorDocument 503 /503_SERVICE_UNAVAILABLE ErrorDocument 504 /504_GATEWAY_TIME_OUT ErrorDocument 505 /505_VERSION_NOT_SUPPORTED ErrorDocument 506 /506_VARIANT_ALSO_VARIES ErrorDocument 507 /507_INSUFFICIENT_STORAGE ErrorDocument 510 /510_NOT_EXTENDED
Implementing a Caching Scheme with .htaccess
# year <FilesMatch "\.(ico|pdf|flv|jpg|jpeg|png|gif|swf|mp3|mp4)$"> Header set Cache-Control "public" Header set Expires "Thu, 15 Apr 2010 20:00:00 GMT" Header unset Last-Modified </FilesMatch> #2 hours <FilesMatch "\.(html|htm|xml|txt|xsl)$"> Header set Cache-Control "max-age=7200, must-revalidate" </FilesMatch> <FilesMatch "\.(js|css)$"> SetOutputFilter DEFLATE Header set Expires "Thu, 15 Apr 2010 20:00:00 GMT" </FilesMatch>
Password Protect a single file
<Files login.php> AuthName "Prompt" AuthType Basic AuthUserFile /web/google.com/.htpasswd Require valid-user </Files>
Password Protect multiple files
<FilesMatch "^(private|phpinfo).*$"> AuthName "Development" AuthUserFile /.htpasswd AuthType basic Require valid-user </FilesMatch>
Send Custom Headers
Header set P3P "policyref="https://www.google.com/w3c/p3p.xml"" Header set X-Pingback "https://www.google.com/xmlrpc.php" Header set Content-Language "en-US" Header set Vary "Accept-Encoding"
Blocking based on User-Agent Header
SetEnvIfNoCase ^User-Agent$ .*(craftbot|download|extract|stripper|sucker|ninja|clshttp|webspider|leacher|collector|grabber|webpictures) HTTP_SAFE_BADBOT SetEnvIfNoCase ^User-Agent$ .*(libwww-perl|aesop_com_spiderman) HTTP_SAFE_BADBOT Deny from env=HTTP_SAFE_BADBOT
Blocking with RewriteCond
RewriteCond %{HTTP_USER_AGENT} ^.*(craftbot|download|extract|stripper|sucker|ninja|clshttp|webspider|leacher|collector|grabber|webpictures).*$ [NC] RewriteRule . - [F,L]
.htaccess for mod_php
SetEnv PHPRC /location/todir/containing/phpinifile
.htaccess for PHP as CGI
AddHandler php-cgi .php .htm Action php-cgi /cgi-bin/php5.cgi
Shell wrapper for custom php.ini
#!/bin/sh export PHP_FCGI_CHILDREN=3 exec php5.cgi -c /abs/php5/php.ini
Add values from HTTP Headers
SetEnvIfNoCase ^If-Modified-Since$ "(.+)" HTTP_IF_MODIFIED_SINCE=$1 SetEnvIfNoCase ^If-None-Match$ "(.+)" HTTP_IF_NONE_MATCH=$1 SetEnvIfNoCase ^Cache-Control$ "(.+)" HTTP_CACHE_CONTROL=$1 SetEnvIfNoCase ^Connection$ "(.+)" HTTP_CONNECTION=$1 SetEnvIfNoCase ^Keep-Alive$ "(.+)" HTTP_KEEP_ALIVE=$1 SetEnvIfNoCase ^Authorization$ "(.+)" HTTP_AUTHORIZATION=$1 SetEnvIfNoCase ^Cookie$ "(.+)" HTTP_MY_COOKIE=$1
Stop hotlinking
RewriteCond %{HTTP_REFERER} !^$ RewriteCond %{HTTP_REFERER} !^https://(www\.)?askapache\.com/.*$ [NC] RewriteRule \.(gif|jpg|swf|flv|png)$ https://www.google.com/feed.gif [R=302,L]
Other Example .htaccess Files
# Set the Time Zone of your Server SetEnv TZ America/Indianapolis # ServerAdmin: This address appears on some server-generated pages, such as error documents. SetEnv SERVER_ADMIN [email protected] # Possible values for the Options directive are "None", "All", or any combination of: # Indexes Includes FollowSymLinks SymLinksifOwnerMatch ExecCGI MultiViews Options -ExecCGI -MultiViews -Includes -Indexes FollowSymLinks # DirectoryIndex: sets the file that Apache will serve if a directory is requested. DirectoryIndex index.html index.php /index.php # Action lets you define media types that will execute a script whenever # a matching file is called. This eliminates the need for repeated URL # pathnames for oft-used CGI file processors. # Format: Action media/type /cgi-script/location # Format: Action handler-name /cgi-script/location # Action php5-cgi /bin/php.cgi # AddHandler allows you to map certain file extensions to "handlers": # actions unrelated to filetype. These can be either built into the server # or added with the Action directive (see below) # # To use CGI scripts outside of ScriptAliased directories: # (You will also need to add "ExecCGI" to the "Options" directive.) # AddHandler php-cgi .php .inc # Commonly used filename extensions to character sets. AddDefaultCharset UTF-8 # AddType allows you to add to or override the MIME configuration AddType 'application/rdf+xml; charset=UTF-8' .rdf AddType 'application/xhtml+xml; charset=UTF-8' .xhtml AddType 'application/xhtml+xml; charset=UTF-8' .xhtml.gz AddType 'text/html; charset=UTF-8' .html AddType 'text/html; charset=UTF-8' .html.gz AddType application/octet-stream .rar .chm .bz2 .tgz .msi .pdf .exe AddType application/vnd.ms-excel .csv AddType application/x-httpd-php-source .phps AddType application/x-pilot .prc .pdb AddType application/x-shockwave-flash .swf AddType application/xrds+xml .xrdf AddType text/plain .ini .sh .bsh .bash .awk .nawk .gawk .csh .var .c .in .h .asc .md5 .sha .sha1 AddType video/x-flv .flv # AddEncoding allows you to have certain browsers uncompress information on the fly. Note: Not all browsers support this. AddEncoding x-compress .Z AddEncoding x-gzip .gz .tgz # DefaultType: the default MIME type the server will use for a document. DefaultType text/html # Optionally add a line containing the server version and virtual host # name to server-generated pages (internal error documents, FTP directory # listings, mod_status and mod_info output etc., but not CGI generated # documents or custom error documents). # Set to "EMail" to also include a mailto: link to the ServerAdmin. # Set to one of: On | Off | EMail ServerSignature Off
## MAIN DEFAULTS Options +ExecCGI -Indexes DirectoryIndex index.html index.htm index.php DefaultLanguage en-US AddDefaultCharset UTF-8 ServerSignature Off ## ENVIRONMENT VARIABLES SetEnv PHPRC /webroot/includes SetEnv TZ America/Indianapolis SetEnv SERVER_ADMIN [email protected] ## MIME TYPES AddType video/x-flv .flv AddType application/x-shockwave-flash .swf AddType image/x-icon .ico ## FORCE FILE TO DOWNLOAD INSTEAD OF APPEAR IN BROWSER AddType application/octet-stream .mov .mp3 .zip ## ERRORDOCUMENTS ErrorDocument 400 /e400/ ErrorDocument 401 /e401/ ErrorDocument 402 /e402/ ErrorDocument 403 /e403/ ErrorDocument 404 /e404/ # Handlers be builtin, included in a module, or added with Action directive # default-handler: default, handles static content (core) # send-as-is: Send file with HTTP headers (mod_asis) # cgi-script: treat file as CGI script (mod_cgi) # imap-file: Parse as an imagemap rule file (mod_imap) # server-info: Get server config info (mod_info) # server-status: Get server status report (mod_status) # type-map: type map file for content negotiation (mod_negotiation) # fastcgi-script: treat file as fastcgi script (mod_fastcgi) # ## PARSE AS CGI AddHandler cgi-script .cgi .pl .spl ## RUN PHP AS APACHE MODULE AddHandler application/x-httpd-php .php .htm ## RUN PHP AS CGI AddHandler php-cgi .php .htm ## CGI PHP WRAPPER FOR CUSTOM PHP.INI AddHandler phpini-cgi .php .htm Action phpini-cgi /cgi-bin/php5-custom-ini.cgi ## FAST-CGI SETUP WITH PHP-CGI WRAPPER FOR CUSTOM PHP.INI AddHandler fastcgi-script .fcgi AddHandler php-cgi .php .htm Action php-cgi /cgi-bin/php5-wrapper.fcgi ## CUSTOM PHP CGI BINARY SETUP AddHandler php-cgi .php .htm Action php-cgi /cgi-bin/php.cgi ## PROCESS SPECIFIC FILETYPES WITH CGI-SCRIPT Action image/gif /cgi-bin/img-create.cgi ## CREATE CUSTOM HANDLER FOR SPECIFIC FILE EXTENSIONS AddHandler custom-processor .ssp Action custom-processor /cgi-bin/myprocessor.cgi ### HEADER CACHING <FilesMatch "\.(flv|gif|jpg|jpeg|png|ico)$"> Header set Cache-Control "max-age=2592000" </FilesMatch> <FilesMatch "\.(js|css|pdf|swf)$"> Header set Cache-Control "max-age=604800" </FilesMatch> <FilesMatch "\.(html|htm|txt)$"> Header set Cache-Control "max-age=600" </FilesMatch> <FilesMatch "\.(pl|php|cgi|spl|scgi|fcgi)$"> Header unset Cache-Control </FilesMatch> ## ALTERNATE EXPIRES CACHING ExpiresActive On ExpiresDefault A604800 ExpiresByType image/x-icon A2592000 ExpiresByType application/x-javascript A2592000 ExpiresByType text/css A2592000 ExpiresByType text/html A300 <FilesMatch "\.(pl|php|cgi|spl|scgi|fcgi)$"> ExpiresActive Off </FilesMatch> ## META HTTP-EQUIV REPLACEMENTS <FilesMatch "\.(html|htm|php)$"> Header set imagetoolbar "no" </FilesMatch>
Here are some default MOD_REWRITE code examples.
## REWRITE DEFAULTS RewriteEngine On RewriteBase / ## REQUIRE SUBDOMAIN RewriteCond %{HTTP_HOST} !^$ RewriteCond %{HTTP_HOST} !^subdomain\.askapache\.com$ [NC] RewriteRule ^/(.*)$ https://subdomain.google.com/$1 [L,R=301] ## SEO REWRITES RewriteRule ^(.*)/ve/(.*)$ $1/voluntary-employee/$2 [L,R=301] RewriteRule ^(.*)/hsa/(.*)$ $1/health-saving-account/$2 [L,R=301] ## WORDPRESS RewriteCond %{REQUEST_FILENAME} !-f # Existing File RewriteCond %{REQUEST_FILENAME} !-d # Existing Directory RewriteRule . /index.php [L] ## ALTERNATIVE ANTI-HOTLINKING RewriteCond %{HTTP_REFERER} !^$ RewriteCond %{HTTP_REFERER} !^https://(subdomain\.)?askapache\.com/.*$ [NC] RewriteRule ^.*\.(bmp|tif|gif|jpg|jpeg|jpe|png)$ - [F] ## REDIRECT HOTLINKERS RewriteCond %{HTTP_REFERER} !^$ RewriteCond %{HTTP_REFERER} !^https://(subdomain\.)?askapache\.com/.*$ [NC] RewriteRule ^.*\.(bmp|tif|gif|jpg|jpeg|jpe|png)$ https://google.com [R] ## DENY REQUEST BASED ON REQUEST METHOD RewriteCond %{REQUEST_METHOD} ^(TRACE|TRACK|OPTIONS|HEAD)$ [NC] RewriteRule ^.*$ - [F] ## REDIRECT UPLOADS RewriteCond %{REQUEST_METHOD} ^(PUT|POST)$ [NC] RewriteRule ^(.*)$ /cgi-bin/form-upload-processor.cgi?p=$1 [L,QSA] ## REQUIRE SSL EVEN WHEN MOD_SSL IS NOT LOADED RewriteCond %{HTTPS} !=on [NC] RewriteRule ^.*$ https://%{SERVER_NAME}%{REQUEST_URI} [R,L] ### ALTERNATATIVE TO USING ERRORDOCUMENT # https://www.htaccesselite.com/d/htaccess-errordocument-examples-vt11.html RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule ^.*$ /error.php [L] ## SEO REDIRECTS Redirect 301 /2006/oldfile.html https://subdomain.google.com/newfile.html RedirectMatch 301 /o/(.*)$ https://subdomain.google.com/s/dl/$1
Examples of protecting your files and securing them with password protection.
# # Require (user|group|valid-user) (username|groupname) # ## BASIC PASSWORD PROTECTION AuthType basic AuthName "prompt" AuthUserFile /.htpasswd AuthGroupFile /dev/null Require valid-user ## ALLOW FROM IP OR VALID PASSWORD Require valid-user Allow from 192.168.1.23 Satisfy Any ## PROTECT FILES <FilesMatch "\.(htaccess|htpasswd|ini|phps|fla|psd|log|sh)$"> Order Allow,Deny Deny from all </FilesMatch> ## PREVENT HOTLINKING SetEnvIfNoCase Referer "^https://subdomain.google.com/" good SetEnvIfNoCase Referer "^$" good <FilesMatch "\.(png|jpg|jpeg|gif|bmp|swf|flv)$"> Order Deny,Allow Deny from all Allow from env=good ErrorDocument 403 https://www.google.com/intl/en_ALL/images/logo.gif ErrorDocument 403 /images/you_bad_hotlinker.gif </FilesMatch> ## LIMIT UPLOAD FILE SIZE TO PROTECT AGAINST DOS ATTACK #bytes, 0-2147483647(2GB) LimitRequestBody 10240000 ## MOST SECURE WAY TO REQUIRE SSL SSLOptions +StrictRequire SSLRequireSSL SSLRequire %{HTTP_HOST} eq "google.com" ErrorDocument 403 https://google.com ## COMBINED DEVELOPER HTACCESS CODE-USE THIS <FilesMatch "\.(flv|gif|jpg|jpeg|png|ico|js|css|pdf|swf|html|htm|txt)$"> Header set Cache-Control "max-age=5" </FilesMatch> AuthType basic AuthName "Ooops! Temporarily Under Construction..." AuthUserFile /.htpasswd AuthGroupFile /dev/null Require valid-user # password prompt for everyone else Order Deny,Allow Deny from all Allow from 192.168.64.5 # Your, the developers IP address Allow from w3.org # css/xhtml check Allow from googlebot.com # Allows google to crawl your pages Satisfy Any # no password required if host/ip is Allowed ## DONT HAVE TO EMPTY CACHE OR RELOAD TO SEE CHANGES ExpiresDefault A5 #If using mod_expires <FilesMatch "\.(flv|gif|jpg|jpeg|png|ico|js|css|pdf|swf|html|htm|txt)$"> Header set Cache-Control "max-age=5" </FilesMatch> ## ALLOW ACCESS WITH PASSWORD OR NO PASSWORD FOR SPECIFIC IP/HOSTS AuthType basic AuthName "Ooops! Temporarily Under Construction..." AuthUserFile /.htpasswd AuthGroupFile /dev/null Require valid-user # password prompt for everyone else Order Deny,Allow Deny from all Allow from 192.168.64.5 # Your, the developers IP address Allow from w3.org # css/xhtml Allow from googlebot.com # Allows google to crawl your pages Satisfy Any # no password required if host/ip is Allowed
Advanced Mod_Rewrites
Here are some specific htaccess examples taken mostly from my WordPress Password Protection plugin, which does a lot more than password protection as you will see from the following mod_rewrite examples.
These are a few of the mod_rewrite uses that BlogSecurity declared pushed the boundaries of Mod_Rewrite! Some of these snippets are quite exotic and unlike anything, you may have seen before, also only for those who understand them as they can kill a website pretty quickly.
Directory Protection
Enable the DirectoryIndex Protection, preventing directory index listings and defaulting.
Options -Indexes DirectoryIndex index.html index.php /index.php
Password Protect wp-login.php
Requires a valid user/pass to access the login page
<Files wp-login.php> Order Deny,Allow Deny from All Satisfy Any AuthName "Protected By AskApache" AuthUserFile /web/google.com/.htpasswda1 AuthType Basic Require valid-user </Files>
Password Protect wp-admin
Requires a valid user/pass to access any non-static (CSS, js, images) file in this directory.
Options -ExecCGI -Indexes +FollowSymLinks -Includes DirectoryIndex index.php /index.php Order Deny,Allow Deny from All Satisfy Any AuthName "Protected By AskApache" AuthUserFile /web/google.com/.htpasswda1 AuthType Basic Require valid-user <FilesMatch "\.(ico|pdf|flv|jpg|jpeg|mp3|mpg|mp4|mov|wav|wmv|png|gif|swf|css|js)$"> Allow from All </FilesMatch> <FilesMatch "(async-upload)\.php$"> <IfModule mod_security.c> SecFilterEngine Off </IfModule> Allow from All </FilesMatch>
Protect wp-content
Denies any Direct request for files ending in .php with a 403 Forbidden. May break plugins/themes
RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /wp-content/.*$ [NC] RewriteCond %{REQUEST_FILENAME} !^.+flexible-upload-wp25js.php$ RewriteCond %{REQUEST_FILENAME} ^.+\.(php|html|htm|txt)$ RewriteRule .? - [F,NS,L]
Protect wp-includes
Denies any Direct request for files ending in .php with a 403 Forbidden.. May break plugins/themes
RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /wp-includes/.*$ [NC] RewriteCond %{THE_REQUEST} !^[A-Z]{3,9}\ /wp-includes/js/.+/.+\ HTTP/ [NC] RewriteCond %{REQUEST_FILENAME} ^.+\.php$ RewriteRule .? - [F,NS,L]
Common Exploits
Block common exploit requests with 403 Forbidden. These can help a lot, and may break some plugins.
RewriteCond %{REQUEST_URI} !^/(wp-login.php|wp-admin/|wp-content/plugins/|wp-includes/).* [NC] RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ ///.*\ HTTP/ [NC,OR] RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /.*\?\=?(http|ftp|ssl|https):/.*\ HTTP/ [NC,OR] RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /.*\?\?.*\ HTTP/ [NC,OR] RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /.*\.(asp|ini|dll).*\ HTTP/ [NC,OR] RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /.*\.(htpasswd|htaccess|aahtpasswd).*\ HTTP/ [NC] RewriteRule .? - [F,NS,L]
Stop Hotlinking
Denies any request for static files (images, CSS, etc) if the referrer is not a local site or is empty.
RewriteCond %{HTTP_REFERER} !^$ RewriteCond %{REQUEST_URI} !^/(wp-login.php|wp-admin/|wp-content/plugins/|wp-includes/).* [NC] RewriteCond %{HTTP_REFERER} !^https://www.google.com.*$ [NC] RewriteRule \.(ico|pdf|flv|jpg|jpeg|mp3|mpg|mp4|mov|wav|wmv|png|gif|swf|css|js)$ - [F,NS,L]
Safe Request Methods
Denies any request not using GET, PROPFIND, POST, OPTIONS, PUT, HEAD
RewriteCond %{REQUEST_METHOD} !^(GET|HEAD|POST|PROPFIND|OPTIONS|PUT)$ [NC] RewriteRule .? - [F,NS,L]
Forbid Proxies
Denies any POST Request using a Proxy Server. Can still access the site, but not comment.
RewriteCond %{REQUEST_METHOD} =POST RewriteCond %{HTTP:VIA}%{HTTP:FORWARDED}%{HTTP:USERAGENT_VIA}%{HTTP:X_FORWARDED_FOR}%{HTTP:PROXY_CONNECTION} !^$ [OR] RewriteCond %{HTTP:XPROXY_CONNECTION}%{HTTP:HTTP_PC_REMOTE_ADDR}%{HTTP:HTTP_CLIENT_IP} !^$ RewriteCond %{REQUEST_URI} !^/(wp-login.php|wp-admin/|wp-content/plugins/|wp-includes/).* [NC] RewriteRule .? - [F,NS,L]
Real wp-comments-post.php
Denies any POST attempt made to a non-existing wp-comments-post.php
RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /.*/wp-comments-post\.php.*\ HTTP/ [NC] RewriteRule .? - [F,NS,L]
HTTP PROTOCOL
Denies any badly formed HTTP PROTOCOL in the request, 0.9, 1.0, and 1.1 only
RewriteCond %{THE_REQUEST} !^[A-Z]{3,9}\ .+\ HTTP/(0\.9|1\.0|1\.1) [NC] RewriteRule .? - [F,NS,L]
SPECIFY CHARACTERS
Denies any request for a URL containing characters other than “a-zA-Z0-9.+/-?=&” – REALLY helps but may break your site depending on your links.
RewriteCond %{REQUEST_URI} !^/(wp-login.php|wp-admin/|wp-content/plugins/|wp-includes/).* [NC] RewriteCond %{THE_REQUEST} !^[A-Z]{3,9}\ [a-zA-Z0-9\.\+_/\-\?\=\&]+\ HTTP/ [NC] RewriteRule .? - [F,NS,L]
BAD Content-Length
Denies any POST request that doesn’t have a Content-Length Header
RewriteCond %{REQUEST_METHOD} =POST RewriteCond %{HTTP:Content-Length} ^$ RewriteCond %{REQUEST_URI} !^/(wp-admin/|wp-content/plugins/|wp-includes/).* [NC] RewriteRule .? - [F,NS,L]
BAD Content-Type
Denies any POST request with a content type other than application/x-www-form-urlencoded|multipart/form-data
RewriteCond %{REQUEST_METHOD} =POST RewriteCond %{HTTP:Content-Type} !^(application/x-www-form-urlencoded|multipart/form-data.*(boundary.*)?)$ [NC] RewriteCond %{REQUEST_URI} !^/(wp-login.php|wp-admin/|wp-content/plugins/|wp-includes/).* [NC] RewriteRule .? - [F,NS,L]
Missing HTTP_HOST
Denies requests that don’t contain an HTTP Host Header.
RewriteCond %{REQUEST_URI} !^/(wp-login.php|wp-admin/|wp-content/plugins/|wp-includes/).* [NC] RewriteCond %{HTTP_HOST} ^$ RewriteRule .? - [F,NS,L]
Bogus Graphics Exploit
Denies obvious exploit using bogus graphics
RewriteCond %{HTTP:Content-Disposition} \.php [NC] RewriteCond %{HTTP:Content-Type} image/.+ [NC] RewriteRule .? - [F,NS,L]
No UserAgent, Not POST
Denies POST requests by blank user-agents. May prevent a small number of visitors from POSTING.
RewriteCond %{REQUEST_METHOD} =POST RewriteCond %{HTTP_USER_AGENT} ^-?$ RewriteCond %{REQUEST_URI} !^/(wp-login.php|wp-admin/|wp-content/plugins/|wp-includes/).* [NC] RewriteRule .? - [F,NS,L]
No Referer, No Comment
Denies any comment attempt with a blank HTTP_REFERER field, highly indicative of spam. May prevent some visitors from POSTING.
RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /.*/wp-comments-post\.php.*\ HTTP/ [NC] RewriteCond %{HTTP_REFERER} ^-?$ RewriteRule .? - [F,NS,L]
Trackback Spam
Denies obvious trackback spam.
RewriteCond %{REQUEST_METHOD} =POST RewriteCond %{HTTP_USER_AGENT} ^.*(opera|mozilla|firefox|msie|safari).*$ [NC] RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /.+/trackback/?\ HTTP/ [NC] RewriteRule .? - [F,NS,L]
Map all URIs except those corresponding to existing files to a handler
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} !-d RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} !-f RewriteRule . /script.php
Map any request to a handler
In the case where all URIs should be sent to the same place (including potentially requests for static content) the method to use depends on the type of the handler. For php scripts, use: For other handlers such as php scripts, use:
RewriteCond %{REQUEST_URI} !=/script.php RewriteRule .* /script.php
And for CGI scripts:
ScriptAliasMatch .* /var/www/script.cgi
Map URIs corresponding to existing files to a handler instead
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -d [OR] RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -f RewriteCond %{REQUEST_URI} !=/script.php RewriteRule .* /script.php
If the existing files you wish to have handled by your script have a common set of file extensions distinct from that of the hander, you can bypass mod_rewrite and use instead mod_actions. Let’s say you want all .html and .tpl files to be dealt with by your script:
Action foo-action /script.php AddHandler foo-action html tpl
Deny access if var=val contains the string foo.
RewriteCond %{QUERY_STRING} foo RewriteRule ^/url - [F]
Removing the Query String
RewriteRule ^/url /url?
Adding to the Query String
Keep the existing query string using the Query String Append flag, but add var=val to the end.
RewriteRule ^/url /url?var=val [QSA]
Rewriting For Certain Query Strings
Rewrite URLs like https://google.com/url1?var=val to https://google.com/url2?var=val but don’t rewrite if val isn’t present.
RewriteCond %{QUERY_STRING} val RewriteRule ^/url1 /url2
Modifying the Query String
Change any single instance of val in the query string to other_val when accessing /path. Note that %1 and %2 are back-references to the matched part of the regular expression in the previous RewriteCond.
RewriteCond %{QUERY_STRING} ^(.*)val(.*)$ RewriteRule /path /path?%1other_val%2
Disable browser caching for all files that don’t get a hash string by Angular.
<FilesMatch "^(?!.*\.([0-9a-z]{20})\.).*$"> <IfModule mod_headers.c> FileETag None Header unset ETag Header unset Pragma Header unset Cache-Control Header unset Last-Modified Header set Pragma "no-cache" Header set Cache-Control "max-age=0, no-cache, no-store, must-revalidate" Header set Expires "Mon, 1 Jan 1900 00:00:00 GMT" </IfModule> </FilesMatch> <IfModule mod_headers.c>
Remove X-Powered-By header
<IfModule mod_headers.c> Header unset X-Powered-By Header always unset X-Powered-By </IfModule>
Remove server signature
ServerSignature Off
This is a fairly simple RewriteRule. Use the expression (-4)? to optionally match the -4 and redirect it to /blog-5 along with requests to /blog/. The second (.*) group after the / captures everything else into $2.
RewriteEngine On RewriteRule ^blog(-4)?/(.*) blog-5/$2 [L]
The above will do a silent internal rewrite. If you actually want to redirect and have the browser the new URL, change [L] to [L,R=301].
Note: Realizing blog-4 is probably a variable name, use (-.+)? to match anything. But you also need a RewriteCond so it doesn’t match blog-5:
RewriteCond %{REQUEST_URI} !^/blog-5 RewriteRule ^blog(-.+)?/(.*) blog-5/$2 [L]
Forcing Non-WWW with HTTPS Site Addresses
When you add this information to your .htaccess file, any visitors who type in www.huyhoa.net will be sent to huyhoa.net.
Options +FollowSymLinks RewriteEngine on RewriteCond %{SERVER_PORT} 80 [OR] RewriteCond %{HTTP_HOST} ^www.huyhoa.net [NC] RewriteRule ^(.*)$ https://huyhoa.net/$1 [R,L]
Replace huyhoa.net with your domain.
Forcing WWW with HTTPS Site Addresses with .htaccess
Options +FollowSymLinks RewriteEngine on RewriteCond %{SERVER_PORT} 80 [OR] RewriteCond %{HTTP_HOST} !^www.huyhoa.net [NC] RewriteRule ^(.*)$ https://www.huyhoa.net/$1 [R,L]
Remember to replace huyhoa.net with your domain.
Creating a Custom 404 Error Page with .htaccess
# serve custom error pages ErrorDocument 404 /errors/400.html
You can change any error page using the .htaccess file.
For example:
# serve custom error pages ErrorDocument 400 /errors/400.html ErrorDocument 401 /errors/401.html ErrorDocument 402 /errors/402.html ErrorDocument 403 /errors/403.html ErrorDocument 404 /errors/404.html ErrorDocument 405 /errors/405.html ErrorDocument 408 /errors/408.html ErrorDocument 500 /errors/500.html ErrorDocument 501 /errors/501.html ErrorDocument 503 /errors/503.html ErrorDocument 508 /errors/508.html
See all list of HTTP status codes here: https://en.wikipedia.org/wiki/List_of_HTTP_status_codes
Denying and Allowing Access
Deny except specific IPs
Order deny,allow Deny from all Allow from 1.1.1.1 Allow from 2.2.2.2
Allow except specific IPs
Order deny,allow Allow from all Deny from 1.1.1.1 Deny from 2.2.2.2
Set Expires
# BEGIN EXPIRES <IfModule mod_expires.c> ExpiresActive On ExpiresDefault "access plus 10 days" ExpiresByType text/css "access plus 1 week" ExpiresByType text/plain "access plus 1 month" ExpiresByType image/gif "access plus 1 month" ExpiresByType image/png "access plus 1 month" ExpiresByType image/jpeg "access plus 1 month" ExpiresByType application/x-javascript "access plus 1 month" ExpiresByType application/javascript "access plus 1 week" ExpiresByType application/x-icon "access plus 1 year" </IfModule> # END EXPIRES
Temporary Maintenance using Mod_Rewrite
# Don't forget to turn on the rewrite engine RewriteEngine on # Maintenance Redirection # Replace 1\.1\.1\.1 with your own IP address # Uncomment first conditional to turn off the redirection # RewriteCond %{REQUEST_URI} ^$a RewriteCond %{REQUEST_URI} !maintenance.html RewriteCond %{REQUEST_FILENAME} !(styles|images).+$ RewriteCond %{REMOTE_ADDR} !^1\.1\.1\.1$ RewriteCond %{REMOTE_ADDR} !^127\.0\.0\.1$ RewriteRule (.*) /maintenance.html [R,L]
Prevent Image Hotlinking
<IfModule mod_rewrite.c> Options -Indexes Options +FollowSymLinks RewriteEngine on RewriteCond %{HTTP_REFERER} !^https://(.+\.)?www\.SITE-NAME\.DOMAIN/ [NC] RewriteCond %{HTTP_REFERER} !^https://(.+\.)?yandex\.(.+)/ [NC] RewriteCond %{HTTP_REFERER} !^https://(.+\.)?rambler\.(.+)/ [NC] RewriteCond %{HTTP_REFERER} !^https://(.+\.)?google\.(.+)/ [NC] RewriteCond %{HTTP_REFERER} !^https://(.+\.)?(.*\.)?google\.(.+)/ [NC] RewriteCond %{HTTP_REFERER} !^https://(.+\.)?bing\.(.+)/ [NC] RewriteCond %{HTTP_REFERER} !^https://(.+\.)?(.*\.)?bing\.(.+)/ [NC] RewriteCond %{HTTP_REFERER} !^https://(.+\.)?yahoo\.(.+)/ [NC] RewriteCond %{HTTP_REFERER} !^https://(.+\.)?(.*\.)?yahoo\.(.+)/ [NC] RewriteCond %{HTTP_REFERER} !^$ RewriteRule .*\.(swf|jp?g|ti?f|gif|gif|bmp|png|pdf|mp3|wav|wmv|avi|mpeg|ogg)$ https://www\.SITE-NAME\.DOMAIN/image\.png [L] </IfModule>
Redirect a Single Page
Redirect 301 /oldpage.html https://www.example.com/newpage.html Redirect 301 /oldpage2.html https://www.example.com/folder/
Redirect Using RedirectMatch
RedirectMatch 301 /subdirectory(.*) https://www.google.com/ads/$1 RedirectMatch 301 ^/(.*).htm$ /$1.html RedirectMatch 301 ^/200([0-9])/([^01])(.*)$ /$2$3 RedirectMatch 301 ^/category/(.*)$ /$1 RedirectMatch 301 ^/(.*)/the-top-best-vietnam-tourist-destination.html(.*) /vietnam-tourist-destination.html RedirectMatch 301 ^/(.*).html/1/(.*) /$1.html$2 RedirectMatch 301 ^/manual/(.*)$ https://www.php.net/manual/$1 RedirectMatch 301 ^/dreamweaver/(.*)$ /tools/$1 RedirectMatch 301 ^/community/(.*)$ https://community.cloudflare.com/$1
Alias a Single Directory
RewriteEngine On RewriteRule ^source-directory/(.*) /target-directory/$1 [R=301,L]
Redirect an Entire Site
Redirect 301 / https://newsite.com/
Exclude URL from Redirection
This snippet allows you to exclude a URL from redirection. For example, if you have redirection rules set up but want to exclude robots.txt so search engines can access that URL as expected.
RewriteEngine On RewriteRule ^robots.txt[L]
Hidden files and directories (those whose names start with a dot .) should most, if not all, of the time, be secured. For example: .htaccess, .htpasswd, .git, .hg…
RewriteCond %{SCRIPT_FILENAME} -d [OR] RewriteCond %{SCRIPT_FILENAME} -f RewriteRule "(^|/)\."[F]
Alternatively, you can just raise a “Not Found” error, giving the attacker no clue:
RedirectMatch 404 /\..*$
Deny Access to Backup and Source Files
These files may be left by some text/HTML editors (like Vi/Vim) and pose a great security danger if exposed to the public.
<FilesMatch "(\.(bak|config|dist|fla|inc|ini|log|psd|sh|sql|swp)|~)$"> ## Apache 2.2 Order allow,deny Deny from all Satisfy All ## Apache 2.4 # Require all denied </FilesMatch>
Disable Directory Browsing
Options All -Indexes
Performance
Compress Text Files
<IfModule mod_deflate.c> # Force compression for mangled headers. # https://developer.yahoo.com/blogs/ydn/pushing-beyond-gzipping-25601.html <IfModule mod_setenvif.c> <IfModule mod_headers.c> SetEnvIfNoCase ^(Accept-EncodXng|X-cept-Encoding|X{15}|~{15}|-{15})$ ^((gzip|deflate)\s*,?\s*)+|[X~-]{4,13}$ HAVE_Accept-Encoding RequestHeader append Accept-Encoding "gzip,deflate" env=HAVE_Accept-Encoding </IfModule> </IfModule> # Compress all output labeled with one of the following MIME-types # (for Apache versions below 2.3.7, you don't need to enable `mod_filter` # and can remove the `<IfModule mod_filter.c>` and `</IfModule>` lines # as `AddOutputFilterByType` is still in the core directives). <IfModule mod_filter.c> AddOutputFilterByType DEFLATE application/atom+xml \ application/javascript \ application/json \ application/rss+xml \ application/vnd.ms-fontobject \ application/x-font-ttf \ application/x-web-app-manifest+json \ application/xhtml+xml \ application/xml \ font/opentype \ image/svg+xml \ image/x-icon \ text/css \ text/html \ text/plain \ text/x-component \ text/xml </IfModule> </IfModule>
Set Expires Headers
Expires headers tell the browser whether they should request a specific file from the server or just grab it from the cache. It is advisable to set static content’s expires headers to something far in the future.
If you don’t control versioning with filename-based cache busting, consider lowering the cache time for resources like CSS and JS to something like 1 week. Source
<IfModule mod_expires.c> ExpiresActive on ExpiresDefault "access plus 1 month" # CSS ExpiresByType text/css "access plus 1 year" # Data interchange ExpiresByType application/json "access plus 0 seconds" ExpiresByType application/xml "access plus 0 seconds" ExpiresByType text/xml "access plus 0 seconds" # Favicon (cannot be renamed!) ExpiresByType image/x-icon "access plus 1 week" # HTML components (HTCs) ExpiresByType text/x-component "access plus 1 month" # HTML ExpiresByType text/html "access plus 0 seconds" # JavaScript ExpiresByType application/javascript "access plus 1 year" # Manifest files ExpiresByType application/x-web-app-manifest+json "access plus 0 seconds" ExpiresByType text/cache-manifest "access plus 0 seconds" # Media ExpiresByType audio/ogg "access plus 1 month" ExpiresByType image/gif "access plus 1 month" ExpiresByType image/jpeg "access plus 1 month" ExpiresByType image/png "access plus 1 month" ExpiresByType video/mp4 "access plus 1 month" ExpiresByType video/ogg "access plus 1 month" ExpiresByType video/webm "access plus 1 month" # Web feeds ExpiresByType application/atom+xml "access plus 1 hour" ExpiresByType application/rss+xml "access plus 1 hour" # Web fonts ExpiresByType application/font-woff2 "access plus 1 month" ExpiresByType application/font-woff "access plus 1 month" ExpiresByType application/vnd.ms-fontobject "access plus 1 month" ExpiresByType application/x-font-ttf "access plus 1 month" ExpiresByType font/opentype "access plus 1 month" ExpiresByType image/svg+xml "access plus 1 month" </IfModule>
Set PHP Variables
php_value <key> <val>
# For example:
php_value upload_max_filesize 50M php_value max_execution_time 240