Setting Up an .htaccess File Without Breaking the Site
One file, read on every request, able to redirect anything or return 500 for everything. Here is what it does, where it belongs, and how to test a change safely.
What an .htaccess File Actually Is
It is a plain text configuration file that Apache reads per directory. Drop one in a folder and its rules apply to that folder and everything beneath it, without restarting the server and without touching the main config. That is the whole appeal: on shared hosting you rarely get access to the main config, and .htaccess is the part they hand you.
The tradeoff is cost and blast radius. Apache checks for the file on every single request, in every directory along the path, and a syntax error takes down the whole site rather than one page. Rules in the main server config always win over rules in a per-directory file, which is worth remembering when a directive appears to do nothing. Apache's htaccess howto makes the case for moving rules into the vhost once you can.
Where the file goes
Put it in your document root, the folder that holds index.php or index.html. Name it exactly .htaccess: leading dot, no extension, no .txt on the end. Windows editors love to append .txt silently, so check the filename after uploading rather than before.
A second .htaccess deeper in the tree overrides the parent for its own subtree. That is useful for locking down one folder, and confusing when you forget it exists six months later.
Five steps to ship a change safely
- Back up the current file by downloading a copy. Do not rename it in place:
.htaccess.bakleft in the web root is still readable over http, and it often contains paths you would rather not publish. - Add one block at a time. If something breaks you want to know which block did it.
- Load the site in a private window. A cached 301 from an earlier attempt survives your edits and produces very convincing false results.
- Watch the redirect chain, not just the final page. One hop is right. Two or more means two rules are firing in sequence.
- If you get a 500, the last block needs a module that is not loaded, or has a typo. The Apache error log names the exact line.
When it is live, confirm what the server really sends with an outside check such as indexcheck.tools, which reads the response headers and redirect chain rather than trusting the config.
Force HTTPS without an infinite loop
The naive rule checks %{HTTPS} !=on and redirects. Behind Cloudflare, a load balancer, or any proxy that terminates TLS and then talks to the origin over plain http, that test is always true. Browser goes to https, proxy forwards http, rule fires again, and the loop never ends.
The fix is a second condition on %{HTTP:X-Forwarded-Proto}, which the proxy sets to tell the origin what the visitor actually used. Both conditions have to be true before the redirect fires, so the loop cannot start. Put this rule above everything else in the rewrite block, because a canonical host redirect running first costs your visitors an extra round trip. The mod_rewrite documentation covers what each rule flag changes.
301 or 302, and why the difference matters
A 301 says the move is permanent. Search engines pass ranking signals to the new URL, and browsers cache the response hard, sometimes for months, sometimes until the user clears their cache by hand. A 302 says the old URL is coming back, so nothing transfers and nothing sticks.
| Situation | Use | Why |
|---|---|---|
| Old page replaced by a new one | 301 | Signals move to the new URL |
| Domain change | 301 | Permanent, and needed for the old domain to stop ranking |
| A/B test or seasonal landing page | 302 | The original URL comes back |
| Maintenance window | 302 or 503 | Nothing has moved permanently |
| You are still testing the rule | 302 | A wrong 301 sticks in browser caches |
Test with a 302, confirm the destination, then switch to 301. Google's guidance on how redirects are handled in Search spells out what each status means for indexing.
www or non-www: pick one and stay there
Both hostnames can serve the same site. If both answer, every page has two addresses, and analytics, cookies, HSTS scope and CDN caching all get messier than they need to be. Choose one, redirect the other, keep the choice for the life of the domain.
Neither is better for ranking. Non-www is shorter and reads well. The www version gives you a hostname you can point at a CDN with a CNAME, which a bare domain cannot always do, and it keeps cookies off your subdomains. Switching on both redirects at once would produce a loop, so the generator makes it a single choice: tick the canonical hostname rule, then pick a direction.
Apache 2.4 syntax, and where 2.2 differs
Access control changed in 2.4. The old Order, Allow from and Deny from directives moved to mod_access_compat, and modern configs use Require from mod_authz_core instead. A rule written for 2.2 can fail silently on 2.4 or throw a 500, depending on whether the compat module is loaded.
| Goal | Apache 2.4 | Apache 2.2 |
|---|---|---|
| Allow everyone | Require all granted | Order allow,denyAllow from all |
| Deny everyone | Require all denied | Order allow,denyDeny from all |
| Block one address | Require not ip 203.0.113.42 | Deny from 203.0.113.42 |
| Allow only one address | Require ip 203.0.113.7 | Order deny,allowDeny from allAllow from 203.0.113.7 |
Everything the generator writes uses the 2.4 form, with the 2.2 equivalent commented underneath each access block. Not sure which version you are on? Run apache2 -v or httpd -v, or read the Server response header. Apache's 2.2 to 2.4 upgrade guide covers the rest of the changes.
Ready to build one
Open the rule generator, pick a preset close to your setup, and adjust from there. Anything still unclear is probably covered on the FAQ page, and the about page explains why the whole thing runs in your browser.