The .htaccess file is Apache’s per-directory configuration. Drop a few lines in, and you control redirects, URL rewrites, access restrictions, hotlinking, error pages, and compression — without ever touching the main server config. This guide covers the directives that actually come up in everyday work, with copy-paste-ready examples.
Where to find / create .htaccess
Lives in your public_html folder (or any subfolder, applying to that folder and below). Filename starts with a dot, so it’s hidden by default. Show hidden files in File Manager Settings → “Show Hidden Files (dotfiles)”.
If it doesn’t exist: File Manager → New File → name it .htaccess (exactly, dot included).
Edit with right-click → Edit in File Manager. Or download via FTP, edit locally, re-upload.
Safety first: always test
A single broken directive in .htaccess produces a “500 Internal Server Error” on the entire site. Two habits:
- Copy before editing. Right-click the file → Copy → name backup
.htaccess.backup. Edit the original. If it breaks, rename the backup back. - Test the site immediately after any change. Load the home page and one inner page. If 500 error, undo the change.
Force HTTPS
Redirects all HTTP traffic to HTTPS:
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
Put at the top of .htaccess, before any WordPress rules.
Force www or non-www
Pick one canonical form and redirect the other:
# Force non-www (recommended for most sites)
RewriteEngine On
RewriteCond %{HTTP_HOST} ^www.(.*)$ [NC]
RewriteRule ^(.*)$ https://%1%{REQUEST_URI} [L,R=301]
# OR force www
RewriteEngine On
RewriteCond %{HTTP_HOST} !^www. [NC]
RewriteRule ^(.*)$ https://www.%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
Use one block or the other, not both. Combine with the force-HTTPS rule.
Page-level redirects
Redirect 301 /old-page https://yourdomain.com/new-page
Redirect 301 /retired-section/ https://yourdomain.com/replacement-section/
Redirect 301 /typo-in-url https://yourdomain.com/correct-url
One per line. Always use 301 (permanent) unless the redirect is truly temporary. See redirects guide.
Block hotlinking
Stop other sites from embedding your images on theirs (which costs you bandwidth):
RewriteEngine On
RewriteCond %{HTTP_REFERER} !^$
RewriteCond %{HTTP_REFERER} !^https?://(www.)?yourdomain.com [NC]
RewriteRule .(jpe?g|png|gif|webp|svg)$ - [F,NC,L]
Allows images to load when the referrer is your own site (or empty — direct URL access). Blocks when referrer is anything else.
Note: blocks Google Images and social media link previews too. If those matter, whitelist them:
RewriteCond %{HTTP_REFERER} !^https?://(www.)?google. [NC]
RewriteCond %{HTTP_REFERER} !^https?://(www.)?facebook. [NC]
RewriteCond %{HTTP_REFERER} !^https?://(www.)?twitter. [NC]
RewriteCond %{HTTP_REFERER} !^https?://(www.)?linkedin. [NC]
Add each whitelisted source as a RewriteCond above the RewriteRule.
Block bad bots
RewriteEngine On
RewriteCond %{HTTP_USER_AGENT} (AhrefsBot|MJ12bot|SemrushBot|DotBot|BLEXBot) [NC]
RewriteRule .* - [F,L]
Blocks these SEO scrapers. Add others to the pipe-separated list as needed. Returns 403 Forbidden to matched user agents.
Compliant bots respect robots.txt — use that instead. .htaccess blocking is for non-compliant ones.
Restrict access by IP
Block all but specific IPs (useful for admin areas):
# Apache 2.4 syntax
<RequireAll>
Require ip 192.0.2.1
Require ip 198.51.100.0/24
</RequireAll>
Put in .htaccess inside the folder you want restricted (e.g. public_html/wp-admin/.htaccess).
To deny specific IPs while allowing all others:
<RequireAll>
Require all granted
Require not ip 203.0.113.45
Require not ip 198.51.100.0/24
</RequireAll>
Password-protect a directory
Easier via cPanel UI (Directory Privacy), but here’s the manual version:
AuthType Basic
AuthName "Restricted Area"
AuthUserFile /home/youruser/.htpasswds/private-section
Require valid-user
The password file is generated by cPanel’s Directory Privacy tool. Browser prompts for username/password on access.
Custom error pages
ErrorDocument 404 /errors/not-found.html
ErrorDocument 500 /errors/server-error.html
ErrorDocument 403 /errors/forbidden.html
Apache serves your custom HTML for these error codes instead of the default Apache page.
Enable browser caching
Tells browsers to cache static assets for longer, reducing requests to your server:
<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 image/svg+xml "access plus 1 year"
ExpiresByType text/css "access plus 1 month"
ExpiresByType application/javascript "access plus 1 month"
ExpiresByType text/html "access plus 1 hour"
</IfModule>
If LiteSpeed Cache or another caching plugin is active, it likely handles this; redundant rules aren’t harmful.
Enable compression
<IfModule mod_deflate.c>
AddOutputFilterByType DEFLATE text/html text/css text/javascript application/javascript application/json
</IfModule>
Compresses responses before sending. LiteSpeed handles this natively; on Apache servers it’s worth enabling.
Protect sensitive files
# Block access to wp-config.php
<Files wp-config.php>
Require all denied
</Files>
# Block access to .env files
<Files .env>
Require all denied
</Files>
# Block access to .git folder
RedirectMatch 404 /.git
These files should never be web-accessible. The first two stop direct URL access; the third returns 404 for any URL containing .git/ (prevents repo exposure).
WordPress-specific .htaccess
WordPress’s default block (you’ll see this in any WP install):
# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>
# END WordPress
Handles pretty permalinks. Don’t modify between the BEGIN/END markers — WordPress regenerates this block when settings change. Add your custom rules ABOVE the WordPress section.
Order of operations
Apache processes .htaccess top-to-bottom for some directives, but RewriteRule/RewriteCond blocks evaluate together. General good practice:
- Security headers and file blocks at the top.
- Bot blocks next.
- HTTPS / www-canonical redirects.
- Page-level redirects.
- Application rules (WordPress block).
- Caching and compression at the bottom (or in own
<IfModule>blocks).
Common .htaccess issues
“500 Internal Server Error” right after editing. Syntax error somewhere. Rename your edited file to .htaccess.broken; site comes back. Compare to your backup; find the bad line.
“Rule isn’t working.” Common causes: RewriteEngine On not declared, rule order conflict, mod_rewrite not loaded (rare on iWebVault — usually loaded). Test with a simple rule first to confirm rewrite is working.
“Browser doesn’t reflect new redirect.” Browser cached the old version. 301s are cached aggressively. Test in incognito, or clear browser cache.
“AutoSSL stopped working after .htaccess change.” Possibly blocking /.well-known/. Add: RewriteRule ^.well-known/ - [L] early in the file.
“My WordPress permalinks broke.” The WordPress block got modified or removed. WordPress → Settings → Permalinks → Save (re-saving regenerates the block).
What’s next
- Redirect strategy specifically: Redirects guide.
- If you’re using LiteSpeed Cache, much of caching/compression is handled there: see LiteSpeed Cache setup.
- Error log when .htaccess goes wrong: Error logs guide.
The directives above cover 95% of what real .htaccess work involves. Copy what you need, always backup first, test immediately after every change.
Was this helpful?
Thanks for your feedback!