The .htaccess file is the single most powerful, and most quietly dangerous, file in a PrestaShop installation. A handful of well-placed lines block the file-scanning bots that hammer every store on the public internet, shave kilobytes off every page, and stop sensitive files from ever being served. The same file, edited carelessly, returns a 500 Internal Server Error on every URL and takes your whole shop offline until you can reach an FTP client. Most merchants never open it. This guide is about opening it on purpose, knowing exactly which lines to add, where to put them so PrestaShop doesn't overwrite your work, and how to get back online in sixty seconds if something goes wrong.
Last updated: June 2026.
This is the rules-and-config post for the cluster: the literal directives you paste into .htaccess. The wider strategy, what to harden first, how to think about your whole attack surface, lives in the complete security hardening checklist, and the no-jargon version for non-technical owners is the plain-English guide. Here we stay at the file level.
What .htaccess is, and the one fact that saves your store
.htaccess ("hypertext access") is a per-directory configuration file for the Apache web server. PrestaShop writes it for you the first time you enable Friendly URLs under Shop Parameters → Traffic & SEO → SEO & URLs, and rewrites it every time you toggle that setting or change a URL pattern. That auto-generation is the fact that saves you: if you ever break the file, you can regenerate a clean default from the back office in two clicks (covered at the end).
One caveat before you touch anything: .htaccess only works on Apache. A growing share of PrestaShop hosting runs Nginx (or Apache-behind-Nginx), where .htaccess files are ignored entirely. If you're on Nginx, the security and performance ideas below are identical but the syntax lives in your site/server block, not in a per-directory file, follow the official PrestaShop Nginx configuration documentation (or the sample your host provides) for the rewrite rules to start from. Not sure which you're on? A line saying Server: Apache or Server: nginx in your response headers tells you immediately.
The golden rule: write outside PrestaShop's markers
Open the file and you'll find PrestaShop's managed block bracketed by comment markers:
| What you see | What it means |
|---|---|
# ~~start~~ Do not remove this comment, Prestashop will keep automatically the code outside this comment when .htaccess will be generated again | Everything from here to ~~end~~ is owned by PrestaShop. Friendly-URL rewrites, MultiViews, the front-controller rules all live inside. Never edit this block by hand, PrestaShop overwrites it on the next regeneration and your changes vanish. |
# ~~end~~ Do not remove this comment | End of the managed block. |
The marker comment is explicit: PrestaShop keeps the code outside this comment when it regenerates. So your custom security and performance rules go above the ~~start~~ marker or below the ~~end~~ marker, never between them. That single habit is the difference between rules that survive every "save SEO settings" click and rules that silently disappear next Tuesday.
What PrestaShop's default block already does (leave it alone)
Before adding anything, it's worth knowing what's already handled inside the managed block so you don't duplicate it and trigger conflicts:
- URL rewriting. The large
RewriteRuleset that turns/123-nike-air-maxinto somethingindex.phpcan route. PrestaShop-managed; never touched by hand. Options -MultiViews. Stops Apache content-negotiating a request for/aboutinto some strayabout.htmlinstead of letting PrestaShop's router handle it.DirectoryIndex index.php. Ensures the front controller runs when a directory is requested.- RewriteBase. Set to
/for a root install, or/shop/if PrestaShop lives in a subfolder. Get this wrong and every friendly URL 404s. - PHP value overrides on some hosts (memory limit, upload size), added when you can't edit
php.inidirectly.
All of that is correct out of the box. Your job is to add the layer PrestaShop doesn't ship: hardening and caching.
Security rules to add (above the marker)
PrestaShop's default file is functional, not hardened. These are the rules that close real, routinely-scanned holes. Paste them before the ~~start~~ marker.
1. Block direct access to sensitive files
Put this above the PrestaShop managed marker on Apache 2.4+:
<FilesMatch "^(composer\.(json|lock)|package(-lock)?\.json|\.env|\.gitignore)$">
Require all denied
</FilesMatch>
<FilesMatch "^(parameters\.php|settings\.inc\.php)$">
Require all denied
</FilesMatch>
A PrestaShop tree contains files that should never be served to a browser: YAML config, logs, SQL dumps, raw Twig and Smarty templates. If a bot can GET /app/config/parameters.yml, it can read your database credentials. Deny the dangerous extensions:
<FilesMatch "\.(yml|yaml|log|tpl|twig|sql|md|dist|neon|ini)$">
Require all denied
</FilesMatch>
(On older Apache 2.2 hosting, swap Require all denied for Order deny,allow / Deny from all. Your host can tell you which Apache version you're on.) PrestaShop already drops index.php stubs into many folders, but an explicit extension deny covers the files those stubs miss.
2. Lock down the high-value config files by name
Two files deserve a belt-and-braces named block because they're the crown jewels: the legacy config/settings.inc.php (1.6) and the modern app/config/parameters.php (1.7–9). They're PHP, so Apache won't print them, but a misconfigured server or a .bak copy can leak them. Deny the lot:
<FilesMatch "(parameters\.(php|yml)|settings\.inc\.php|.*\.bak)$">
Require all denied
</FilesMatch>
3. Block .git and .env exposure
If you deploy with Git (you should), a browsable /.git/ directory hands an attacker your entire source history, including credentials in old commits. Same story for a stray .env:
RedirectMatch 404 /\.git
<FilesMatch "^\.env">
Require all denied
</FilesMatch>
4. Prevent directory listing
Without it, anyone pointing a browser at /upload/ or /download/ sees a clickable file index, a textbook information leak. One line shuts it everywhere:
Options -Indexes
5. Add security headers
HTTP response headers tell the browser to switch on its own defenses. These need Apache's mod_headers (almost always present); wrap them in an <IfModule> so a host without it doesn't 500:
<IfModule mod_headers.c>
Header set X-Content-Type-Options "nosniff"
Header set X-Frame-Options "SAMEORIGIN"
Header set Referrer-Policy "strict-origin-when-cross-origin"
Header set Permissions-Policy "camera=(), microphone=(), geolocation=()"
</IfModule>
- X-Content-Type-Options: nosniff. Stops the browser guessing a file's type and executing an upload as script.
- X-Frame-Options: SAMEORIGIN. Blocks clickjacking by refusing to let your store load inside another site's iframe.
- Referrer-Policy, limits how much URL data leaks to third parties on outbound clicks.
- Permissions-Policy, denies camera, mic and geolocation by default so a compromised script can't quietly request them.
Note the deliberate omission: the old X-XSS-Protection header is deprecated and ignored (or harmful) in current browsers, don't add it. The header worth adding next, Content-Security-Policy, is powerful but easy to break a PrestaShop theme with, so it belongs in a careful, tested rollout rather than a copy-paste. CSP is also your strongest defense against payment-page card skimmers. The mechanics of that attack are in the anatomy of a Magecart-style attack.
One thing .htaccess deliberately can't do well: rate-limiting or geo-blocking abusive traffic at scale. Blanket Deny from IP lists in .htaccess rot fast and don't stop distributed scanners. For real visitor control, bad-bot filtering, IP bans, country rules, handle it at the application or edge layer: see blocking bad bots and unwanted traffic and, for stores already feeling the strain, surviving the ?q= crawler flood.
Performance rules to add
The same file is where you turn on the two highest-leverage front-end speed wins. Again: outside the markers, each wrapped in <IfModule>.
Gzip / Deflate compression
Text responses, HTML, CSS, JS, JSON, SVG, compress by roughly 60–80%, so a PrestaShop product page that ships ~150 KB of markup can leave the server closer to 40 KB. So what does that mean for you? Faster first paint, lower bounce, and a better PageSpeed score, with no change to a single template:
<IfModule mod_deflate.c>
AddOutputFilterByType DEFLATE text/html text/css text/plain text/xml
AddOutputFilterByType DEFLATE application/javascript application/json image/svg+xml
AddOutputFilterByType DEFLATE font/woff2 image/x-icon
</IfModule>
Many hosts already enable compression server-wide. If yours does, the <IfModule>-wrapped block above is harmless and simply redundant, mod_deflate won't double-compress already-compressed output. If a host has locked mod_deflate behind AllowOverride, the <IfModule> guard is what stops a 500; if you ever do see one after adding it, remove the block and let the server handle compression globally.
Browser caching (Expires headers)
This tells a returning visitor's browser to reuse static assets it already has instead of re-downloading them. The biggest repeat-visit win available. Long cache lifetimes are safe only for assets that are versioned or fingerprinted (PrestaShop and many themes/modules append a version query string or change filenames when bundles are rebuilt); for anything that isn't, use shorter lifetimes or confirm a cache-busting strategy (a query-string or file-version token) is actually active before adding a long Expires header, or a stale CSS/JS file can linger in browsers after an update:
<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 font/woff2 "access plus 1 year"
ExpiresByType text/css "access plus 1 month"
ExpiresByType application/javascript "access plus 1 month"
ExpiresDefault "access plus 2 days"
</IfModule>
| Asset | Suggested lifetime | Why |
|---|---|---|
| Images (jpg/png/webp) | 1 year | Rarely change; a new image gets a new filename anyway. |
| Fonts (woff2) | 1 year | Effectively never change. |
| CSS / JS | 1 month | Safe when versioned/cache-busted; shorten or verify busting if not. |
| HTML | Don't cache | Prices, stock and cart contents change constantly. |
Keep-Alive and ETags. Leave them to the server
Keep-Alive (reusing one TCP connection for many assets) helps every PrestaShop page, since each loads dozens of files, but it's almost always already on at the host level, so don't fight it in .htaccess. ETags are similar: fine for a single-server shop, occasionally a cache-busting nuisance on clustered or CDN setups (the CDN usually manages them for you). The rule of thumb: don't add directives for things your stack already handles. Every redundant line is another chance for a 500.
Common mistakes that take a store offline
- Editing inside the markers. Custom rules between
~~start~~and~~end~~get wiped on the next regeneration. Always write outside. - Unguarded compression or header blocks. A duplicate definition on a host that already compresses is usually just redundant, but an unwrapped
HeaderorAddOutputFilterByTypeline on a host where the module isn't loaded throws a 500. Always wrap in<IfModule>, and remove the block if it still conflicts. - Wrong RewriteBase. A subfolder install (
/shop/) withRewriteBase /404s every friendly URL. - Missing
RewriteEngine On. Copy rewrite rules from a generic guide without it and everything except the homepage 404s. (PrestaShop's own block includes it, this bites people who paste third-party rules.) - Directives your host forbids. Shared hosts often lock
php_value,OptionsandHeaderat the server level (AllowOverride). Using a locked directive returns 500. Check before you add.
How to recover from a broken .htaccess in under a minute

The SEO & URLs list shows each page with its page name, page title and friendly URL.
A 500 on every page after a save feels catastrophic; it's actually one of the fastest problems in hosting to fix, because the cause is always the file you just touched. Three routes, fastest first:
- FTP/SFTP. Connect, rename
.htaccessto.htaccess.broken(or delete it). The store returns instantly; only friendly URLs stop working until you regenerate. - Hosting File Manager. In cPanel or your panel, enable Show Hidden Files (dotfiles hide by default), then rename or fix the file the same way.
- Regenerate clean from the back office. Once the store is back up, go to Shop Parameters → Traffic & SEO → SEO & URLs, switch Friendly URLs off, save, then on again, and save. PrestaShop writes a fresh, correct default file, your safety net for any .htaccess disaster.
The cheap insurance: cp .htaccess .htaccess.backup before any edit takes one second and saves an evening. Better still, make changes on staging first.
Test before you walk away
- Click the critical paths: homepage, a category, a product, cart, and the full checkout. A bad rule can break one page type and leave others fine.
- Verify the speed wins: Google PageSpeed Insights will flag if compression or browser caching isn't actually firing.
- Verify the headers: run your domain through securityheaders.com to confirm each security header is being sent.
Frequently asked questions
Where exactly do my custom rules go in the .htaccess file?
Outside PrestaShop's managed block. Above the # ~~start~~ marker or below the # ~~end~~ marker, never between them. The marker comment itself says PrestaShop keeps the code outside the block when it regenerates the file. Anything you place between the markers is wiped the next time you save SEO settings or change a URL pattern.
I added rules and now every page returns a 500. How do I recover fastest?
The cause is always the file you just touched. Connect by FTP/SFTP (or your host's File Manager with hidden files shown), rename .htaccess to .htaccess.broken, and the store returns instantly. Only friendly URLs stop working until you regenerate. Then bring the store back up and regenerate a clean file from Shop Parameters → Traffic & SEO → SEO & URLs by toggling Friendly URLs off, saving, on, and saving again.
My host runs Nginx. Do these .htaccess rules do anything?
No. .htaccess is an Apache feature and Nginx ignores it entirely. The same security and performance ideas apply, but the directives live in your server block, not a per-directory file. Follow the official PrestaShop Nginx configuration (or your host's sample) for the rewrite rules, and translate the deny/header/compression rules into location blocks. Check your Server: response header to confirm which one you're on.
Will adding compression and Expires headers double up with what my host already does?
Usually it's harmless. mod_deflate won't double-compress already-compressed output, so a redundant block just sits there doing nothing. The danger is an unwrapped directive on a host where the module isn't loaded, that throws a 500. Always wrap compression and header blocks in <IfModule>, and if you still see a conflict, remove the block and let the server handle it globally.
Should I add a Content-Security-Policy header here too?
Not as a copy-paste. CSP is your strongest defence against payment-page card skimmers, but a too-strict policy silently breaks theme scripts, payment iframes and analytics. It belongs in a careful, tested rollout, build it in report-only mode first, watch what it would block, then enforce. Don't drop a blanket CSP line into .htaccess and walk away.
Where .htaccess ends and modules begin
Done right, .htaccess is a genuinely strong, free first layer, it closes the file-exposure holes scanners look for and turns on the compression and caching that make PrestaShop feel quick. But it's a blunt instrument. It can't reason about who is making a request, can't recover a store after a breach, and can't keep an un-upgradeable shop patched against known CVEs. Those are application-layer jobs:
- Stuck on an old version you can't upgrade? Server rules won't patch a vulnerable core. Virtual patching does, see advanced hardening for stores you can't upgrade yet.
- Protecting the admin and customer logins (2FA, password policy) is out of .htaccess scope, covered here.
- If the worst happens, a header file won't help you respond; the breach-response playbook will.
For the performance side, the same logic applies: hand-rolled Expires and Deflate rules are a fine baseline, but full page caching, smart minification, image optimization and CDN integration are what move a real store from "fine" to fast, and those belong in a maintained module rather than an ever-growing .htaccess. That's the kind of work we build at mypresta.rocks: the technical depth handled for you, so the speed and the peace of mind are settings in your back office, not lines you have to get exactly right in a file that can take the whole store down.