Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

iTechGuides is reader-supported. When you buy through links on our site, we may earn an affiliate commission. As an Amazon Associate I earn from qualifying purchases. Learn more

Apache’s mod_rewrite changes how request URLs are mapped to resources. An internal rewrite serves a different file or application route while the browser keeps the original URL; an external redirect sends a 3xx response and makes the browser request a new URL. The basic switch is RewriteEngine On, followed by ordered RewriteRule directives and, when needed, RewriteCond conditions.

This guide shows how to write rules in virtual-host or main-server configuration and in .htaccess, how to choose flags, how to route requests without loops, and how to avoid open redirects, proxy abuse, and unsafe filesystem mappings.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

What mod_rewrite does

mod_rewrite is Apache’s rule-based URL manipulation engine. Apache evaluates rules sequentially. A RewriteCond placed immediately before a rule limits when that rule may run; the rule’s pattern then tests the current request path and its substitution identifies the next resource or URL. The processing model and directive order are described in Apache’s mod_rewrite introduction.

A substitution can remain inside Apache or leave the server:

Operation What the client sees Typical use
Internal rewrite The browser keeps the requested address. Apache serves another resource internally. Map a clean route such as /about to about.php, or send application routes to a front controller.
External redirect Apache returns a 3xx response. The browser changes its address and makes another request. Move old URLs, enforce a canonical path, or send users to a different public URL.

The distinction matters for bookmarks, search indexing, caching, analytics, and whether a second HTTP request occurs. Use an internal rewrite when the public URL is already correct; use a redirect when the client must learn a different URL.

Where to put the rules

Main server or virtual-host configuration

When you administer Apache, put site-wide rules in the main configuration or the relevant <VirtualHost>. These rules run in Apache’s main rewrite phase and give you clearer control over ordering and interactions with other URL-mapping directives. The remapping guide recommends this approach when you control the server configuration: Apache URL remapping.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

In this context, the pattern is matched against the URL path in the server-level phase. A leading slash may therefore be significant. Keep the pattern form consistent with the context and Apache version used by your deployment; do not copy a .htaccess pattern blindly into a virtual host.

.htaccess (per-directory context)

Use .htaccess when your hosting arrangement does not grant access to the main configuration. Apache must permit the required overrides through AllowOverride; otherwise the file is ignored or its directives are rejected. The same remapping guide identifies per-directory files as the practical option in this restricted-access case.

Per-directory processing is different: Apache removes the directory prefix before matching a RewriteRule. Consequently, a rule in the document root normally matches about, not /about; a rule in /blog/.htaccess sees the path relative to /blog/. Apache explains this distinction in its technical details for mod_rewrite.

That prefix removal is the most common reason a rule works in httpd.conf but not in .htaccess. Check both the directory containing the file and the exact string presented to the pattern before changing the regular expression.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Minimal working rules

Enable the engine once in the applicable configuration scope:

RewriteEngine On

An internal mapping can then serve a PHP resource while preserving the clean URL:

# In the document-root .htaccess example
RewriteEngine On
RewriteRule ^about$ about.php [END]

A permanent redirect changes what the browser displays:

# Old public path to its new public path
RewriteRule ^about-old$ /articles/about [R=301,END]

These are deliberately small examples. In a virtual-host rule, adjust the leading slash to match that context; in .htaccess, omit the directory prefix that Apache has already removed. The remapping documentation shows the same internal-versus-external model.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

How Apache evaluates a rule

1. The engine must be enabled

If RewriteEngine On is absent, no rewrite rules in that scope run. A server administrator may also need to load the mod_rewrite module and permit the directives in the selected context.

2. Conditions are tested before the rule

Every RewriteCond belongs to the next RewriteRule. Conditions are evaluated first, in the order written. They can inspect request metadata such as the host or method, or resource state such as whether the target filename exists.

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^ index.php [END]

This common front-controller pattern routes requests that are neither existing files nor existing directories to index.php. The exact substitution must match your application’s entry point and directory layout. Put file and directory exclusions before a broad catch-all rule so real assets are not swallowed by application routing.

3. The rule pattern is matched

The first argument of RewriteRule is a regular expression. Anchors such as ^ and $ make an exact route match; a broad expression such as .* can match nearly everything. Start with narrow, explicit patterns and widen them only when the URL design requires it.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

4. The substitution and flags determine the result

The substitution is a filesystem path, an internal URL-path, or (with redirect or proxy behavior) a destination URL. Flags in square brackets modify processing. A dash (-) means “make no substitution,” which is useful when a condition should terminate processing without changing the resource.

Internal rewrites in practice

Map a readable route to a script

Suppose visitors should request /about, while the application file is about.php. In a document-root .htaccess file:

RewriteEngine On
RewriteRule ^about$ about.php [END]

The request remains /about in the address bar. Apache internally selects about.php. No 3xx response is sent, so clients do not make a second request merely because the mapping exists.

Route dynamic paths

Capturing groups let a rule pass a path component to an application:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
RewriteRule ^article/([0-9]+)$ article.php?id=$1 [END]

Use restrictive character classes that reflect the identifiers your application actually accepts. Do not use a broad capture by default when the captured value will later be treated as a filename, option, or network destination.

Pass the result to another URL-mapping directive

The [PT] flag, documented in the RewriteRule flags reference, passes the rewritten result back through Apache’s URL-mapping phase. This is useful when a rewritten path must then be handled by a directive such as Alias. Use it only when that second mapping is intentional; otherwise an ordinary internal rewrite is simpler.

External redirects and canonical URLs

Permanent versus temporary status

[R=301] sends a permanent redirect. Browsers, intermediaries, and crawlers may cache that result, so use it only after the destination is correct. During migration or testing, a temporary redirect status is safer because it communicates that the change may be reversed. Choose the status deliberately rather than adding 301 to every redirect.

# Permanent move after the destination is verified
RewriteRule ^about-old$ /articles/about [R=301,END]

The redirect target should normally be an absolute-path URL on the same site, such as /articles/about. An absolute URL is appropriate when a deliberate cross-host move is required, but it must be constrained to a trusted destination.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Redirect only the intended host

If canonicalization depends on the host name, guard the rule with an allowlist rather than echoing arbitrary request data:

RewriteCond %{HTTP_HOST} ^(www.)?example.com$ [NC]
RewriteRule ^about-old$ https://www.example.com/articles/about [R=301,END]

Replace the example host with the hostname you administer. A redirect assembled from unvalidated input can become an open redirect. Apache states the risk plainly: “If a RewriteRule constructs a redirect URL using unvalidated user input, an attacker can craft a link that redirects visitors to a malicious site while appearing to originate from your domain.” See the Apache mod_rewrite introduction.

Conditions, exclusions, and rule order

Protect existing files and directories

Application routers should usually run after static resources have been excluded:

RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^ - [END]

RewriteRule ^ index.php [END]

The first rule stops rewriting when the request already resolves to a file or directory. The second handles the remaining paths. If your application needs a different policy—for example, to route a directory through the application—change the exclusions intentionally rather than deleting them as a troubleshooting shortcut.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Put narrow rules before broad rules

Apache processes rules sequentially. Place host canonicalization, specific legacy redirects, and static-resource exclusions before a catch-all route. If a broad rule runs first, it can prevent the later rule from ever being reached or can repeatedly transform the same request.

Combine conditions carefully

Multiple conditions normally form an AND relationship. The [OR] condition flag joins adjacent tests as alternatives, as in the file-or-directory exclusion above. Keep related conditions together so a later rule’s prerequisites are clear when you revisit the configuration.

Stopping processing: L versus END

Flag Effect When to choose it
[L] Stops the current round of rewrite processing. Use when later rules in the current pass must not run, while another per-directory pass may still be valid.
[END] Stops all per-directory rewrite processing for the current request. Use in .htaccess when you want to prevent re-entry and reduce rewrite-loop surprises.
[R=301] Sends an external permanent redirect response. Use only for a verified permanent public-URL change; combine with a termination flag as appropriate.
[PT] Passes the rewritten result back through URL mapping. Use when directives such as Alias must process the rewritten path.

These behaviors are defined in Apache’s RewriteRule flags documentation. A common loop fix is replacing an overly permissive [L] rule in .htaccess with a correctly scoped rule and [END], but termination flags cannot repair a pattern that keeps matching the wrong path.

Why rules loop

The internal target matches the same rule

An internal rewrite can cause Apache to perform another per-directory pass. If the rewritten filename still satisfies the original pattern, the rule may run again. Anchor the public route, exclude the target file, or terminate per-directory processing with [END] where appropriate.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Redirecting to the URL you are already serving

A redirect rule that produces its own input URL creates a client-visible loop. Compare the exact path, host, scheme, and trailing-slash form before issuing the redirect. Canonicalization rules should have one clear “already canonical” case that does nothing.

Mixing contexts without accounting for prefixes

A pattern copied from a virtual host into a nested .htaccess file may include a prefix that Apache has already stripped. The rule then fails, or a fallback rule catches the request and rewrites it repeatedly. Test the path as seen in that directory’s per-directory phase.

Overlapping application and static rules

If a front-controller catch-all precedes an asset exclusion, requests for CSS, JavaScript, images, or uploaded files may be routed into the application. Put exclusions first and ensure the application target itself cannot be caught by the same route.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Security rules you should not skip

Prevent open redirects

Never let an untrusted query parameter, path capture, or host header become an unrestricted redirect destination. Prefer a fixed relative path or a fixed URL on an allowlisted host. Validate any user-supplied identifier before using it in a substitution, and do not assume that escaping alone makes an arbitrary destination safe.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Do not proxy arbitrary backreferences

The [P] flag turns a rewrite into a proxy request. Apache warns against allowing user-controlled backreferences to select proxy targets because an attacker could make the server request internal or otherwise unintended services, creating a server-side request forgery (SSRF) risk. Keep proxy destinations fixed or strictly allowlisted, and apply normal proxy access controls.

Constrain filesystem mappings

A broad capture such as (.+) can accept far more input than a route needs. When a captured value contributes to a filesystem path, use restrictive character classes, validate it at the application layer, and rely on appropriate <Directory> protections. Do not treat a rewrite expression as a substitute for filesystem authorization.

Separate routing from authorization

A rewrite can select a resource; it does not by itself grant a user permission to read or modify that resource. Keep authentication, authorization, and directory protections in their proper directives and application layers.

Debugging a rule that does not work

  1. Confirm the module and scope. Verify that mod_rewrite is loaded, RewriteEngine On is in the active server, virtual-host, or directory scope, and the host permits the directives.
  2. Check the context. Determine whether the rule is in main configuration, a virtual host, the document root, or a nested directory. Rewrite the pattern for that context’s path prefix.
  3. Test the smallest exact rule. Temporarily match one known path, such as ^about$, and use a harmless internal target. Add conditions only after the basic match succeeds.
  4. Inspect the response. Run a header request such as curl -I https://your-host.example/about. A 3xx response indicates a redirect; a 200, 403, or application response may indicate an internal rewrite or a later authorization failure. Follow redirect locations deliberately rather than hiding them with automatic following.
  5. Validate Apache configuration. On systems that provide it, run the administrator’s configuration test command (commonly apachectl -t) before reloading. Fix syntax errors first.
  6. Check the effective logs. Review the virtual host’s error and access logs, especially after changing conditions or flags. A rule can be syntactically valid yet never match because a condition is false.
  7. Look for a second pass. If you see repeated 3xx responses or the same internal target appearing repeatedly, inspect broad patterns, missing exclusions, and termination flags. Test with a temporary redirect while diagnosing; do not leave a mistaken permanent redirect cached by clients.

Deployment checklist

  • Decide whether the requirement is an internal rewrite or an external redirect before writing the substitution.
  • Use main or virtual-host configuration when you control Apache; use .htaccess only when that is the permitted deployment model.
  • Confirm AllowOverride permits the directives needed by the .htaccess file.
  • Write patterns for the actual context, remembering that per-directory processing removes the directory prefix.
  • Place specific redirects and existing-file/directory exclusions before broad application routes.
  • Choose [L] or [END] based on whether another per-directory pass is acceptable.
  • Use [R=301] only after a permanent destination has been verified; use a temporary status while testing.
  • Use [PT] only when another URL-mapping directive must process the result.
  • Keep redirect hosts and proxy targets fixed or allowlisted; never derive them freely from user input.
  • Restrict captured path characters when values reach the filesystem or another security-sensitive subsystem.
  • Validate configuration, test representative URLs with headers, and inspect logs before and after reload.

A practical decision framework

Requirement Recommended approach Reason
Expose a clean URL for an existing script Internal RewriteRule The browser keeps the clean address while Apache serves the implementation file.
Retire an old public URL External redirect, usually temporary during testing and permanent after verification Clients and crawlers learn the replacement address.
Route all non-file requests to an application File/directory exclusions followed by a front-controller rule Static resources remain directly accessible while application routes are centralized.
Run rules on a managed server Virtual-host or main-server configuration You control processing order and avoid per-directory prefix surprises.
Run rules on hosting without server-config access Document-root or nested .htaccess, if overrides are allowed Per-directory configuration is available without changing the global server file.

Once the rule’s purpose, context, and termination behavior are explicit, most mod_rewrite problems become ordinary matching or ordering errors rather than mysterious Apache behavior.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.