.htaccess redirect generator
Turn a list of old → new URLs into ready-to-paste 301 rules for Apache .htaccess, Nginx, vercel.json or Netlify, plus the site-wide HTTPS and www rules that don’t loop.
.htaccess
RewriteEngine On
# Site-wide: one hop to the canonical HTTPS host
RewriteCond %{HTTPS} off [OR]
RewriteCond %{HTTP_HOST} ^www\. [NC]
RewriteRule ^ https://example.com%{REQUEST_URI} [R=301,L]
# Page redirects
Redirect 301 /old-page /new-page
Redirect 301 /blog/2019/hello https://example.com/blog/hello
# Old URLs with query strings
RewriteCond %{QUERY_STRING} ^id=12$
RewriteRule ^products\.php$ /products/blue-widget [R=301,L,QSD]Notes on the generated rules
Apache
Simple path-to-path moves use Redirect from mod_alias, which matches the start of the path and carries the rest over, so Redirect 301 /blog /news also sends /blog/post to /news/post. Old URLs with query strings (?id=12) can’t be matched by Redirect; the generator switches to mod_rewrite with a RewriteCond %{QUERY_STRING} for those and adds the QSD flag so the old query isn’t appended to the new URL. Put these rules above WordPress’s own # BEGIN WordPress block.
Nginx
Exact location = blocks are the fastest match. Query-string URLs are handled with a map on $request_uri, placed in the http block. Reload with nginx -t && systemctl reload nginx.
Vercel and Netlify
In vercel.json, "permanent": true sends a 308 and false a 307; to force exactly 301 or 302, the generator uses statusCode. Netlify’s _redirects file goes in your publish directory; rules run top to bottom and the first match wins.
Avoiding chains
If you already have redirects from an earlier migration, update them to point straight at the newest URLs instead of adding a new layer on top. Then run your old URL list through the bulk checker with the expected destinations to confirm every row is a single hop.
Questions
How do I write a 301 redirect in .htaccess?
For a single page: Redirect 301 /old-page https://example.com/new-page. For patterns or query strings use mod_rewrite: RewriteEngine On, then RewriteRule ^old-folder/(.*)$ /new-folder/$1 [R=301,L].
Where do I put the .htaccess file?
In the document root of the site (the folder that holds index.php or index.html). Rules there apply to the whole site. The server must have AllowOverride enabled and mod_rewrite loaded for RewriteRule lines.
Why does my .htaccess HTTPS redirect cause a loop?
Usually the rule has no condition, or the site sits behind Cloudflare or a load balancer that talks to Apache over HTTP, so %{HTTPS} is always off. Tick the proxy option to test X-Forwarded-Proto instead.
Should I redirect old URLs to the homepage?
No. Redirect each old URL to its closest equivalent. Google treats mass redirects to the homepage as soft 404s, so the old page’s ranking is lost anyway. If there is no equivalent, a 404 or 410 is more honest.
Sources: Apache mod_alias and mod_rewrite flags; Nginx rewrite module; Vercel project configuration; Netlify redirects.