A redirect is a few lines in an .htaccess file, and the lines are easy to get slightly wrong. A rule that matches a page also matches nothing when the address has a query string. An https rule that is fine on one host makes an endless loop behind a CDN. A www rule followed by an https rule sends every visitor through two redirects. Most of these mistakes do not show until the site is live.
This page writes the rules for the redirects you choose, in an order that gives one redirect where it can, and then follows a list of addresses through them the way a browser would: request, redirect, request again. You see the status and the final address of each, and the line of the rule that did it. You can also paste a file you already have to find mistakes and to test it. Everything runs in your browser, nothing is uploaded, and the code behind the page makes no network requests.
How to use the Htaccess Redirect Generator: 301, HTTPS, www, and Tester
- Add the redirects you needChoose a kind of redirect: one address for the site, one page, a list of pages, a folder, a new domain, gone pages, a pattern, or the trailing slash. Add as many as you like and fill in the fields.
- Pick the typeUse 301 for a page that has moved for good, and 302 or 307 for one that is only moved for a while. 308 and 307 keep the request method. If you are not sure, 301 is the usual choice.
- Copy the rulesCopy the file or download it as .htaccess. The rules are written in the right order, with a comment above each. Put them in the .htaccess file in the root folder of your site, and keep a copy of the old file.
- Check where addresses end upThe list under the file follows each address through the rules. Look for a redirect loop, a chain of more than one redirect, or an address that is not redirected. Add your own addresses to the list.
- Test a file you already haveOpen the Test a file tab, paste your .htaccess, and add addresses. The page lists the mistakes it finds and follows each address through your rules.
Where .htaccess rules work
An .htaccess file is a configuration file for the Apache web server, read from the folder it is in and every folder below it. The Apache documentation says the directives in it apply to the directory in which the file is found and to all subdirectories, that the default value of AllowOverride is None, which means .htaccess files are ignored until the server enables them, and that if you have access to the main server configuration file you should put your configuration there instead, because httpd looks in every directory for .htaccess files and that costs time on every request. If your host runs another server, such as nginx, an .htaccess file does nothing and the rules have to be written in its own format.
Redirect or RewriteRule
Apache has two ways to redirect. The Redirect directive of mod_alias maps an old address to a new one by asking the client to fetch the resource at the new location. It takes a status such as permanent, temp, or gone, only complete path segments are matched, so /service does not match /servicefoo.txt, and extra path information is added to the new address. A request with GET parameters is redirected with its parameters. RedirectMatch is the same with a regular expression. The documentation says mod_alias handles simple tasks and that for more complicated ones, such as changing the query string, you use mod_rewrite.
RewriteRule and RewriteCond belong to mod_rewrite. Their power has a catch in an .htaccess file: the pattern is matched against only a partial path, with the directory the file is in removed from the front, so the pattern for /about is ^about$, not ^/about$. A pattern that starts with a slash never matches. The page writes patterns this way, and warns when a pasted rule does not. The two modules are separate, and the order of the lines in the file does not tell you which one runs first, so the page uses one kind in a file, and warns about files that mix them.
Which status to send
A 301 says a page has moved permanently, and a 302 says it has moved temporarily. Without a status, Redirect sends a 302, and so does a RewriteRule with R and no code, which is easy to miss. Google's documentation says permanent redirects, 301 and 308, show the new target in search results, while temporary ones, 302, 303, and 307, show the source page, and it recommends a permanent server-side redirect whenever possible.
The difference between the older and newer codes is the request method. RFC 9110 says that with a 301 or a 302 the client may change the method from POST to GET, and that with a 307 or a 308 the user agent must not change it. For a normal page, 301 and 302 are fine. For a form that posts to an address that moved, use 308 or 307.
One address for the whole site
A site is often reachable as http and https, with and without www, which gives four addresses for every page. Search engines and visitors should see one. The Apache documentation has a recipe for a canonical hostname that redirects every other host name to www, with a condition on HTTP_HOST. The page extends it with the https test, using %{HTTPS}, which holds on when the connection uses SSL or TLS, and writes a single rule: if the host is yours, and the connection is not https or the host is not the one you chose, redirect to https and the chosen host, keeping the path and the query string.
A single rule means a single redirect. Two separate rules, one for https and one for www, send a visitor who types http://example.com through two redirects. Page redirects have the same problem, so the page writes the new address in full, with your chosen scheme and host, and puts those rules before the host rule. Another host, such as an IP address or a staging name, is left alone. If your site is behind a CDN or a load balancer that handles https, the server sees plain HTTP on every request, and a rule that tests %{HTTPS} redirects forever. There is a setting that tests the X-Forwarded-Proto header instead.
Query strings
A RewriteRule pattern is matched against the path, never the query string. A rule for /page.php?id=5 written as a pattern with the question mark can never match. To match an address with a query string, you add a RewriteCond on %{QUERY_STRING}, and the page does this when the old address has a query. By default, a redirect to an absolute address includes the requested query string, and the QSD flag, for query string discard, drops it. A question mark at the end of the new address also drops the old query string, which is what a redirect from /page.php?id=5 to /products/5 needs.
Lists of redirects, chains, and loops
After a site move, you may have hundreds of old and new addresses. Paste them with an arrow, a tab, or a comma between the two, and the page writes a rule for each and checks the list. It reports an address that is redirected to itself, one that appears twice with different targets, and a chain, such as /a to /b when /b is itself redirected to /c. A chain makes a visitor wait for two redirects, and the first target should be changed to the last. A pair that redirect to each other is a loop.
How the tester works, and how it was checked
The tester reads the redirect directives of an .htaccess file in the root folder and follows an address through them: it runs the rules, and when one redirects, it requests the new address and runs the rules again, until a page is served, the redirects loop, or the browser would be sent to another site. It reads RewriteEngine, RewriteCond with the usual variables, RewriteRule with the flags R, L, END, NC, NE, QSA, QSD, F, G, and S, Redirect, and RedirectMatch. Tests of files and folders depend on your server, so the page says what it assumed.
The Apache server could not be run on the computer this page was written on, because the system blocks its program. The tester was therefore checked against what the Apache documentation states, such as the Redirect example with its query string, the canonical hostname recipe, and the way a pattern sees the path, and against combinations: every setting of the address rule, with and without a CDN, was followed from every way of reaching the site, 18 addresses for each, and 63 combinations of the other redirects were followed for loops and chains. This found a real mistake in an early version, which sent an https visitor to http when the https choice was off. It was fixed. This is a model of Apache, not Apache, so test the live site after you upload the file.
Limits and accuracy
- The rules and the tester have not been run on a real Apache server. They follow the Apache documentation, so test the live site after you upload the file, and keep a copy of the old .htaccess file.
- The tester reads redirects only: RewriteCond, RewriteRule, Redirect, and RedirectMatch. Other directives are ignored, and rules that rewrite to a script, such as a front controller, are followed as internal rewrites without running the script.
- Whether an address is a file or a folder depends on your server. The tester assumes that a name with a dot is a file and other names are folders, and says so when a rule depends on it.
- Patterns are read as JavaScript regular expressions. Apache uses PCRE, which is almost the same. A pattern that uses a feature that JavaScript does not have is skipped, and the page says so.
- The tester runs the rewrite rules before the Redirect lines, as an .htaccess file does, and warns when both are used. It treats headers, cookies, and the visitor's address as empty, except X-Forwarded-Proto.
- A redirect to another site is followed only to the first hop, because the rules of the other site are not known.
- An .htaccess file works only on Apache and servers that read its format. On nginx, the rules have to be written differently.
Frequently asked questions
How do I redirect HTTP to HTTPS in .htaccess?
Add the one-address recipe with https turned on. It writes RewriteCond %{HTTPS} off and a RewriteRule that sends the visitor to the https address with a 301. If your site is behind a CDN or load balancer, tick that box, so the rule tests the X-Forwarded-Proto header and does not loop.
What is the difference between a 301 and a 302 redirect?
A 301 says the page moved permanently, and search engines show the new address. A 302 says it moved temporarily, and they keep showing the old one. Redirect and a RewriteRule with R both send 302 unless you give a code, so write 301 for a page that moved for good.
Why does my redirect not work when the address has a query string?
A RewriteRule pattern is matched against the path only, and Redirect does not match a query string either. To match /page.php?id=5, you need a RewriteCond on %{QUERY_STRING} and a RewriteRule for the path. The page writes both when the old address has a query.
Why do I get a redirect loop?
A rule sends the visitor to an address that the same rule redirects again. A common cause is an https rule behind a CDN that terminates https, so the server always sees http. Another is two rules that redirect to each other. The tester follows the redirects and shows the loop.
Where do I put the .htaccess file?
In the root folder of your site, which is often called public_html or www, on an Apache server that allows .htaccess files. Put the new rules above the rules that are already there, and keep a copy of the old file in case of a mistake.
Can I redirect an old domain to a new domain?
Yes. Use the new domain recipe on the old site. It redirects every address to the same path and query string on the new site, with the type you choose. Use 301 for a move that is permanent, and keep the old domain registered so the redirects keep working.
Is my file uploaded?
No. The rules are written and tested in your browser, and the code behind the page makes no network requests. Nothing is saved, so copy the file before you close the page.
Research and references
This page was written and checked against the sources below.
- Apache HTTP Server: mod_alias (Redirect, RedirectMatch)
- Apache HTTP Server: mod_rewrite (RewriteRule, RewriteCond)
- Apache HTTP Server: RewriteRule flags
- Apache HTTP Server: Redirecting and remapping with mod_rewrite
- Apache HTTP Server: .htaccess files
- RFC 9110: HTTP Semantics, Redirection 3xx
- Google Search Central: Redirects and Google Search

