.htaccess in Joomla
One small text file in your Joomla root, the .htaccess file, decides whether your clean URLs work, whether common attacks get blocked, and whether your CSS and JavaScript arrive compressed. Most site owners never open it, yet it runs on almost every request to an Apache server. When it is missing or wrong, pages return "404 Not Found", the site looks broken, or it quietly stays less safe than it should be.
This article explains the Joomla .htaccess file from top to bottom. It covers the basics for site owners, the rename and SEF setup for administrators, and the rewrite rules, security blocks, and performance tricks that developers need to understand.
The .htaccess file is the doorman of an Apache Joomla site: it decides what gets in, where it goes, and how fast it arrives.
The goal is simple: help you understand what every block in the shipped file does, so you can use it with confidence and adapt it safely.
1. The Basics
1.1 What is the .htaccess File?
The .htaccess file (the name means "hypertext access") is a per-directory configuration file for the Apache web server. It lets you change how the server behaves for one folder and everything below it, without touching the main server configuration. The leading dot makes it a hidden file on Linux, which is why many file managers do not show it by default.
Joomla uses it for four main jobs:
- Turn clean SEF URLs into requests Joomla can route.
- Block some of the most common attack patterns in the URL.
- Set a few security headers and access rules.
- Serve pre-compressed CSS and JavaScript when they exist.
1.2 Why It Ships as htaccess.txt
Joomla does not install an active .htaccess file. It ships a ready-made template named htaccess.txt in the site root instead. There are two reasons. First, a hidden file is easy to overlook during an upload. Second, an .htaccess file with rewrite rules on a server that does not support them can break the whole site. Shipping it as a plain .txt keeps it inactive until you choose to use it.
To activate it, you rename the file:
htaccess.txt → .htaccess
This single rename is the step most beginners forget. The two files are byte-for-byte identical; only the name differs.
1.3 Where It Lives
The file sits in the Joomla web root, next to index.php and configuration.php:
public_html/
index.php
configuration.php
htaccess.txt ← the shipped template
.htaccess ← the active file after you rename it
web.config.txt ← the IIS equivalent (Windows only)
Apache reads .htaccess only when it is allowed to (see section 11). On most shared hosting it is allowed by default, which is exactly why .htaccess is so popular there.
2. Turning On Clean URLs
2.1 The Two Joomla Settings
Clean URLs depend on two options in System → Global Configuration → Site, plus the file itself:
- Search Engine Friendly URLs turns
index.php?option=com_content&view=article&id=42into/news/42-my-article. This works on any web server, with or without.htaccess. - Use URL Rewriting removes the
index.phpfrom the path, so the URL becomes/news/my-article. This option needs the web server's rewrite engine and the matching config file.
2.2 The Order That Avoids a Broken Site
Do the steps in this order:
- Rename
htaccess.txtto.htaccessfirst. - Then set Use URL Rewriting = Yes in Global Configuration.
- Open a few internal links and confirm they load.
If you switch on rewriting before the file exists, Joomla produces URLs without index.php, but Apache does not know how to route them, and every page except the home page returns a 404.
2.3 What Each Setting Produces
| SEF | URL Rewriting | Example URL |
|---|---|---|
| Off | Off | /index.php?option=com_content&view=article&id=42 |
| On | Off | /index.php/news/42-my-article |
| On | On | /news/my-article |
Only the last row needs .htaccess. The middle row is the safe fallback when rewriting is not available: the index.php stays in the path, but the URL is still readable.
3. The Top of the File: Options and Headers
Before any rewriting happens, the shipped file sets a few server options and security headers. These run even if mod_rewrite is switched off.
3.1 FollowSymlinks and No Directory Listings
Options +FollowSymlinks
Options -Indexes
+FollowSymlinks lets Apache follow symbolic links, which mod_rewrite requires. The file's own comments warn that some hosts forbid setting this in .htaccess; if your site errors, you comment the line out. -Indexes stops Apache from showing an automatic file list when a folder has no index file, so visitors cannot browse your directories.
A second block reinforces the same idea for the autoindex module:
<IfModule mod_autoindex.c>
IndexIgnore *
</IfModule>
3.2 The nosniff Header
The file sets one security header for every response:
<IfModule mod_headers.c>
Header always set X-Content-Type-Options "nosniff"
</IfModule>
This tells the browser not to guess ("sniff") the content type of a file. Without it, a browser might treat an uploaded image as JavaScript and run it. The <IfModule> wrapper means the rule applies only if Apache's mod_headers is loaded, so the file never errors on a server that lacks it.
3.3 Locking Down SVG Files
SVG images are XML and can contain scripts. The shipped file blocks that when an SVG is opened directly:
<FilesMatch "\.svg$">
<IfModule mod_headers.c>
Header always set Content-Security-Policy "script-src 'none'"
</IfModule>
</FilesMatch>
This stops inline JavaScript from running when someone opens an SVG file straight from your media folder or embeds it with an <object> tag. It is a small but real defence against a malicious upload.
3.4 The Commented CORP and COEP Block
Just above the SVG rule, the file includes two cross-origin headers that are commented out by default:
#<IfModule mod_headers.c>
# Header always set Cross-Origin-Resource-Policy "same-origin"
# Header always set Cross-Origin-Embedder-Policy "require-corp"
#</IfModule>
They are off because they can break sites that legitimately load images, fonts, or embeds from other domains. Enable them only after you test that every third-party asset still loads. They are powerful, but they are not safe to switch on blindly.
Back to top4. The Exploit-Blocking Rules
Once mod_rewrite is on, the file opens with a short list of rules that block the most common Joomla exploit attempts in the URL query string. Each rule inspects %{QUERY_STRING} and, on a match, returns a 403 Forbidden.
RewriteEngine On
# Block any script trying to base64_encode data within the URL.
RewriteCond %{QUERY_STRING} base64_encode[^(]*\([^)]*\) [OR]
# Block any script that includes a <script> tag in URL.
RewriteCond %{QUERY_STRING} (<|%3C)([^s]*s)+cript.*(>|%3E) [NC,OR]
# Block any script trying to set a PHP GLOBALS variable via URL.
RewriteCond %{QUERY_STRING} GLOBALS(=|\[|\%[0-9A-Z]{0,2}) [OR]
# Block any script trying to modify a _REQUEST variable via URL.
RewriteCond %{QUERY_STRING} _REQUEST(=|\[|\%[0-9A-Z]{0,2})
# Return 403 Forbidden and show the root home page content.
RewriteRule .* index.php [F]
In plain words, the four conditions catch:
- base64_encode(...) in the URL, a classic way to smuggle code.
- An injected
<script>tag, plain or URL-encoded as%3C...%3E. - Attempts to overwrite PHP's
GLOBALSarray. - Attempts to tamper with the
_REQUESTvariable.
The [OR] flag chains the conditions so that any one match triggers the block. The final [F] flag returns 403 Forbidden. These rules are a helpful baseline, not a firewall: keep Joomla updated and use a real Web Application Firewall for serious protection. If a legitimate request ever trips them, the comments tell you to disable the offending line with a leading #.
5. The Custom Redirects Section
The file reserves a clearly marked space for your own redirect rules:
## Begin - Custom redirects
#
# If you need to redirect some pages, or set a canonical non-www to
# www redirect (or vice versa), place that code here. Ensure those
# redirects use the correct RewriteRule syntax and the [R=301,L] flags.
#
## End - Custom redirects
This block is intentionally empty. It is the right place for infrastructure-level redirects that should run before PHP starts. A common example forces a single canonical host:
# Redirect www to the bare domain with a permanent 301
RewriteCond %{HTTP_HOST} ^www\.example\.test [NC]
RewriteRule (.*) https://example.test/$1 [R=301,L]
Put it inside this section so a Joomla update that replaces the SEF rules does not wipe your customisation by accident. For editorial redirects (a renamed article keeping its old link), prefer Joomla's own Redirects component, which is editor-friendly and survives a site move. Use .htaccess for server-level rules such as forcing HTTPS or a canonical host. See the Redirects article for the difference.
6. RewriteBase and Subfolders
Just before the core SEF section, the file has a commented line:
# RewriteBase /
It tells Apache the URL path that the rewrite rules are relative to. For a site in the web root you almost never need it. But when Joomla lives in a subfolder, for example https://example.test/blog/, or when the server's URL does not map directly to the physical file path, you uncomment and set it:
RewriteBase /blog
Forgetting this is one of the most common rewrite problems on subfolder installs. The home page works, but internal links resolve against the wrong base and return 404s. Set the base to match the folder, just / for the root.
7. The Core SEF Section
This is the heart of the file: the rules that actually route clean URLs to Joomla. It has three parts.
7.1 The HTTP Authorization Fix
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
Some PHP setups (FastCGI) strip the HTTP Authorization header before PHP sees it. Joomla's Web Services API uses that header to read its bearer token. This line copies the header into an environment variable so the API can still find it. The - target means "do not rewrite the URL", only set the variable.
7.2 Routing the Web Services API
RewriteCond %{REQUEST_URI} ^/api/
RewriteCond %{REQUEST_URI} !^/api/index\.php
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule .* api/index.php [L]
If the path starts with /api/, is not already api/index.php, and does not match a real file or folder, Apache rewrites it to the API entry point api/index.php. This is how a request like /api/index.php/v1/content/articles reaches Joomla's headless API. The [L] flag means "last rule, stop here".
7.3 Routing the Front End
RewriteCond %{REQUEST_URI} !^/index\.php
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule .* index.php [L]
This is the rule that makes clean URLs work. The two key conditions are !-f ("not a real file") and !-d ("not a real directory"). Together they say:
If the request points at a real file or folder, serve it directly. Otherwise, hand it to index.php and let Joomla figure out the route.
That is why /about-us reaches Joomla and becomes a page, while /images/logo.png is served straight from disk and never touches PHP.
7.4 Rewrite Versus Redirect
The SEF rules above are rewrites, and a rewrite is not the same as a redirect. The difference matters the moment you add your own rules.
- A rewrite is internal and invisible. The browser asks for
/about-us, Apache quietly servesindex.php, and the address bar never changes. This is how clean URLs reach Joomla. - A redirect is external and visible. Apache tells the browser "go to this other URL instead", the browser makes a second request, and the address bar changes. This is how you send an old URL to a new one.
Use a rewrite when you want Joomla to handle a friendly URL. Use a redirect when a URL has genuinely moved, and send the right status code: 301 for a permanent move, 302 for a temporary one.
7.5 Common Rewrite Flags
The square brackets at the end of a RewriteRule or RewriteCond are flags that change what the rule does. The shipped file uses several of them; these are the ones worth knowing:
| Flag | Meaning |
|---|---|
L |
Last rule: stop processing further rewrite rules in this pass. |
END |
Stop all rewrite processing completely, with no further passes. |
NC |
No case: match case-insensitively. |
QSA |
Query String Append: keep the original query string and add to it. |
R=301 |
Redirect the browser with a 301 (permanent); use R=302 for temporary. |
F |
Forbidden: return 403 and stop. Used by the exploit-blocking rules. |
G |
Gone: return 410, telling crawlers the URL is permanently removed. |
OR |
On a RewriteCond, combine with the next condition as "either/or". |
Reading the flags is the quickest way to understand an unfamiliar rule. [R=301,L], for example, means "redirect permanently and stop", the standard pair for a canonical or HTTPS redirect.
8. The No-Rewrite Fallback
What happens if mod_rewrite is not available at all? The file has a small fallback that runs only in that case:
<IfModule !mod_rewrite.c>
<IfModule mod_alias.c>
RedirectMatch 302 ^/$ /index.php/
</IfModule>
</IfModule>
The !mod_rewrite.c condition means "only if mod_rewrite is not loaded". In that situation, a visitor to the bare domain is sent with a temporary 302 redirect to /index.php/, so the front controller still runs and the generated links (which include index.php) keep working. It is a safety net, not a feature you rely on: without mod_rewrite you cannot use the cleanest URL format.
9. Compression and Caching
9.1 Serving Pre-Compressed Assets (GZIP and Brotli)
The last block in the file is a performance trick. If a pre-compressed .gz copy of a CSS or JavaScript file exists, and the browser accepts gzip, Apache serves the smaller file instead of compressing on the fly.
<IfModule mod_headers.c>
# Serve a gzip-compressed CSS file if it exists and the client accepts gzip.
RewriteCond "%{HTTP:Accept-encoding}" "gzip"
RewriteCond "%{REQUEST_FILENAME}\.gz" -s
RewriteRule "^(.*)\.css" "$1\.css\.gz" [QSA]
# Same for JavaScript.
RewriteCond "%{HTTP:Accept-encoding}" "gzip"
RewriteCond "%{REQUEST_FILENAME}\.gz" -s
RewriteRule "^(.*)\.js" "$1\.js\.gz" [QSA]
# Send the right content type and stop double compression.
RewriteRule "\.css\.gz$" "-" [T=text/css,E=no-gzip:1,E=no-brotli:1]
RewriteRule "\.js\.gz$" "-" [T=text/javascript,E=no-gzip:1,E=no-brotli:1]
</IfModule>
Two details matter. The no-gzip and no-brotli flags stop Apache from compressing an already-compressed file a second time, which would corrupt it. A FilesMatch block then sets Content-Encoding: gzip and adds Vary: Accept-Encoding so proxies cache the compressed and uncompressed versions separately.
The file's own comment warns that if your host already gzips CSS and JS, this block causes a double-compression error (ERR_CONTENT_DECODING_FAILED in the browser console). If you see that, comment the GZIP section out. This block only helps if you actually generate .css.gz and .js.gz files; without them, it simply does nothing.
9.2 Browser Caching with mod_expires
Pre-compression makes the first download smaller; browser caching avoids the download entirely on the next visit. With mod_expires you tell browsers how long to keep static files. This is not part of the shipped file, so you add it in your own block:
<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 font/woff2 "access plus 1 year"
ExpiresByType text/css "access plus 1 month"
ExpiresByType application/javascript "access plus 1 month"
</IfModule>
Typical durations are a year for images and fonts, which rarely change, and a month for CSS and JavaScript. Long expiry works best when your file names are versioned (for example style.4f2a.css): a changed file gets a new name, so the browser fetches the new one instead of serving a stale cached copy. Joomla's own media versioning helps here by appending a version query to its assets.
10. The .htaccess on Other Web Servers
The .htaccess file is an Apache feature. Other servers handle the same jobs differently.
| Server | Reads .htaccess? | How SEF is configured |
|---|---|---|
| Apache | Yes | Rename htaccess.txt to .htaccess. |
| LiteSpeed (commercial) | Yes | Reads the Apache .htaccess directly. |
| OpenLiteSpeed | Only if enabled | Turn on "Auto Load from .htaccess", or use its own rewrite settings. |
| Nginx | No | Add a try_files rule to the server config. |
| IIS (Windows) | No | Rename web.config.txt to web.config and install URL Rewrite. |
The single most common migration mistake is copying an Apache .htaccess into an Nginx setup and expecting it to work. Nginx ignores the file completely. The same routing logic exists, but it must be written into the server config in Nginx's own syntax. See the Web Servers article for the per-server equivalents.
11. Under the Hood (Developer View)
11.1 When Apache Reads the File
Apache checks for .htaccess on every request, and it reads not just the file in the target folder but the one in every parent folder up to the document root. This is flexible: you can drop rules into any folder without server access. It is also the cost: those file reads happen on every single request.
11.2 AllowOverride Controls Everything
Whether Apache reads .htaccess at all depends on the AllowOverride directive in the main server config:
<Directory /var/www/html>
AllowOverride All # read .htaccess and honour its directives
</Directory>
If AllowOverride is None, Apache ignores the file entirely, and your rewrite rules do nothing no matter how correct they are. On a server you control, the faster pattern is to set AllowOverride None and move the rules into the virtual host, so Apache stops looking for the file:
# Same Joomla rules, but in the <VirtualHost> instead of .htaccess
<Directory /var/www/html>
Options +FollowSymlinks -Indexes
AllowOverride None
# ... paste the RewriteRule blocks here ...
</Directory>
This removes the per-request file reads and is measurably faster at scale. On shared hosting you rarely have this choice, so .htaccess stays.
11.3 How the Server Hands Off to Joomla
After the rewrite, Joomla reads the request from the $_SERVER superglobal that Apache populates. A few values drive how Joomla builds URLs and detects HTTPS:
| Variable | What Joomla uses it for |
|---|---|
REQUEST_URI |
The requested path, to route the page. |
HTTP_HOST |
The domain, to build absolute links. |
HTTP_AUTHORIZATION |
The API bearer token (set by the fix in section 7.1). |
HTTPS |
To decide whether the connection is secure. |
11.4 Testing the API Route
Because the file routes /api/ to api/index.php and preserves the Authorization header, you can confirm the Web Services API works with a single request:
curl -H "X-Joomla-Token: <your-token>" \
https://example.test/api/index.php/v1/content/articles
A JSON list of articles means the rewrite and the Authorization fix both work. A 404 on the same call usually means .htaccess is not active or AllowOverride is off.
11.5 Behind a Reverse Proxy or CDN
Many Joomla sites sit behind a CDN or reverse proxy such as Cloudflare. The .htaccess file still runs on the origin server, but the request has already passed through another layer first, and that changes two things.
First, the proxy often terminates HTTPS and then talks to your server over plain HTTP. Apache sees HTTPS as off, so a plain "Force HTTPS" rewrite can loop forever: the visitor arrives over HTTPS at the proxy, your server sees HTTP and redirects to HTTPS, the proxy forwards it again as HTTP. The fix is to check the forwarded header instead of HTTPS:
RewriteCond %{HTTP:X-Forwarded-Proto} !https
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
Second, set Behind Load Balancer = Yes in Global Configuration → Server, so Joomla trusts the forwarded protocol and builds https:// links correctly. Without it, you can get mixed-content warnings or redirect loops even when the .htaccess rule itself is right.
12. Security Beyond the Shipped Rules
The shipped file is a baseline. On a server where you can edit .htaccess freely, a few extra rules harden the site further. Add them in your own block, not inside the Joomla SEF section.
12.1 Force HTTPS
RewriteCond %{HTTPS} off
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
Back it up with Global Configuration → Server → Force HTTPS = Entire Site, so Joomla enforces it too.
12.2 Block Sensitive Files
Some files should never be downloadable. The most important is configuration.php, which holds your database password. You can deny direct access to risky paths:
<FilesMatch "^(configuration\.php|\.env|.*\.(bak|old|log))$">
Require all denied
</FilesMatch>
# Block the .git folder
RedirectMatch 404 /\.git
Note that modern Joomla already places much of its code outside the web root and protects core folders, but backup copies such as configuration.php.bak are a frequent leak that these rules close.
12.3 Keep Headers Consistent
Joomla ships a System - HTTP Headers plugin that sets most security headers from the backend. The .htaccess file sets X-Content-Type-Options: nosniff at the server. If both set the same header with different values, the one that runs last wins, usually the server or a proxy. Decide where each header lives and keep the two layers in sync.
12.4 Optional Hardening
The rules below are not in the shipped file and not required, but they close common gaps. Add only the ones you understand, test after each, and keep them in your own block, never inside the Joomla SEF section.
Stop PHP running in upload folders. An attacker who manages to upload a script often drops it in a media folder such as images/. Place a small second .htaccess file inside that folder to refuse PHP execution. You scope it by location this way because the <Directory> directive is not allowed in an .htaccess file:
# images/.htaccess
<FilesMatch "\.php$">
Require all denied
</FilesMatch>
Disable the TRACE method. The HTTP TRACE method is almost never needed and can echo back request headers. Refuse it:
RewriteCond %{REQUEST_METHOD} ^TRACE
RewriteRule .* - [F]
Deny more sensitive files. Extend the block from section 12.2 to cover dependency manifests and database dumps, which sometimes get left in the web root:
<FilesMatch "^(composer\.(json|lock)|.*\.sql)$">
Require all denied
</FilesMatch>
Add stronger response headers. Beyond nosniff, these headers improve security but need testing, because a strict policy can block third-party fonts, scripts, or embeds:
<IfModule mod_headers.c>
# Force HTTPS for two years, including subdomains. Add only once HTTPS is solid.
Header always set Strict-Transport-Security "max-age=63072000; includeSubDomains"
# Send only the origin as referrer to other sites.
Header always set Referrer-Policy "strict-origin-when-cross-origin"
# Switch off browser features the site does not use.
Header always set Permissions-Policy "geolocation=(), camera=(), microphone=()"
</IfModule>
Joomla's System - HTTP Headers plugin can set most of these from the backend instead. Pick one place, the plugin or the file, and keep it consistent (see section 12.3). Add HSTS only when every page reliably loads over HTTPS, because once a browser sees the header it refuses plain HTTP for the whole max-age, even if you later turn HTTPS off.
Branded error pages. Apache's default error screens look nothing like your site. Route them through Joomla so the visitor stays on a branded page:
ErrorDocument 404 /index.php
ErrorDocument 403 /index.php
Joomla then renders its own error page, which you can style by overriding templates/your_template/error.php. Keep the target as /index.php so the path still resolves if the site moves to a subfolder or a new domain.
13. SEO and Metadata
The .htaccess file shapes SEO before any extension does. Search engines reward sites that are fast, secure, and consistent, and all three start here:
- Clean URLs: with the file active and URL Rewriting on, paths are short and readable, which both users and crawlers prefer.
- One canonical host: use the custom redirects block to force HTTPS and pick either
wwwor the bare domain, then 301-redirect the other. Serving the same page on two hosts splits ranking signals. - Correct status codes: a permanent move must return
301, not302. The[R=301,L]flags matter for passing link equity. - Speed: the GZIP block and long cache headers improve Core Web Vitals, which feed Google's ranking.
None of this needs an SEO extension. It is configuration you set once in the file and in Global Configuration, and it pays off on every page.
Back to top14. Common Mistakes and Pitfalls
14.1 Forgetting the Rename
Symptom: the home page works, but every other page returns 404 after you switch on Use URL Rewriting.
Fix: rename htaccess.txt to .htaccess. The file must be active before rewriting is turned on.
14.2 The Hidden File You Cannot See
Symptom: you renamed the file but your FTP client or file manager does not show it, so you are not sure it exists.
Fix: enable "show hidden files" in your client (or ls -a on the command line). Files beginning with a dot are hidden by default.
14.3 AllowOverride Is Off
Symptom: the file exists, is named correctly, yet rewriting still does nothing.
Fix: the server has AllowOverride None. Ask your host to allow overrides, or move the rules into the virtual host (see section 11.2).
14.4 The Subfolder RewriteBase
Symptom: rewriting works in the web root but breaks when Joomla lives in a subfolder.
Fix: uncomment and set RewriteBase /subfolder to match the install path.
14.5 Double Compression
Symptom: CSS and JavaScript fail to load and the console shows ERR_CONTENT_DECODING_FAILED.
Fix: your host already gzips assets. Comment out the GZIP block at the bottom of the file.
14.6 Edits Lost After an Update
Symptom: your custom rules disappear after a Joomla update or a fresh upload.
Fix: a major update can ship a new htaccess.txt; if you re-rename it, your edits are gone. Keep your rules only inside the "Custom redirects" block, and keep a backup copy of your live .htaccess.
14.7 Blocking Yourself with the Exploit Rules
Symptom: a legitimate URL with an unusual query string returns 403 Forbidden.
Fix: one of the exploit-blocking conditions matched by accident. Comment out the specific RewriteCond line with a leading #, as the file's own notes suggest.
15. Best Practices
If you remember only a few things from this article, remember these:
- Rename
htaccess.txtto.htaccessbefore turning on URL Rewriting. - Put your own rules only inside the "Custom redirects" block, so updates do not erase them.
- Keep a backup of your live
.htaccessbefore you edit it. - On a subfolder install, set
RewriteBaseto the folder path. - Force HTTPS and one canonical host with
[R=301,L], and match it with Joomla's Force HTTPS. - If the host already compresses assets, comment out the GZIP block.
- On a server you control, move the rules into the virtual host and set
AllowOverride Nonefor speed. - Block
configuration.phpbackups,.env, and.gitfrom the web. - Use Joomla's Redirects component for editorial redirects; use
.htaccessfor server-level rules. - Treat the exploit-blocking rules as a baseline, not a replacement for updates and a real firewall.
16. Quick Reference
ACTIVATE Rename htaccess.txt → .htaccess
SEF SETTINGS System → Global Configuration → Site
SEF URLs = Yes, Use URL Rewriting = Yes
SUBFOLDER Uncomment RewriteBase /subfolder
ROUTE FRONT RewriteRule .* index.php [L] (after !-f and !-d)
ROUTE API RewriteRule .* api/index.php [L] (paths under /api/)
AUTH FIX E=HTTP_AUTHORIZATION keeps the API token alive
EXPLOIT Blocks base64_encode, <script>, GLOBALS, _REQUEST [F]
FLAGS [L] stop [F] 403 [R=301,L] redirect [QSA] keep query
NOSNIFF Header always set X-Content-Type-Options "nosniff"
GZIP Serves .css.gz / .js.gz if present; turn off on double-compress
CACHING mod_expires: images/fonts 1yr, CSS/JS 1mo
FALLBACK No mod_rewrite -> RedirectMatch 302 ^/$ /index.php/
ALLOWOVERRIDE Must be All (or rules in vhost) or .htaccess is ignored
CANONICAL Custom redirects block + [R=301,L]
PROXY Check X-Forwarded-Proto; Behind Load Balancer = Yes
HARDEN Optional: no-PHP uploads, TRACE off, HSTS, ErrorDocument
OTHER SERVERS LiteSpeed reads it; Nginx and IIS do not
Back to top17. Summary
The .htaccess file is the most influential text file in an Apache Joomla site, yet it hides behind a leading dot and ships inactive on purpose. Once you know what each block does, it stops being mysterious:
- Activation: rename
htaccess.txtto.htaccess, then enable URL Rewriting. - Routing: the SEF section sends anything that is not a real file or folder to
index.php, and/api/requests toapi/index.php. - Defence: it blocks common URL exploits, sets the
nosniffheader, and locks down SVG scripts. - Speed: it can serve pre-compressed assets and lets you add cache and HTTPS rules.
- Portability: it is an Apache feature; LiteSpeed reads it, but Nginx and IIS need their own config.
If your Joomla site throws 404s after you enable clean URLs, breaks its CSS after an upload, or loses your custom rules after an update, the cause is almost always in this one file. A careful read of the rewrite rules, the RewriteBase, and the AllowOverride setting usually finds the problem fast. It is exactly the kind of quiet foundation work that keeps a Joomla site fast, safe, and reliable for years, and it is worth getting right once rather than fighting it on every page.


Peter is a Joomla specialist and a Linux admin for fast, secure and scalable websites.
Frequently Asked Questions
The Joomla .htaccess file controls URL rewriting, redirects, security settings and caching. It helps improve SEO, website performance and protection against common attacks.
Rename htaccess.txt to .htaccess and enable Search Engine Friendly URLs in Joomla Global Configuration. Make sure your server supports Apache's mod_rewrite.
Yes. You can create permanent (301) redirects in the .htaccess file to preserve SEO value and automatically send visitors to the correct pages.
Yes, provided you create a backup first. A small syntax error can make your website temporarily inaccessible, so always test changes after saving.
Yes. You can redirect all HTTP traffic to HTTPS with a simple rule in the .htaccess file, ensuring secure connections and supporting better SEO.
Common settings include blocking directory browsing, preventing access to sensitive files, disabling script execution in upload folders and protecting against common exploits.
The .htaccess file works on Apache, LiteSpeed and OpenLiteSpeed web servers because they are compatible with Apache's configuration format. Nginx does not support .htaccess, so the rules must be converted to the Nginx configuration. On IIS, similar functionality is configured in the web.config file.


