To secure a PrestaShop server, you combine several layers that work together: an up-to-date system and PHP, a firewall with only the necessary ports open, SSH login with keys only, fail2ban to block addresses that guess passwords or scan your shop, request limits in nginx, and Cloudflare in front of the server for DDoS protection, a WAF and bot filtering. Add a protected back office, logs, monitoring and backups. Below we go through each layer in turn, with configuration examples and a checklist at the end.
- Why do shop servers get attacked?
- The foundation: system, PHP and firewall
- Secure login: SSH and the PrestaShop back office
- fail2ban: blocking attacks automatically
- Cloudflare in front of PrestaShop
- DDoS protection
- Bots: good, bad and AI
- Logs, monitoring and backups
- Server security checklist
- Sources
- Frequently asked questions
Why do shop servers get attacked?
Most attacks on online shops are not aimed at one particular shop. They come from automated tools that probe thousands of addresses around the clock, looking for forgotten database dumps (backup.sql), configuration files (.env, .git), login pages and modules with known vulnerabilities. The Friends of Presta registry regularly publishes new flaws in PrestaShop modules, and some of them can be exploited without logging in. We explain how to tell whether a shop has already been hacked in PrestaShop security: vulnerabilities and hack signs.
The server is the first line of defence. A well-configured server turns scanners away before they reach PHP, limits login attempts and refuses to run an uploaded script. On our own server, the fail2ban rule for scanners banned 8 addresses on its own within the first hour after we enabled it — all of them looking for .env files and WordPress login pages on a PrestaShop shop.
The foundation: system, PHP and firewall
No configuration helps if the server runs software that no longer gets security fixes. Start with the basics:
| Item | What to do | Why |
|---|---|---|
| System | turn on automatic security updates (on Ubuntu, unattended-upgrades) | patches reach the server within a day, without waiting for an administrator |
| PHP | a version with security support | PHP 8.1 has had no fixes since the end of 2025; PHP 8.2 gets them only until the end of 2026 |
| Firewall | deny incoming traffic by default, open only 80, 443 and SSH | the database, admin tools and helper services are not reachable from the internet |
| MySQL | listen locally only, a separate database user for the shop | a leaked database password gives no access from outside |
| Shop files | a separate system user, write access only where PrestaShop needs it | a script uploaded through a module flaw cannot overwrite the rest of the shop |
PHP is a common problem for shops on PrestaShop 8, which runs on PHP 8.1 at most. Moving to a newer PHP means upgrading the shop — our guide How to upgrade PrestaShop without losing data shows how.
In the nginx configuration, also block access to folders that should not be public and stop PHP from running in upload folders. The official example in the PrestaShop documentation rejects requests for .php files in img/ and upload/, hidden files and the app, config, classes and vendor folders. Even if someone uploads a script through a form, it will not run.
Secure login: SSH and the PrestaShop back office
SSH with keys only, no root
An SSH password can be guessed; a key, in practice, cannot. In /etc/ssh/sshd_config, turn off password login and the root account, and allow only selected users:
PasswordAuthentication no
PermitRootLogin no
MaxAuthTries 3
AllowUsers admin shop
Every developer who works on the server should have their own account and key. When the work ends, you remove one key instead of changing a shared password.
The PrestaShop back office
- A unique admin folder — the PrestaShop installer gives it a random name. Do not rename it to
adminand do not publish it in links. - Separate employee accounts in Advanced Parameters → Team → Employees, with no shared logins. Delete the accounts of people who no longer work on the shop straight away.
- Tie the session to the IP address: the Check the cookie's IP address option in Advanced Parameters → Administration makes a stolen cookie harder to reuse.
- Access from known addresses: if your team works from fixed IP addresses or through a VPN, restrict the admin folder to them in nginx. It is the most effective protection against password guessing.
- A second login factor: OWASP calls multi-factor authentication the strongest single defence against account takeover. If your version of the shop does not have it, add it with a module or restrict the back office by IP.
fail2ban: blocking attacks automatically
fail2ban reads the server logs and blocks, in the firewall, addresses that behave like attackers: a few failed logins, a series of requests for files that do not exist, an exceeded request limit. The ban lasts for a set time, and an address that comes back gets a longer one. It is a simple and effective defence against password guessing and scanners.
For a PrestaShop server, these rules (jails) from a standard fail2ban installation are useful:
| Jail | What it blocks |
|---|---|
sshd | guessing SSH passwords and user names |
nginx-http-auth | guessing passwords for password-protected folders (e.g. phpMyAdmin) |
nginx-limit-req | addresses that exceed the request limit set in nginx |
nginx-botsearch | scanners looking for admin pages and files your shop does not have |
recidive | addresses banned again and again — they get a ban lasting days |
An example from /etc/fail2ban/jail.local:
[sshd]
enabled = true
maxretry = 4
findtime = 10m
bantime = 1h
[recidive]
enabled = true
bantime = 1w
You set request limits in nginx with the limit_req module. The pages that matter most are those that load the server or accept passwords: customer login, the back office, search. Nginx then answers with a 429 code, and fail2ban bans the address that keeps doing it.
limit_req_zone $binary_remote_addr zone=login:10m rate=10r/m;
location ~ ^/(login|fr/connexion)$ {
limit_req zone=login burst=5 nodelay;
try_files $uri /index.php?$args;
}
Important: behind Cloudflare, every request comes from a Cloudflare address. Unless nginx restores the real client IP (the
CF-Connecting-IPheader), fail2ban will ban Cloudflare instead of the attacker, and request limits will apply to all your customers at once. Bans for traffic that passes through Cloudflare also have to be sent to Cloudflare — fail2ban ships ready-madecloudflareandcloudflare-tokenactions for this.
Cloudflare in front of PrestaShop
Cloudflare sits between your customers and your server. When your shop's DNS record is proxied (the orange cloud), visitors see a Cloudflare address and the traffic goes through its filters. Even the free plan gives you:
- DDoS protection at layers 3, 4 and 7 — according to Cloudflare's documentation, with no limit on the size or duration of an attack, on every plan.
- A WAF with the Free Managed Ruleset and your own custom rules, for example blocking countries you do not sell to from the back office.
- One rate limiting rule — worth using for login or search.
- Bot Fight Mode and an option to block AI bots.
- Caching of static files (images, CSS, JS), which takes load off the server. By default Cloudflare does not cache HTML pages, and that is right — the cart and the customer account must always be current. Do not turn on "Cache Everything" for the whole shop.
Set encryption to Full (strict), so the connection between Cloudflare and your server is encrypted and verified too, and restore real client addresses in nginx: the realip module, set_real_ip_from with Cloudflare's IP ranges and real_ip_header CF-Connecting-IP. Without it, logs, statistics and bans only ever see Cloudflare addresses.
DDoS protection
A DDoS (distributed denial of service) attack floods your shop with traffic from thousands of addresses at once so that it stops responding. There are two main kinds:
- Volumetric attacks (layers 3 and 4) — millions of packets that saturate the server's connection. No firewall on the server itself can stop them, because the link is full before the packets arrive. Only filtering in front of the server helps, for example in Cloudflare.
- Application attacks (layer 7, HTTP flood) — ordinary-looking requests to expensive pages: search, filters, the cart. A few hundred per second are enough for PHP and the database to fall behind. Here, request limits, caching and WAF rules help.
Cloudflare only protects you if the attacker does not know your server's real address. If they do, they send traffic straight to it and bypass all the protection. That is why you should:
- Hide the server address. Check every DNS record: subdomains such as
ftp,mailordevwithout the proxy give the address away. Emails sent from the shop server carry it in their headers — send them through an external SMTP server. - Change the IP address after you switch Cloudflare on. The old address may already be stored in historical DNS databases.
- Accept HTTP traffic only from Cloudflare. In the firewall, open ports 80 and 443 only to Cloudflare's ranges, or turn on Authenticated Origin Pulls — a certificate Cloudflare uses to prove its connections.
- Take load off the server with caching. Every image and CSS file served by Cloudflare is a request that never reaches PHP. We cover caching on the shop side in How to speed up PrestaShop.
- Have a plan for an attack. Cloudflare's "I'm Under Attack" mode shows every visitor a short browser check while the attack lasts. You turn it on with one button.
Tip: set separate request limits in nginx and Cloudflare for search and product filters. They are the most common target of HTTP floods on shops, because each such query costs the database far more than an ordinary page.
Bots: good, bad and AI
A large share of a shop's traffic comes from bots. Not all of them should be blocked:
- Good bots — Googlebot, Bingbot, Google Merchant Center, price comparison sites. Without them, your shop disappears from search results and ads. Be careful: anyone can claim to be Googlebot. Google recommends checking the address with a reverse DNS lookup (the name must end in
googlebot.com,google.comorgoogleusercontent.com) followed by a forward lookup of that name. - Bad bots — vulnerability scanners, password guessers, bots that copy your prices and content or create fake accounts. Bot Fight Mode, request limits, traps for typical scanner paths (such as
/wp-login.phpor/.env) and fail2ban work against them. - AI bots — crawlers collecting content for language models. Some respect
robots.txt, but the file is only a request, not a block. If you do not want to share your content, turn on AI bot blocking in Cloudflare.
Protect contact and registration forms from spam with a CAPTCHA, and logins with an attempt limit. That way you do not need to block whole countries or networks, which could cut off real customers.
Logs, monitoring and backups
You need to see your defences at work. Turn on and review:
- nginx logs (traffic and errors) — they show scanning, sudden traffic spikes and 5xx errors.
- PHP-FPM slowlog — scripts that run too long, often the first sign of an attack on search or a faulty module.
- MySQL slow query log — slow database queries that bring the shop down under higher traffic.
- External monitoring — shop availability every minute, server resources, SSL certificate expiry. Alerts must reach someone who will act on them.
- Backups — files and database every day, several days back, also stored outside the server itself. A backup that has never been restored is only a hope: test a restore at least once.
If you are not sure what state your shop and server are in, start with a store security audit: you get a list of vulnerabilities with a risk rating and an estimated fix time.
Server security checklist
| Area | What to check |
|---|---|
| Updates | automatic system patches, a supported PHP, an up-to-date PrestaShop and modules |
| Access | SSH with keys only, no root, separate developer accounts, a unique admin folder |
| Firewall | only 80, 443 and SSH open; MySQL not reachable from outside |
| fail2ban | sshd, nginx-limit-req, nginx-botsearch and recidive jails |
| nginx | request limits, no PHP in img/ and upload/, security headers and HSTS |
| Cloudflare | proxy, Full (strict), WAF, Bot Fight Mode, real client IPs in nginx |
| DDoS | hidden server address, HTTP traffic only from Cloudflare, a plan for "Under Attack" mode |
| Backups and logs | daily backups with a test restore, PHP and MySQL slow logs, monitoring with alerts |
Would you rather not do all this yourself? With our PrestaShop server and administration service, we set up the server along this checklist, move your shop to it and look after it day to day.
Sources
- Cloudflare: About DDoS protection — layer 3, 4 and 7 protection on all plans.
- Cloudflare: Protect your origin server — hiding the origin address, Cloudflare-only traffic, Authenticated Origin Pulls.
- Cloudflare: Restoring original visitor IPs and Cloudflare IP ranges.
- Cloudflare WAF and bot protection on the Free plan.
- fail2ban — official repository (jails and actions, including
cloudflare-token). - nginx: ngx_http_limit_req_module.
- PrestaShop: Configure Nginx (developer documentation).
- OpenSSH: sshd_config.
- Ubuntu Server: Automatic updates.
- PHP: Supported versions.
- Google: Verify requests from Google crawlers.
- OWASP: Credential Stuffing Prevention Cheat Sheet.
- Friends of Presta: PrestaShop security advisories.
Frequently asked questions
Is the free Cloudflare plan enough for a shop?
For most small and medium shops, yes. The Free plan includes unmetered DDoS protection, a basic WAF ruleset, one rate limiting rule and Bot Fight Mode. Paid plans add more rules, better bot detection and support, which help with heavy traffic or frequent attacks.
Does fail2ban work behind Cloudflare?
Yes, but it needs two things. Nginx has to log the real client address from the CF-Connecting-IP header, and bans have to be sent to Cloudflare (the cloudflare-token action), because proxied traffic arrives from Cloudflare addresses. Bans in the server firewall still work for SSH and direct traffic.
Does changing the SSH port improve security?
It cuts down the number of automated attempts in your logs a little, but it does not stop anyone who scans your ports. The real protection is key-only login, no root account and fail2ban. A different port can be an extra, not a replacement.
How do I check that it is really Googlebot?
Run a reverse DNS lookup on the address from your logs (e.g. host 66.249.66.1). The name must end in googlebot.com, google.com or googleusercontent.com, and looking up that name must return the same address. The user agent in your logs proves nothing, because it is easy to fake.
Can I secure a shop like this on shared hosting?
Only partly. Cloudflare, an up-to-date PrestaShop, strong passwords and backups work anywhere, but the firewall, fail2ban, nginx configuration and PHP versions depend on your host. For a larger shop, your own VPS gives you full control over security and performance.
Want someone to secure your shop's server and keep an eye on it every day? Contact us and we will tell you where to start.