Htaccess Redirect Generator_
Tick the rules you want and copy the file. Redirects, HTTPS, www, caching, blocking, basic auth — each block comes with a comment saying what it does and where it bites.
It also checks what you built. Two rules that redirect to each other take a site down completely, and the HTTPS rule almost every generator emits loops forever behind a CDN — because Apache genuinely is serving plain HTTP once the proxy has terminated TLS.
/old → /new- Input
- A domain and a set of rules, plus redirect pairs and addresses where those are needed.
- Output
- A commented .htaccess file, and a list of anything in it that will loop, break or quietly do nothing.
- Processing
- Built and checked in this tab. Nothing is uploaded and no server is contacted.
- Limits
- It cannot see your server. Whether a module is loaded, whether AllowOverride permits these directives, and whether a rule higher up already matched are all things only your host can answer.
- The loop nobody expects
- RewriteCond %{HTTPS} off never matches behind Cloudflare or a load balancer, because TLS was terminated upstream. The rule fires on every request until the browser gives up.
The rules that look right and take the site down
Forcing HTTPS behind a CDN loops forever
The rule every tutorial gives is RewriteCond %{HTTPS} off followed by a redirect to the https:// version. It works when Apache holds the certificate. Put Cloudflare, a load balancer or any managed host in front and TLS is terminated there, so the request reaching Apache genuinely is plain HTTP — even though the visitor typed https://. The condition matches, the redirect fires, the browser comes back over HTTPS, the proxy forwards plain HTTP again, and around it goes until the browser gives up with a redirect-loop error. The fix is to read X-Forwarded-Proto, which is what the proxy sets to tell you what the visitor actually used.
A 301 outlives the mistake that caused it
A permanent redirect is cached by the browser, and in several browsers it stays cached until the user clears it by hand — not until a TTL expires, because there is no TTL. So a 301 pointed at the wrong URL keeps sending returning visitors to the wrong place long after the server has been fixed, and you cannot reach into their cache to correct it. Ship a 302 while you are still testing, switch to 301 once you are sure, and test in a fresh private window rather than the browser you have been reloading all afternoon.
Redirect is not RewriteRule
Redirect 301 /old /new matches a prefix and appends whatever came after it, so /old/deep/page lands on /new/deep/page. That is exactly right for moving a folder and a complete surprise when you meant to move one page. This page uses RedirectMatch with an anchored pattern for single pages and the prefix form only when you explicitly ask to move a folder, so the two cases stay distinct instead of one silently becoming the other.
And none of it works on nginx
There is no .htaccess on nginx and there never will be. Apache re-reads the file on every request, which is what makes per-directory overrides possible and also what makes them slow; nginx reads its configuration once at startup and never consults the filesystem for rules. A .htaccess uploaded to an nginx server is an inert text file. If your host runs nginx, or LiteSpeed in a mode that ignores overrides, these rules belong in the server configuration in a different syntax.
Tick, read the warnings, upload
- 01Set your domain and tick the rules you need. Start from a preset if one matches — "HTTPS and non-www" is what most sites want.
- 02Fill in the extra fields that appear. Redirects go one per line as old then new; the arrow is optional and a space or a comma works too.
- 03Read the panel underneath before copying. Errors mean the file will loop or break; warnings mean a rule will quietly do nothing or cost you something.
- 04Copy or download, and put the file in the directory it should govern. Test in a private window, because a 301 you have already followed is cached.
Four things people write .htaccess for
One canonical address
HTTPS and one hostname, so nothing is indexed twice.
Force HTTPS + Force non-www
proxy-aware by default
A page that moved
One URL to one URL, without dragging the subtree along.
RedirectMatch 301 ^/old/?$ /new
Redirect 301 /old /new
A section that moved
Everything under /blog to /articles, paths intact.
^/blog/(.*)$ /articles/$1
/blog/x → /articles/x
A staging site nobody should see
Basic auth over the whole directory.
a password file above the web root
with the htpasswd generator
Redirect codes, and what each one costs
| Code | Means | What to know |
|---|---|---|
301 | Moved permanently | Cached by browsers, sometimes until cleared by hand. Passes ranking signals. Hard to take back |
302 | Found — temporary | Not cached the same way and passes no ranking signal. The right choice while testing |
307 | Temporary, method preserved | Like 302 but a POST stays a POST. Matters for forms and APIs, rarely for pages |
308 | Permanent, method preserved | The 301 equivalent that does not turn a POST into a GET |
410 | Gone | For content that is not coming back. Removes it from search faster than a 404 does |
Search engines treat a 301 as a signal to move the old URL's authority; a 302 as a signal to keep indexing the old one. Getting the pair the wrong way round is the commonest SEO mistake in this file.
What each rule does, and where it bites
| Rule | Emits | Watch out for |
|---|---|---|
| Force HTTPS | RewriteCond %{HTTP:X-Forwarded-Proto} !https | The naive %{HTTPS} off form loops behind any proxy |
| Force www / non-www | A host condition and a 301 | Turning both on is an instant loop — the checker treats it as an error |
| Trailing slash | !-f and !-d guards, then a 301 | Both directions at once loops. Real files are excluded by the guards |
| Block addresses | Require not ip inside RequireAll | Apache 2.4 syntax. The old Order/Deny form has been removed |
| Hotlink protection | A referer check on image extensions | An empty referer is allowed, or direct visits and privacy tools break |
| Caching | ExpiresByType inside IfModule | Only safe with versioned filenames. HTML is deliberately left uncached |
| Compression | AddOutputFilterByType DEFLATE | Text only — images and video are already compressed |
| Password | AuthUserFile and Require valid-user | The path is a filesystem path, and the file belongs outside the web root |
Every block that depends on an optional module is wrapped in IfModule, so a host without mod_expires gets no rules rather than a 500 on every page.
Habits that avoid an outage
- Keep a copy of the working file before you change it. A syntax error in .htaccess returns 500 for the whole directory, including the page you would use to fix it.
- Test with a fresh private window. A 301 you have already followed is cached, so the browser will not even ask the server what changed.
- Use 302 while you are still deciding, and switch to 301 once the destination is settled. The temporary one is easy to take back and the permanent one is not.
- Put the password file above the web root and generate it with the htpasswd generator — a file inside the web root can often be downloaded.
- If you control the server config, move these rules into the vhost and set
AllowOverride None. Apache checks for .htaccess in every directory of every request whether one exists or not. - Check the response with
curl -Irather than the browser address bar. It shows the status code and the Location header without following anything.
Where .htaccess bites back
A syntax error takes out the whole directory
Apache returns 500 for every request under it, including any admin page you would use to fix the file. Keep a copy of the last working version somewhere you can reach without the site, and have FTP or SSH access ready before you upload a change to a production file.
It does nothing on nginx
There is no equivalent and no plugin that adds one. nginx reads its configuration at startup and never looks at the filesystem for rules, so a .htaccess uploaded there is an inert text file. The same applies to some LiteSpeed and managed-host configurations that disable overrides entirely.
A 301 is close to irreversible
Browsers cache permanent redirects, in several cases until the user clears their cache by hand. Correcting the server does not correct the copies already cached, so a 301 to a wrong URL keeps sending returning visitors there. This is why testing with a 302 first is worth the extra step.
Order matters and the file re-enters
Rules run top to bottom, and [L] stops the current pass — not the process. In a .htaccess the rewritten URL is fed back through the whole file again, which is why a rule that looks like it stops can still loop. Rules that must run first, like forcing HTTPS, belong at the top.
Long cache times are a deployment decision
Caching a stylesheet for a year is right when its filename changes on every build and wrong otherwise. Without versioned filenames there is no way to invalidate what a visitor already has, and the only remedy is waiting. Set the period to match how your assets are named, not to whatever number looks impressive.
What is generated, and what is checked
- HTTPS
- Proxy-aware by default:
X-Forwarded-Protois tested before%{HTTPS}, because the second is off behind any proxy that terminates TLS. The naive form is available and carries a warning - Single-page redirects
RedirectMatchwith^and$, so only the exact path moves. PlainRedirectmatches a prefix and would take every URL beneath it as well- Folder redirects
- A capture group carrying the remainder of the path, emitted only when you ask for a folder move rather than as a silent default
- Blocking
- Apache 2.4
RequireAllwithRequire not ip. The 2.2Order/Denysyntax is not emitted at all — it has been removed from Apache, not merely deprecated - Optional modules
- Caching and compression are wrapped in
IfModule, so a host without the module serves the site rather than a 500 on every page - Checks
- Errors are things that loop or break — two rules redirecting to each other, a redirect pointing at itself. Warnings are rules that quietly do nothing or cost something. Notes are context, including the performance cost of .htaccess itself
- What it cannot check
- Whether a module is loaded, whether
AllowOverridepermits these directives, and whether a rule higher in the file already matched. Those need the server, and this page never contacts one - Scope
- Apache only. Password files come from the htpasswd generator, crawler rules from robots.txt, and the meaning of each status code from HTTP status codes
- Network
- None from tool code. A test sweep calls every function this page uses with
fetchandXMLHttpRequestreplaced by stubs that throw, so a stray request fails the build instead of shipping. Disconnect from the network and the page still works.
Questions about .htaccess and redirects
How do I redirect a URL in .htaccess?
For one page, RedirectMatch 301 ^/old-page/?$ /new-page — the anchors matter, because plain Redirect matches a prefix and would move everything beneath /old-page too. For a whole folder, RedirectMatch 301 ^/blog/(.*)$ /articles/$1 keeps the rest of each path. Tick the matching rule above and it writes either form for you.
Why is my HTTPS redirect looping?
Because you are behind Cloudflare, a load balancer or a managed host that terminates TLS. The request reaching Apache really is plain HTTP, so %{HTTPS} off matches even when the visitor used HTTPS, and the redirect fires forever. Test %{HTTP:X-Forwarded-Proto} instead — that is what the proxy sets to report the original scheme, and it is what this page emits by default.
Should I use 301 or 302?
Reach for 302 first. It is the reversible one: browsers do not hold on to it, and search engines keep indexing the original. Switch to 301 only once the destination is settled and you want the old URL’s authority moved across, because that version gets cached — in several browsers until the user clears it by hand — and a mistake then outlives the fix.
My 301 redirect is not working. Why?
Three usual causes. The browser cached an earlier version of the redirect, so test in a private window. Another rule above it matched first and stopped processing. Or AllowOverride does not permit that directive, in which case the file is being ignored entirely — check with your host, since nothing in the file itself will tell you.
Does .htaccess work on nginx?
No, and there is no equivalent. Apache re-reads the file on every request, which is what makes per-directory overrides work; nginx reads its config once at startup. A .htaccess on an nginx server is an inert text file. The same rules have to be translated into the server configuration.
Is .htaccess slow?
Measurably, yes. Apache looks for the file in every directory along the path of every request, whether one exists or not, and cannot cache the result. If you control the server configuration, the same rules in a vhost with AllowOverride None are faster. .htaccess exists for shared hosting where you do not.
Is anything I enter here sent anywhere?
The work is JavaScript running in this tab. Every function it calls is covered by a test that stubs fetch and XMLHttpRequest to throw, so a request that slipped in would break the build rather than reach a server — and you can confirm it for yourself by disconnecting and carrying on.