April 22nd, 2022

One of the nicest things you can do for yourself if your at all familiar with multi-environment development is to create an .htaccess file that will alleviate a lot of your headaches straight out of the gate. This example is a generic set of redirect and rewrite rules aimed at giving you a seamless development experience between your local, remote development, remote staging, and production environements.

Consider the following set of rules, placed at the top of an Apache .htaccess file.

# Force non-WWW for Local
RewriteCond %{HTTP_HOST} ^www\.(.*)$ [NC]
RewriteCond %{HTTP_HOST} \.local$ [NC]
RewriteRule ^(.*)$ http://%1/$1 [R=301,L]

# Force non-SSL for Local
RewriteCond %{HTTPS} on
RewriteCond %{HTTP_HOST} (.*)\.local$ [NC]
RewriteRule ^(.*)$ http://%1/$1 [R=301,L]

# Force WWW for non-Local non-IO
RewriteCond %{HTTP_HOST} !^www\.(.*)$ [NC]
RewriteCond %{HTTP_HOST} !\.io$ [NC]
RewriteCond %{HTTP_HOST} !\.local$ [NC]
RewriteRule ^(.*)$ https://www.%1/$1 [R=301,L]

# Force SSL for non-Local
RewriteCond %{HTTPS} off
RewriteCond %{HTTP_HOST} ^(.*)$ [NC]
RewriteCond %{HTTP_HOST} !\.local$ [NC]
RewriteRule ^(.*)$ https://%1/$1 [R=301,L]

As you can see from the comment lines (prefixed with the pound sign), each group of rules accomplishes a single goal. To better illustrate how this works, we can take each of the four groups and explain them individually.

Brief Explainer on Apache's Rewrite Conditions and Rules

Regex is an extremely powerful micro-language that allows for really powerful string manipulation and pattern matching. It can do more, but these are the features that we're using it for in this guide, so we'll focus on just them for now. In order of appearance we have:

  • ^: Begins With, allows you to check if the string being checked begins in a specified way.
  • \: Literal Escape, characters following a literal escape will be treated as a human-readable character, instead of a regex rule.
  • ( and ): Capture Group, rules trapped in the capture group will be held in memory so it can be used elsewhere in the rules.
  • .: Wildcard Character, matches anything once.
  • *: Length Quantifier, will match the previous character or matching rule zero or more times, as many times as possible.
  • $: Ends With, allows you to check if the string being checked ends in a specified way.
  • [NC]: Non-case Sensitive Flag, allows upper and lower case characters to mean the same thing.
  • %n: Conditional Capture Group, refers to a captured group from a RewriteCond line, starting at index 1.
  • $n: Rule Capture Group, refers to a captured group from a RewriteRule line, starting at index 1.
  • [R=301]: Redirect Type, defines the http code sent with the redirect.
  • [L]: Last Rule, defines the last rule in the chain, and causes the URL to be rewritten as the rules currently dictate.
  • !: Not Flag, when paired with ^ or $, means a string does not begin with or end with the specified rules.

Something important to note as well is that when a line fails a qualification check, the apache rewrite cursor move past any remaining RewriteCond lines and resuming processing immediately AFTER the next RewriteRule line.

# Force non-WWW for Local

This set of rules will make the site easier to work with so you don't need to worry about SEO canonization when dealing with WWW and non-WWW forms of your domain when working on a .local domain on your local environments. If you don't use the .local GTLD for your local environments, you can substitute this value for whatever you decided to use when setting your environment up.

RewriteCond %{HTTP_HOST} ^www\.(.*)$ [NC]

Line one, checks to see if the host name begins with www. and captures anything that follows, ignoring casing.

RewriteCond %{HTTP_HOST} \.local$ [NC]

Line two, checks to see if the host name ends with .local, ignoring casing.

RewriteRule ^(.*)$ http://%1/$1 [R=301,L]

Line three, captures the entire URI following the hostname, and changes the URL to what was captured in line one, appending the capture from earlier in this line, line three. It then instructs Apache to send using the L flag, the redirect header using the 301 http code.

# Force non-SSL for Local

This set of rules will make it so that you don't need to worry about installing an SSL certificate on your local development environment. A lot of times setting this up can be tricky or time intensive. These rules will allow you to selectively turn off the SSL protocol for any and all local environment requests.

RewriteCond %{HTTPS} on

Line one, checks to see if the the SSL port has been engaged for the request.

RewriteCond %{HTTP_HOST} (.*)\.local$ [NC]

Line two, checks to see if the host name ends with .local, ignoring casing.

RewriteRule ^(.*)$ http://%1/$1 [R=301,L]

Line three, captures the entire URI following the hostname, and changes the URL to what was captured in line one, appending the capture from earlier in this line, line three. It then instructs Apache to send using the L flag, the redirect header using the 301 http code.

# Force WWW for non-Local non-IO

A lot of times when hosting a production application over a domain, it's better to do so over www, since most root domain name servers don't provide CNAME flattening. Using and canonizing to WWW will prevent this issue but isn't necessarily true for all configurations and is by no means necessary. If you don't wish to serve your site over the WWW subdomain, this section can be omitted from the rules entirely.

RewriteCond %{HTTP_HOST} !^www\.(.*)$ [NC]

Line one, checks to see if the hostname does NOT begin with WWW, capturing anything that follows, while ignoring casing.

RewriteCond %{HTTP_HOST} !\.io$ [NC]

Line two, checks to see if the hostname does NOT end with .IO, ignoring casing.

RewriteCond %{HTTP_HOST} !\.local$ [NC]

Line three, checks to see if the hostname does NOT end with .LOCAL, ignoring casing.

RewriteRule ^(.*)$ https://www.%1/$1 [R=301,L]

Line four, captures the entire URI following the hostname, and changes the URL to what was captured in line one preceeded by WWW, and appending the capture from earlier in this line, line four. It then instructs Apache to send using the L flag, the redirect header using the 301 http code.

Sidebar
Loading…
Loading the web debug toolbar…
Attempt #