← Back to Apache Course | Chapter 3: Modules | Lesson 1 of 5

mod_rewrite

mod_rewrite is Apache's URL-rewriting engine -- it lets you rewrite an incoming request to a different internal URL based on pattern-matching rules, which is how sites turn /product.php?id=42 into a clean /products/42 in the address bar.

Enabling the Module

mod_rewrite isn't always on by default. On Ubuntu/Debian, enable it with sudo a2enmod rewrite and reload Apache; on RHEL-family systems it's usually compiled in and just needs LoadModule rewrite_module modules/mod_rewrite.so uncommented in the config.

RewriteEngine and RewriteRule

RewriteEngine On turns rewriting on for that scope (VirtualHost, Directory, or .htaccess). Each RewriteRule pattern substitution [flags] then matches the requested path against a regular expression and, if it matches, replaces it with the substitution. For example, RewriteRule ^products/([0-9]+)/?$ product.php?id=$1 [L] sends /products/42 internally to product.php?id=42.

RewriteCond: Rewriting Conditionally

RewriteCond adds a condition that must be true immediately before the RewriteRule below it applies -- checking things like the request's scheme, host, or whether a file already exists. A very common pattern forces HTTPS: RewriteCond %{HTTPS} off followed by a rule that redirects to the https:// version of the same URL.

Common Flags

Flags in [brackets] change how a rule behaves. [L] (last) stops processing further rules once this one matches. [R] or [R=301] issues an actual browser redirect instead of an internal rewrite, with the number setting the HTTP status code. [NC] makes the pattern case-insensitive. [QSA] appends the original query string to the rewritten URL instead of discarding it.

Warning: Forgetting [L] lets Apache keep evaluating rules after a match, which can rewrite the URL a second time in a way you didn't intend -- almost every real-world rule set needs it.

Example: Clean URLs and forcing HTTPS with mod_rewrite

apacheconf
RewriteEngine On

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

# /products/42 -> product.php?id=42
RewriteRule ^products/([0-9]+)/?$ product.php?id=$1 [L,QSA]
{# Flagged by hand after confirming a runner can't handle this example (a shell command / go.mod file stored as a TopicExample, a language feature the configured runner version doesn't support, or output that blows a runner's sandbox limit) -- see TopicExample.norun. Never render the run button for these, regardless of language, since it would just fail at execute_code (or worse, hang the Judge0 queue on a submission that can never finish cleanly). #}

⚠️ This example can't run in the browser editor. Try it in your own local environment instead.

{# common_mistakes/chapter_summary/browser_support: on Hindi pages the view already swaps in the hi_ translation fields (or blanks these out if untranslated), so this renders correctly for both languages without a lang_code check here. #}
Common Mistakes
  1. Forgetting RewriteEngine On at the top of the scope -- every RewriteRule below it is silently ignored without it.
  2. Leaving off the [L] flag, letting a later rule further rewrite a URL that already matched, producing confusing double-rewritten results.
  3. Writing rules directly in .htaccess when AllowOverride doesn't permit FileInfo for that directory, so the rules are parsed but never actually take effect.
🔒

Chapter Quiz — Complete all 5 topics to unlock

0/5 topics done

Complete these topics first:

Login to run this code

C/C++/Java/PHP execution requires a free account. Your code is saved — you'll land right back in the editor after logging in.