1001Ferramentas
πŸ”Generators

.htaccess RewriteRule Generator

Generate RewriteRule (mod_rewrite) rules for .htaccess. Includes [L,R=301,QSA] flags and regex capture groups.


  

mod_rewrite in .htaccess: internal rewrites, flags, RewriteCond, and the patterns every developer should memorize

Apache's mod_rewrite is a small regex-based URL processor that runs on every request. Unlike a plain redirect, a rewrite is internal: the URL changes inside the server, but the browser keeps seeing the original address β€” pretty URLs, hidden file extensions, SPA fallbacks, and reverse-proxy hops are all rewrites under the hood. Externally visible 301/302 hops are rewrites with the [R] flag added on top.

This generator emits a single RewriteRule for the pattern/substitution pair you typed; the reference below covers the full syntax, every flag worth knowing, the RewriteCond variables you will use most often, the common patterns (WordPress, SPA fallback, maintenance mode, pretty URLs), and the performance trade-offs of running rules from .htaccess.

Syntax: RewriteEngine, RewriteCond, RewriteRule

RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php?route=$1 [QSA,L]

RewriteCond lines stack like an AND chain and apply only to the next RewriteRule. The !-f / !-d tests ("not a file", "not a directory") are the classic guard so static files and real directories bypass the front controller.

Flags cheat sheet

  • [L] β€” last; stop processing further rules in this pass.
  • [R=301] β€” emit an external 301 redirect (any 3xx code accepted).
  • [QSA] β€” query string append; merge the original query with the new one.
  • [NC] β€” no case; case-insensitive pattern match.
  • [NE] β€” no escape; do not URL-encode special characters in the substitution.
  • [F] β€” forbidden; return 403 without writing the new URL.
  • [G] β€” gone; return 410 (use to retire URLs permanently).
  • [P] β€” proxy; pass the request through to a backend (requires mod_proxy).
  • [E=var:val] β€” set an environment variable visible to PHP and the access log.

Common patterns

# Pretty URLs: /product/42 -> product.php?id=42
RewriteRule ^product/(\d+)$ product.php?id=$1 [L]

# Hide .php extension
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^([^.]+)$ $1.php [L]

# Single-page app fallback (Vue, React, Angular)
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.html [L]

# Maintenance mode (allow your own IP)
RewriteCond %{REMOTE_ADDR} !^198\.51\.100\.42$
RewriteCond %{REQUEST_URI} !^/maintenance\.html$
RewriteRule (.*) /maintenance.html [R=503,L]

# Subdomain to subdirectory: blog.example.com -> example.com/blog
RewriteCond %{HTTP_HOST} ^blog\.example\.com$ [NC]
RewriteRule (.*) /blog/$1 [L]

RewriteCond variables and operators

Useful variables: %{REQUEST_URI}, %{REQUEST_FILENAME}, %{HTTP_HOST}, %{HTTPS}, %{HTTP_USER_AGENT}, %{QUERY_STRING}, %{TIME_HOUR}, %{REMOTE_ADDR}. Test operators: ! (negate), = (string equality), </> (lexicographic), -d (is directory), -f (is file), -l (is symlink), -s (size > 0). Combine flags after the pattern with [NC,OR] when you need a logical OR between two conditions.

Performance and debugging

Apache reads every .htaccess from the URL's folder up to the document root on each request, so a deep tree with overrides adds latency. When you control the virtual host config, move the rules into <Directory> with AllowOverride None for a measurable speedup. For debugging, raise the log temporarily with LogLevel rewrite:trace3 β€” every matched rule, captured group, and substitution is printed to the access log. Tools such as htaccess.io and htaccess-checker.com let you dry-run rules in a browser.

FAQ

Rewrite or redirect β€” which one do I want? Use a rewrite when the URL should change only inside the server (pretty URLs, SPA routing). Use a redirect ([R=301]) when the browser address bar must change too (canonical host, HTTPS, retired URL).

Are .htaccess files slow? Yes, slightly β€” they are re-read on every request. The fix is to move the rules into the virtual host config and turn AllowOverride off. The behaviour stays identical, only the per-request stat() calls go away.

How do I debug a rule that does not match? Temporarily set LogLevel alert rewrite:trace3 in your virtual host. The access log will print the full rewrite trace: which rules ran, what each capture group held, and the final URL. Remember to lower the level afterwards β€” trace3 is verbose.

Why is the regex order important? Rules are processed top-to-bottom, and [L] only stops the current pass β€” internal rewrites can re-enter the pipeline. Place the most specific rules first and the catch-all (e.g. SPA fallback) last so the first match is the right one.

Related Tools