Joshua's Docs - htaccess cheatsheet (apache flavor)

Some other cheatsheets



# Block indexing
Header set X-Robots-Tag "noindex, nofollow"
# Don't list files / directories
Options -Indexes
#Caching time is in seconds
	# 1 Week
	<filesMatch "\.(ico|pdf|flv|jpg|jpeg|png|gif|js|swf|svg|woff)$">
		Header set Cache-Control "max-age=604800, public"

Deny access to a directory (put code in htaccess within)

Deny from all

Typical WordPress htaccess:

# 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]
# END WordPress
# Speed up - permits concurrent reqs on same connection
<IfModule mod_headers.c>
Header set Connection keep-alive
# Custom 404
ErrorDocument 404 /custom-error.php

Setting headers (mod_headers)

Apache Docs -

General syntax:

Header set {header-name} {header-value}

Common needs:

  • Restrict Iframe embedding to same-origin
    • Header always append X-Frame-Options SAMEORIGIN

Rewriting URLs

Standard Redirects

General syntax:

Redirect {code} {from} {to}


Redirect 301 /p/other.html /other/


Some cheatsheets:

General syntax using mod_rewrite:

<IfModule mod_rewrite.c>
	RewriteEngine On
	RewriteCond {...}
	RewriteRule {...}


RewriteCond act as AND by default; if you have three RewriteCond lines and then a RewriteRule, the rule won't execute unless all three of the preceding conditions match. However, you can use the OR flag ([OR]) with RewriteCond.


Flag Short Name Description
B escape backref URI-encodes non-alphanumeric chars that were captured as part of pattern.
BNP backrefnoplus " " (literal space) is escaped to %20 instead of +
C chain Rule is chained to all following; if it does not match, all following are skipped.
CO cookie You can set a cookie as part of the redirect!

DPI discardpath causes the PATH_INFO portion of the rewritten URI to be discarded.
E E Set the value of an environmental variable

END END Terminates current round of rewrites plus blocks rewrites from other htacess files in the current scope and on the current round.

The more extreme version of [L]
F forbidden Server will return 403 (forbidden) and chain is ended.
G gone Server returns 410 (gone) and chain ended.
H handler (Advanced) sets handler for request (e.g. tell server to handle non *.php files as php)
L last Stop processing rules - end the chain.
N next Start over from the top of the chain, but with the current output of the chain as the input.

Warning: Easy to accidentally write infinite loop!
NC nocase Pattern will be parsed as case-insensitive
NE noescape Will prevent special chars from being escaped. Necessary if trying to preserve anchor link in redirect.
NS nosubreq Prevents rule from being used on subrequests
P proxy Lets you proxy requests through to another path or external host.

Should be avoided, and if proxy necessary, use ProxyPass.
PT passthrough Forces the target string (result of rule) to be treated as URI, which is necessary for things like the Redirect directive to be followed
QSA qsappend Querystring from source is copied and merged with target.

Necessary because default behavior is to drop src query if target already has one.
QSD qsdiscard Drop the querystring from the src and don't copy to target.

Necessary because default behavior is to copy qs from src to target if src has and target does not.
QSL qslast Instead of splitting path from querystring at first ?, splits at last
R redirect Returns HTTP redirect to browser. Syntax is [R=301], where status code can be 301, 302, or any valid code.

Should almost always be used in combination with L (as [R,L]) - warning from docs: "because on its own, the [R] flag prepends http://thishost[:thisport] to the URI, but then passes this on to the next rule in the ruleset, which can often result in 'Invalid URI in request' warnings."
S skip Skip a certain number of following rules. [S=number_to_skip]. Can be used to emulate "go-to" logic and branching.
T type Sets the MIME type of the response. Very similar to AddType directive.

Misc examples:

Example: Force HTTPS

# Force HTTPS
RewriteCond %{SERVER_PORT} 80 
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [R,L]

Redirect from subdomain to main

This is especially important with CPanel, as the default behavior with "addon" domains is to actually make it a subdomain of the domain set as the CPanel root (usually the first domain purchased). This makes it very easy to end up with duplicate content... see this and this.

<IfModule mod_rewrite.c>
	RewriteEngine On
	# Force to
	RewriteCond %{HTTP_HOST} ^(?:www\.)?(.+)\.mainDomain\.com [NC]
	RewriteRule (.*)$1 [R=301,L]
<IfModule mod_rewrite.c>
	RewriteEngine On
	# Force to
	RewriteCond %{HTTP_HOST} ^(?:www\.)?mail\.(.+)\.com [NC]
	RewriteRule (.*)$1 [R=301,L]

File handlers / mocking

Usually this is necessary when trying to dynamically generate images / tracking pixels. There are a few options.

For one, you can simply use a rewrite rule to route the request from /image.gif to serve image.php.

Or, the more advanced way:

  • AddHandler will let you tell the server to process a file extension with a different handler than usual.
    • To process .gif
      • AddHandler application/x-httpd-php-stable .gif
  • AddType tells the server to map extensions to a different mime type, which can also affect how it gets processed
    • Example: AddType image/png .png
    • To process .gif
      • AddType application/x-httpd-php .gif

Depending on which option you have used, you might also need to explicitly set the MIME type in your response to the incoming request. This would be code dependent, but in PHP, usually looks like header("Content-Type: image/gif")

Disable mod_security stuff for WP

<IfModule mod_security.c>
  SecFilterEngine Off
  SecFilterScanPOST Off
Markdown Source Last Updated:
Sat Dec 14 2019 10:37:33 GMT+0000 (Coordinated Universal Time)
Markdown Source Created:
Mon Aug 19 2019 17:06:24 GMT+0000 (Coordinated Universal Time)
© 2023 Joshua Tzucker, Built with Gatsby