Skip to main content

.htaccess: Redirects, Rewrite Rules, and Site Protection

Hosting & cPanel · 15.07.2025 · 5 min read
Illustration for “.htaccess: Redirects, Rewrite Rules, and Site Protection”

The .htaccess file lets you configure Apache directly in the site folder without access to the server configuration. It is located in public_html/.

⚠️ An error in .htaccess causes a 500 error for the entire site. Always make a backup before editing.

301 Redirects

RewriteEngine On

# From the old page to the new one
Redirect 301 /old-page.html /new-page

# Redirect an entire folder
RedirectMatch 301 ^/old-section/(.*)$ /new-section/$1

www ↔ non-www

RewriteEngine On

# Redirect ALL requests to www
RewriteCond %{HTTP_HOST} !^www\. [NC]
RewriteRule ^(.*)$ https://www.%{HTTP_HOST}/$1 [R=301,L]

# Or the opposite — remove www
RewriteCond %{HTTP_HOST} ^www\.(.+)$ [NC]
RewriteRule ^(.*)$ https://%1/$1 [R=301,L]

HTTP → HTTPS Redirect

RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]

Password-Protect a Folder

# Create the .htpasswd file:
# htpasswd -c /home/user/.htpasswd adminuser

# In the folder's .htaccess:
AuthType Basic
AuthName "Protected Area"
AuthUserFile /home/user/.htpasswd
Require valid-user

Blocking IP Addresses

# Block a specific IP
Deny from 203.0.113.42

# Allow only your own IP
Order deny,allow
Deny from all
Allow from 203.0.113.10

Caching Static Files

<IfModule mod_expires.c>
ExpiresActive On
ExpiresByType image/jpeg "access plus 1 year"
ExpiresByType image/png "access plus 1 year"
ExpiresByType image/webp "access plus 1 year"
ExpiresByType text/css "access plus 1 month"
ExpiresByType application/javascript "access plus 1 month"
</IfModule>
✅ After making changes to .htaccess, check the site in incognito mode. If you get a 500 error — restore the previous version via cPanel → File Manager.

Rule Order Matters

Combining the HTTPS redirect and the www redirect carelessly in one file can easily produce a double redirect or a loop — Apache applies rules top to bottom and stops only at the first rule whose L flag fires.

# Correct order: HTTPS first, then www,
# so the browser doesn't do two separate redirects in a row
RewriteEngine On

RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://www.%{HTTP_HOST}/$1 [R=301,L]

RewriteCond %{HTTP_HOST} !^www\. [NC]
RewriteRule ^(.*)$ https://www.%{HTTP_HOST}/$1 [R=301,L]

Both conditions lead to the same final address with www and HTTPS at once, so the browser gets a single redirect instead of two in sequence.

Testing Rules Safely

Check every significant change with a saved backup copy next to it — a rule can be rolled back instantly instead of waiting to restore it through the hosting panel.

# Save a working copy before editing
cp .htaccess .htaccess.bak

# If the site returns 500 after an edit, restore the previous version with one command
cp .htaccess.bak .htaccess

Common .htaccess Errors

SymptomCause
500 Internal Server Error right after savingA syntax error in a directive: a missing space between RewriteCond and its pattern, a stray quote, or an invalid flag like [R=301,L,X]
RewriteRule: bad flag delimitersThe flags inside the square brackets are missing a comma between them, or have a stray space inside the brackets
ERR_TOO_MANY_REDIRECTS in the browserThe www ↔ non-www rule and the HTTP → HTTPS rule conflict in order, especially when Cloudflare's Flexible SSL is already active and the repeated rule bounces the request back and forth
Invalid command 'ExpiresActive'The directive is used without the <IfModule mod_expires.c> wrapper, and the module is disabled on the account — Apache does not understand the command and returns 500
Basic Auth does not prompt for a passwordThe .htpasswd file path is wrong or the Apache process lacks read permission on the file

When .htaccess Is Not the Right Tool

  • The site runs on Nginx — only Apache reads .htaccess; on Nginx the rules are rewritten into the virtual host config on the provider's side
  • The rules pile up and live inside subfolders — with AllowOverride All, Apache scans the directory tree on every request, which noticeably slows responses
  • You need settings that AllowOverride does not permit (process limits, core modules) — .htaccess only overrides what the hosting explicitly allows
  • Changes must apply to hundreds of domains at once — keeping an identical file in every folder is awkward and easy to let drift out of sync

Verifying the Result

After editing, always check the actual HTTP response, not just how the page looks in a browser — the status code is not always visible, especially when a cache is involved. If the redirect rules are part of an HTTPS migration, see also the article on setting up an HTTPS redirect; for a 500 error, the causes are covered in the article on diagnosing error_log.

# Check the response code and the redirect's destination
curl -I http://example.com/old-page.html

# Confirm the caching headers were applied to static assets
curl -I https://example.com/style.css | grep -i cache-control
Was this article helpful?
← Back to Knowledge Base Ask Support