Setting Apache environment variables with mod_rewrite

October 26, 2009

Apache’s mod_rewrite module is most commonly used to generate clean URLs, by covertly “rewriting” incoming paths to different internal paths. (Drupal rewrites /some/url as index.php?q=some/url and works off the querystring, for example.) It can also be used to overtly redirect users with the same kind of rules.

But mod_rewrite’s flexibility allows it to be used for a whole lot more than simple URL handling. Regex patterns can be tested to set environment variables, for example (the kind retrieved with PHP’s getenv(). I recently started using rewrite rules in my Drupal root .htaccess files as an alternative to my Environments module, for organizing all my server- and subdomain-differentiated logic in a central location.

This functionality is documented reasonably well at Apache.org; see the "Documentation" section at the bottom.

Here are some examples I’m using. They’re all wrapped in:

  <IfModule mod_rewrite.c>
  RewriteEngine On
  ...
  </IfModule>

This sets environment variables for each server environment:

  ## set env vars for domains
  ## dash indicates no subst
  ## '.*' (any string) is critical!! thanks http://www.askapache.com/htaccess/crazy-advanced-mod_rewrite-tutorial.html
  #  siteenv = local, live, dev
  RewriteCond %{SERVER_NAME} ben.local
  RewriteRule .* - [E=siteenv:local]

  RewriteCond %{SERVER_NAME} ^benbuck.net$ [OR]
  RewriteCond %{SERVER_NAME} ^benbuckman.net$
  RewriteRule .* - [E=siteenv:live]

  RewriteCond %{SERVER_NAME} ^dev.benbuck.net$
  RewriteRule .* - [E=siteenv:dev]

Uncomment this for debugging:

    ## stop all following rules on local (for debugging)
    ##  RewriteCond %{ENV:siteenv} local
    ##  RewriteRule .* - [L]

This rule redirects tech.benbuck.net to benbuckman.net/tech. It excludes my local and dev sites, redirects ([R]), and stops checking for other rules ([L]):

  # tech home
  RewriteCond %{SERVER_NAME} ^tech.benbuck
  RewriteCond %{ENV:siteenv} !local
  RewriteCond %{ENV:siteenv} !dev
  RewriteRule ^$ http://benbuckman.net/tech [R,L]

This powers the "shortcut" URLs which I use to tweet my posts. !-f and !-d exclude valid file and directory paths, respectively.

  RewriteCond %{SERVER_NAME} ^benbuck.net$ [OR]
  RewriteCond %{SERVER_NAME} ^benbuckman.net$
  RewriteCond %{REQUEST_FILENAME} !-f
  RewriteCond %{REQUEST_FILENAME} !-d
  RewriteRule ^b/([0-9]*)/?$ http://benbuckman.net/node/$1  [L]

On a multi-site setup, RewriteRules can send /files to /sites/somesite/files based on the subdomain. (This only works for HTTP-requested paths, however; unlike symlinks, these rules have no effect on include()‘d paths, for instance.)

The next thing I’d like to try is virtual document roots (*.domain) that map to different folders.

If you have any other cool mod_rewrite tips, or see any errors in my examples here, please post a comment!