17 December 2021

The mod_rewrite module lets you manipulate URLs. Among others, you can use this to deny access to a page.

Rewrite rules have a condition and rule. The condition defines what needs to be matched, and the rule tells Apache what it should do if a match is found. Both let you use regular expressions.

Example

For instance, let’s say you want to deny access to a contact form at example.com/contact. To do so you can use a rule like this:

RewriteEngine On 
RewriteCond %{REQUEST_URI} "^/contact" [NC] 
RewriteRule "^.*$" - [F,L]

The first line enables rewriting – if you forget this line nothing is rewritten. Next is the condition. In the above example I match any URL that starts with with the string /contact (the caret symbol (^) denotes the start of the string). The NC flag at the end is used to ignore the case. So, the condition matches /contact, /cOnTaCT and any other weird cases.

The rewrite rule starts with a pattern. Here, the pattern is not important – we just want to deny access to the contact form. The pattern ^.*$ matches any string, which is exactly what we want. The F flag throws a “forbidden” error, and L tells Apache to stop processing rules.

Refining the rewrite condition

You always need to think carefully about the rewrite condition. The above rule matches any URL starting with /contact. That is not necessarily what you want, as there may be other pages that start with the string. For instance, the rule also blocks a URL like /contact-your-mp:

$ curl -IL example.com/contact
HTTP/1.1 403 Forbidden
...

$ curl -IL example.com/contact-your-mp
HTTP/1.1 403 Forbidden
...

To uniquely match /contact you need to use the dollar sign to mark the end of the string. In addition, you may need to match both /contact and /contact/ (note the trailing stroke in the second string). You can do the latter by adding /?. The question mark matches the preceding character zero or one times. So, it tells Apache that there may or may not be a trailing stroke.

RewriteEngine On 
RewriteCond %{REQUEST_URI} "^/contact/?$" [NC] 
RewriteRule "^.*$" - [F,L]

Now, the contact form is blocked but the page about contacting your MP can still be accessed:

$ curl -IL example.com/contact
HTTP/1.1 403 Forbidden
...

$ curl -IL example.com/contact/
HTTP/1.1 403 Forbidden
...

$ curl -IL example.com/contact-your-mp
HTTP/1.1 200 OK
...