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.

toolkit.codes/htaccess-generator
Preset
Tick a rule to build the file
UTF-8
Ready
100% LOCAL
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

  1. 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.
  2. 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.
  3. 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.
  4. 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.

Tick
Force HTTPS + Force non-www
Note
proxy-aware by default

A page that moved

One URL to one URL, without dragging the subtree along.

Emits
RedirectMatch 301 ^/old/?$ /new
Not
Redirect 301 /old /new

A section that moved

Everything under /blog to /articles, paths intact.

Emits
^/blog/(.*)$ /articles/$1
Result
/blog/x → /articles/x

A staging site nobody should see

Basic auth over the whole directory.

Needs
a password file above the web root
Make one
with the htpasswd generator

Redirect codes, and what each one costs

CodeMeansWhat to know
301Moved permanentlyCached by browsers, sometimes until cleared by hand. Passes ranking signals. Hard to take back
302Found — temporaryNot cached the same way and passes no ranking signal. The right choice while testing
307Temporary, method preservedLike 302 but a POST stays a POST. Matters for forms and APIs, rarely for pages
308Permanent, method preservedThe 301 equivalent that does not turn a POST into a GET
410GoneFor 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

RuleEmitsWatch out for
Force HTTPSRewriteCond %{HTTP:X-Forwarded-Proto} !httpsThe naive %{HTTPS} off form loops behind any proxy
Force www / non-wwwA host condition and a 301Turning both on is an instant loop — the checker treats it as an error
Trailing slash!-f and !-d guards, then a 301Both directions at once loops. Real files are excluded by the guards
Block addressesRequire not ip inside RequireAllApache 2.4 syntax. The old Order/Deny form has been removed
Hotlink protectionA referer check on image extensionsAn empty referer is allowed, or direct visits and privacy tools break
CachingExpiresByType inside IfModuleOnly safe with versioned filenames. HTML is deliberately left uncached
CompressionAddOutputFilterByType DEFLATEText only — images and video are already compressed
PasswordAuthUserFile and Require valid-userThe 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 -I rather 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-Proto is 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
RedirectMatch with ^ and $, so only the exact path moves. Plain Redirect matches 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 RequireAll with Require not ip. The 2.2 Order/Deny syntax 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 AllowOverride permits 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 fetch and XMLHttpRequest replaced 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.