Joomla’s .htaccess file is an Apache (and LiteSpeed) per-directory config that enables URL rewriting, blocks common query-string exploits, and optionally hardens headers and compression. Joomla does not activate it by default. It ships htaccess.txt in the site root. You rename that file to .htaccess, then turn on Search Engine Friendly URLs and Use URL Rewriting in Global Configuration. The same workflow applies on Joomla 3, 4, 5, and 6. Only the stock file contents have grown over time (notably Web Services /api/ routing from Joomla 4 onward).
This guide is written for production agencies and serious site owners. It goes beyond “rename the file and hope.” You get a version matrix, the real rule order, FastCGI Authorization quirks, OpenLiteSpeed restarts, Cloudflare HTTPS loops, double-gzip failures, subdirectory RewriteBase, sensitive-path locks, and a verification checklist with curl. For a dedicated redirect playbook (www, HTTPS, com_redirect), use Joomla Redirect Guide. For upgrades that may overwrite or diverge from stock rules, see Joomla Upgrade.
Official anchors: Enabling SEF URLs on Apache, Joomla user guide: htaccess.txt, and the live stock file in the Joomla CMS repository.
What you will learn
- Why Joomla ships
htaccess.txt instead of an active .htaccess
- What changed between Joomla 3, 4, 5, and 6 stock files
- Exact Global Configuration settings that pair with Apache rewriting
- The rule order that decides whether your 301s, API calls, and SEF URLs work
- Security headers, exploit blocks, and extra path locks most blog posts skip
- Speed pitfalls: double gzip, Brotli flags, and CDN cache poisoning on 301s
- nginx and IIS alternatives when
.htaccess is the wrong tool
- A field checklist to prove the file is loaded before you blame Joomla
Infyways builds and hardens Joomla estates end to end: Joomla development · Joomla website optimization · Joomla support and maintenance.
Quick answer: do you need .htaccess?
| Goal |
Need .htaccess? |
Notes |
SEF URLs with index.php still visible |
No |
Enable Search Engine Friendly URLs only |
Remove index.php from public URLs |
Yes (Apache/LiteSpeed) |
Also set Use URL Rewriting = Yes |
Web Services /api/... pretty paths (J4+) |
Yes |
Stock file routes /api/ to api/index.php |
| Block base64 / script / GLOBALS query tricks |
Yes |
Built into stock exploit section |
| Force HTTPS or www ↔ bare domain |
Often yes |
Put rules in the Custom redirects zone; details in redirect guide |
| Site runs on nginx only |
No |
Use nginx try_files (no .htaccess) |
| Site runs on IIS |
Use web.config |
Rename web.config.txt instead |
Version matrix: what the stock file actually changed
Always copy rules from your installed htaccess.txt, not from a random gist. After a major upgrade, diff your live .htaccess against the new htaccess.txt.
| Topic |
Joomla 3.10 era |
Joomla 4.x |
Joomla 5.x / 6.x (current line) |
Rename htaccess.txt → .htaccess |
Required for rewrite |
Same |
Same |
Options +FollowSymlinks / -Indexes |
Yes |
Yes |
Yes |
| Query-string exploit blocks |
Yes |
Yes |
Yes |
HTTP_AUTHORIZATION env fix |
Present |
Present |
Present (critical for API tokens on FastCGI) |
Route /api/ → api/index.php |
No |
Yes |
Yes |
| OpenLiteSpeed “restart required” note |
Rare / absent |
Documented in file |
Documented in file |
SVG Content-Security-Policy: script-src 'none' |
Later ports vary |
Present in modern stock |
Present |
| Optional CORP / COEP header stubs |
Rare |
Commented stubs |
Commented stubs |
Precompressed .css.gz / .js.gz serve rules |
Limited / older forms |
GZIP & BROTLI section |
Same family; watch double compression |
Fallback when mod_rewrite missing |
RedirectMatch pattern |
Same idea |
Same idea |
Practical takeaway: A Joomla 3 site upgraded to 5 or 6 that still runs a 2018 .htaccess may miss /api/ routing and newer header/SVG protections. Merge forward carefully. Do not paste a 6.x file onto 3.x and assume every path exists.
How Joomla and Apache share the job
Joomla builds links. Apache rewrites requests.
- Search Engine Friendly URLs = Yes changes how Joomla generates URLs (pretty paths instead of long
option= query strings).
- Use URL Rewriting = Yes tells Joomla it is safe to omit
index.php from those links.
.htaccess + mod_rewrite catches the pretty path and internally routes it to index.php (or api/index.php) without a visible redirect.
If you enable rewriting in Global Configuration but never rename htaccess.txt, you get broken menus and 404s. If you rename the file but leave rewriting Off, index.php stays in URLs. Both switches must match the server.
Confirm overrides are allowed. Apache must permit .htaccess with something like AllowOverride All (or at least FileInfo + Options) for the site directory. Official walkthrough: SEF URLs on Apache.
Step 1: Back up, then activate the stock file
- Download a copy of the current root
htaccess.txt and any existing .htaccess.
- In FTP, SFTP, or hosting File Manager, rename
htaccess.txt to .htaccess.
- On Windows local stacks, show hidden files. A leading-dot name is easy to “lose.”
- If the host already had a custom
.htaccess, merge; do not blindly overwrite years of redirects.
- On OpenLiteSpeed, restart the web server after edits. The stock file warns that changes do not apply until restart.
Permissions: typically 644 for .htaccess is enough. Avoid 777.
Step 2: Turn on SEF and URL rewriting
In the Administrator:
- Open System → Global Configuration (or Configuration on older layouts).
- Set Search Engine Friendly URLs to Yes.
- Set Use URL Rewriting to Yes (label may say Apache mod_rewrite / URL rewriting depending on version).
- Save.
- Open the site frontend in a private window. Click several menu items. Confirm URLs lack
index.php and pages load.
Rollback if the site whitescreens or 500s: set Use URL Rewriting back to No, or rename .htaccess to htaccess.txt again. Then fix the server issue (often Options +FollowSymlinks).
Step 3: Fix the three activation failures everyone hits
FollowSymlinks causes HTTP 500
Stock file includes:
Options +FollowSymlinks
Options -Indexes
Many shared hosts already set symlink policy in the vhost and forbid changing Options in .htaccess. Symptom: instant 500 after rename.
Fix: comment the FollowSymlinks line:
# Options +FollowSymlinks
Options -Indexes
Retest SEF. If URLs work, the host already provides what rewrite needs. Some hosts prefer SymLinksIfOwnerMatch instead. Only use what your host documents.
RewriteBase for subdirectory installs
If Joomla lives at https://example.com/portal/ rather than the domain root, uncomment and set:
RewriteBase /portal/
Wrong RewriteBase produces asset 404s, login loops, or API failures that look like “Joomla bugs.”
Also check:
$live_site in configuration.php (usually leave empty unless you have a known need)
- Administrator → Global Configuration → Live Site (keep empty on most modern installs)
- Hardcoded old paths in templates or CDN settings
MultiViews quietly breaks SEF
Content negotiation (Options +MultiViews) can make Apache serve something.php or variant paths before Joomla’s rewrite runs. If pretty URLs intermittently 404 while index.php/... works, try:
Options -MultiViews
Place it near the other Options lines. Test thoroughly; hosts differ.
Anatomy: rule order is the product
Apache applies rules top to bottom. The stock Joomla layout is intentional. Custom 301s belong in the Custom redirects section, before RewriteBase and before the core SEF block. If you append redirects after RewriteRule .* index.php [L], many never fire.
Logical map of a modern stock file:
- Options (symlinks, no indexes)
- IndexIgnore
- Early headers (
X-Content-Type-Options: nosniff, optional CORP/COEP, SVG CSP)
RewriteEngine On
- Exploit blocks (query string patterns → forbid)
- Custom redirects (your HTTPS, www, legacy paths)
RewriteBase (if needed)
- Core SEF (
HTTP_AUTHORIZATION, /api/ router, site index.php router)
- Fallback if rewrite module missing (
RedirectMatch)
- GZIP section for precompressed static assets
That order is why agencies lose hours: a perfect HTTPS rule pasted at the bottom of the file does nothing useful after [L] SEF routing.
Core SEF section explained (site + API)
Modern Joomla (4+) does two internal rewrites.
Authorization passthrough (all modern lines):
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
PHP running as CGI/FastCGI often drops the Authorization header. Joomla Web Services (bearer tokens) and some extensions need this environment copy. If API calls return 401 with a valid token only on production (not on Apache mod_php), this line is the first suspect. Confirm it exists after upgrades.
API application (Joomla 4+):
RewriteCond %{REQUEST_URI} ^/api/
RewriteCond %{REQUEST_URI} !^/api/index\.php
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule .* api/index.php [L]
Without this block, /api/index.php/v1/... may work while /api/v1/... 404s.
Site application:
RewriteCond %{REQUEST_URI} !^/index\.php
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule .* index.php [L]
Physical files and folders still win (!-f / !-d). That is why /images/logo.png is not swallowed by Joomla routing.
Built-in exploit rules (what they catch)
The stock block rejects request query strings that try to:
- Smuggle
base64_encode(...) in the URL
- Inject
<script style payloads via query encoding tricks
- Set
GLOBALS or _REQUEST through the query string
Matched requests are forbidden ([F]). If a legitimate extension breaks after enabling .htaccess, temporarily comment the exploit lines to confirm, then fix the extension or narrow the pattern. Do not leave exploit rules disabled long term on a public site.
These rules are not a full WAF. Pair with host firewall, extension hygiene, and Joomla security practice.
Security hardening beyond the stock file
Prefer one owner for each concern. Joomla’s System – HTTP Headers plugin can set HSTS, frame options, referrer policy, CSP, and more. If the plugin manages a header, do not also set conflicting values in .htaccess.
Headers the stock file already leans on
X-Content-Type-Options: nosniff (stock)
- SVG-specific CSP disabling script when serving
.svg (stock)
- Optional CORP / COEP (commented; only enable if you understand cross-origin isolation)
Extra path locks agencies actually use
Add carefully after backups. Adjust if a legitimate tool needs a path.
# Deny dotfiles that are not the rewrite file itself
<FilesMatch "^\.">
Require all denied
</FilesMatch>
<Files ".htaccess">
Require all granted
</Files>
# Block common leak targets in the web root
<FilesMatch "(?i)^(configuration\.php|composer\.(json|lock)|package\.json|\.env|\.user\.ini)$">
Require all denied
</FilesMatch>
# Optional: deny web access to logs and tmp if they are web-reachable
RewriteRule ^(tmp|logs|cache)/ - [F,L]
On Apache 2.2-only fossils, Require syntax differs (Deny from all). Match your Apache major version.
Administrator and installation leftovers
- Keep
/administrator/ protected with strong passwords, 2FA, and IP allow lists at the firewall when possible.
- Remove or block leftover
/installation/ after install.
- Root
web.config.txt, README.txt, and sample files are informational; they are not secrets, but reduce noise where you can.
HTTPS and HSTS
Force HTTPS in the Custom redirects section, and account for reverse proxies:
RewriteCond %{HTTPS} !=on [OR]
RewriteCond %{HTTP:X-Forwarded-Proto} =http
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
Cloudflare Flexible SSL warning: origin may see HTTP while the browser already used HTTPS. A naive HTTPS off redirect can loop. Prefer Full (strict) between Cloudflare and origin, or always honor X-Forwarded-Proto.
Enable HSTS only after HTTPS works on every hostname you serve. Browsers remember HSTS for max-age. Mistakes hurt. Many teams set HSTS via the HTTP Headers plugin once TLS is stable.
Deep redirect patterns: Joomla Redirect Guide.
Speed: compression, caching, and the double-gzip trap
Stock GZIP section
Modern htaccess.txt can serve precompressed .css.gz / .js.gz when the client accepts gzip, set Content-Encoding, and set flags to avoid double compression with mod_deflate / Brotli.
Symptom of conflict: CSS/JS fail to load; browser console shows ERR_CONTENT_DECODING_FAILED.
Fix: comment out the entire GZIP section in .htaccess when the host or CDN already compresses those assets. The stock comments describe this exact failure.
What not to force in .htaccess on PHP-FPM hosts
Avoid php_flag / php_value directives on modern PHP-FPM or LiteSpeed setups unless the host says they work. They often 500 the site. Set PHP limits in the panel, .user.ini (when supported), or pool config instead.
Cache-Control for static media (optional)
Long-cache hashed media carefully. Do not aggressive-cache HTML document responses from Joomla if you rely on logged-in personalization without a proper cache layer (Joomla page cache, Varnish, or CDN rules). Wrong HTML caching creates “I updated the article but the site shows the old one” tickets that look like .htaccess bugs and are not.
Custom redirects: placement and ownership
Inside the stock markers:
## Begin - Custom redirects
# your rules here with [R=301,L]
## End - Custom redirects
Use this zone for:
- HTTP → HTTPS
- www ↔ apex
- Permanent moves that still return 200 under the old path
- Stripping legacy
index.php/ prefixes at the edge
Use com_redirect when the old URL already 404s inside Joomla. Server rules win for anything that never reaches a Joomla 404. Full decision tree: joomla-redirect.
CDN note: once a 301 is cached at the CDN or browser, fixing the rule is not instant. Use short test TTLs on staging, and curl -I against origin when debugging.
Subdirectory, reverse proxy, and “two CMSs” layouts
Joomla in a subfolder
RewriteBase /folder/ plus correct menu domains. Test /folder/api/ if you use Web Services.
Reverse proxy / container
Terminate TLS at the proxy. Pass X-Forwarded-Proto and often X-Forwarded-For. Align Joomla behind the proxy so generated URLs stay HTTPS.
Joomla under a parent .htaccess (WordPress at root, Joomla in /cms)
Parent rewrite rules can steal requests before child .htaccess runs. You may need parent exceptions:
RewriteRule ^cms/ - [L]
Order and specificity matter. This layout is a frequent agency footgun.
When .htaccess is the wrong file
| Server |
Do this instead |
| nginx |
try_files $uri $uri/ /index.php?$args; plus a separate /api/ location to api/index.php on J4+ |
| IIS |
Rename web.config.txt → web.config |
| Apache without AllowOverride |
Move rules into the vhost <Directory> block |
| Static export / headless only |
Edge config on the front-end host; Joomla origin still needs API routing if used |
Official nginx notes live under Joomla documentation for SEF on nginx. Do not expect .htaccess to run on nginx.
Administrator folder notes
Joomla may ship additional guidance files under /administrator/. Frontend SEF is controlled by the site root .htaccess. Do not assume copying root rules into /administrator/ is required for normal Admin access. Protect Admin with auth, IP policy, and updates rather than experimental rewrite stacks unless you know you need them.
After every major Joomla upgrade
- Diff
htaccess.txt (new) vs live .htaccess.
- Port missing API, header, or gzip fixes.
- Keep your Custom redirects section intact.
- Retest frontend SEF,
/api/ (if used), and HTTPS redirects.
- On OpenLiteSpeed, restart after the merge.
Skipping this step is how “API worked on 4.4 and died on 5.2” tickets start when someone restored an old .htaccess from backup.
Field verification checklist
Run these from a machine that can reach the site (adjust host and paths):
curl -I https://www.example.com/
curl -I http://www.example.com/
curl -I https://example.com/
curl -I https://www.example.com/a-real-menu-alias
curl -I https://www.example.com/api/index.php/v1/content/articles
What to read in headers:
- Final
HTTP/1.1 200 (or expected 301 chain length of one hop to canonical)
- No redirect loop
x-content-type-options: nosniff when expected
- For API: 401/200 from Joomla is fine; HTML 404 from the wrong front controller is not
Inside Joomla:
- Menu links omit
index.php when rewriting is on
- Media URLs still 200
- Administrator login still works
If pretty URLs 404 but https://site/index.php/alias works, rewriting or RewriteBase is wrong, not article content.
Common issues and fixes
| Symptom |
Likely cause |
Fix |
| HTTP 500 right after rename |
Options +FollowSymlinks forbidden |
Comment that line |
| All CSS broken, decoding error |
Double gzip |
Disable stock GZIP section |
SEF 404s, index.php URLs work |
Rewrite off, missing file, or AllowOverride |
Rename file, enable rewriting, fix vhost |
| Only subfolder site breaks |
Bad RewriteBase |
Set /subfolder/ |
| API 401 only on FastCGI |
Missing Authorization env rule |
Restore stock HTTP_AUTHORIZATION line |
/api/v1 404 on J4+ |
Old J3-era .htaccess |
Merge API rewrite block |
| HTTPS loop behind CDN |
Flexible SSL + force HTTPS |
Full strict TLS; use X-Forwarded-Proto |
| Edits do nothing on OLS |
No restart |
Restart OpenLiteSpeed |
| Redirect rule “ignored” |
Placed after SEF [L] |
Move into Custom redirects section |
| Works on Apache, fails on nginx |
.htaccess not used |
Write nginx try_files |
Key takeaways
- Joomla
.htaccess is opt-in: rename htaccess.txt, then enable SEF + URL rewriting.
- The same process covers Joomla 3 through 6; stock contents differ (especially
/api/ from Joomla 4+).
- Rule order is not cosmetic. Custom 301s go above core SEF.
- Comment
FollowSymlinks when hosts 500; set RewriteBase for subfolders.
- Treat Authorization passthrough and API routing as first-class on modern Joomla.
- Disable stock GZIP rules when the server already compresses assets.
- Diff
.htaccess against new htaccess.txt after every major upgrade.
- Use nginx/IIS native config when Apache per-directory files do not apply.
Frequently asked questions
Does every Joomla site need a .htaccess file?
No. You need it on Apache/LiteSpeed when you want rewrite-based URLs, stock exploit blocks, or related header/compression rules. nginx and IIS use other config files.
Is .htaccess different for Joomla 4, 5, and 6?
The activation steps are the same. File contents evolved. Joomla 4+ stock files route /api/ to api/index.php and include newer header/SVG/gzip notes. Always start from the htaccess.txt that shipped with your version.
Where is the Joomla .htaccess file?
It is not active until you rename root htaccess.txt to .htaccess in the same directory as configuration.php and index.php.
Why do I get a 500 error after enabling it?
Most often Options +FollowSymlinks is disallowed by the host. Comment that line and retest.
Should I enable Use URL Rewriting before renaming the file?
No. Rename first (or confirm rewrite works), then enable Use URL Rewriting. Doing it backwards usually produces a broken frontend.
Can I force HTTPS in Joomla .htaccess?
Yes. Put a 301 rule in the Custom redirects section and handle X-Forwarded-Proto behind proxies. See the redirect guide.
Does .htaccess replace com_redirect?
No. .htaccess runs before PHP. com_redirect runs after Joomla decides a request is a 404. Use both for different jobs.
What about LiteSpeed or OpenLiteSpeed?
LiteSpeed family generally understands .htaccess rewrite rules. On OpenLiteSpeed, restart the server after changes or they may not load.
How do I protect configuration.php with .htaccess?
Deny web access with a FilesMatch/Files rule for configuration.php. Still keep file permissions tight and outside world-writable.
Will a Joomla update overwrite my .htaccess?
Core updates do not normally replace an existing .htaccess, but new installs and some migrations refresh htaccess.txt. Your customized .htaccess can drift. Diff after major upgrades.
Where can Infyways help?
Joomla development, Joomla website optimization, Joomla upgrade, and ongoing support.