Redirect generator
Paste pairs of old and new URLs, one per line, separated by a comma, a tab or a space. Full URLs are fine - the domain is stripped.
Written because this site's own migration needed 271 of these. Generating them by hand is where the mistakes come from.
The two mistakes this exists to prevent
An unescaped full stop. In a regular expression . matches any
character, so a rule written for /pricing.html also matches
/pricingXhtml. Harmless until it is not. Every pattern here is escaped.
A rule with no anchor. Apache's Redirect matches by prefix and
cannot be anchored, so a rule for /shop also catches /shopping,
/shop-faq and everything else beginning the same way. That is the
failure you hear about from a customer rather than find yourself.
RedirectMatch is anchored with ^ and $, which is why it is the
default here.
The generator also refuses a URL that redirects to itself, and tells you when the same source appears twice - in which case the first rule wins and the second is dead weight.
Which style to use
| Style | Use it when |
|---|---|
RedirectMatch |
Almost always. Anchored, escaped, exact. |
Redirect |
Moving a whole directory, where prefix matching is the point. |
RewriteRule |
You are already inside a mod_rewrite block, or need conditions. |
Three things Apache will not do
A query string cannot be matched by a RedirectMatch or RewriteRule
pattern. /?p=123 needs a RewriteCond %{QUERY_STRING} before the
rule; the pattern itself only ever sees the path.
[L] does not mean "last" in a per-directory .htaccess. An internal
rewrite re-runs the whole ruleset from the top, so a rule protected only
by [L] can match its own output. Guard it with a RewriteCond instead.
A .htaccess in a subdirectory replaces its parent's rules rather
than adding to them. A rule for /cms/... written in the web root simply
does not run while WordPress ships its own file at /cms/.htaccess -
which is why migration redirects for media so often appear to do nothing
until the old install is finally removed.