When a critical vulnerability like PHP2Shell appears, well-hardened servers have two big advantages: they get patched faster, and an attacker who does get in can do much less damage.
This checklist covers 30 practical steps for Linux servers running websites and web shops (Nginx or Apache, PHP, MySQL/MariaDB). Most commands are for Ubuntu/Debian; the principles apply to every distribution.
Access and SSH
1. Use SSH keys, disable password login
In /etc/ssh/sshd_config:
PasswordAuthentication no
KbdInteractiveAuthentication no
PubkeyAuthentication yes
2. Disable direct root login
PermitRootLogin no
Log in as a normal user and use sudo.
3. Limit who can log in
AllowUsers deploy admin
4. Restrict SSH by IP where possible
Allow SSH only from your office, VPN or bastion host in the firewall.
5. Add brute-force protection
Use fail2ban or a similar tool to block repeated failed logins.
6. Give every person their own account
No shared logins. Remove accounts and keys of people who left.
Firewall and network
7. Default deny
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow 22/tcp
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable
8. Do not expose databases and caches
MySQL (3306), Redis (6379), OpenSearch (9200) and similar services should listen on 127.0.0.1 or a private network only.
9. Consider restricting outgoing traffic
A web server rarely needs to connect anywhere except APIs, package mirrors and mail. Restricting egress makes it harder for attackers to download tools or exfiltrate data.
10. Put admin panels behind extra protection
/wp-admin, Magento admin, phpMyAdmin, monitoring dashboards: IP allowlist, VPN or an extra authentication layer.
Updates
11. Enable automatic security updates
sudo apt install unattended-upgrades
sudo dpkg-reconfigure -plow unattended-upgrades
12. Restart services after updates
Updated libraries and PHP versions only take effect after a restart. Tools like needrestart show which services still run old code.
13. Stay on supported versions
OS releases and PHP versions have end-of-life dates. Unsupported versions get no security fixes.
14. Subscribe to security announcements
Your distribution’s security list, PHP announcements and your application’s security advisories.
PHP and application isolation
15. Use PHP-FPM instead of mod_php
PHP-FPM runs PHP in separate processes with their own user, which gives better isolation and control.
16. One FPM pool and user per site
If one site is compromised, the attacker should not be able to read the files of other sites.
[shop]
user = shop
group = shop
listen = /run/php/php8.3-fpm-shop.sock
17. Restrict file permissions
Code should not be writable by the web server user, except for specific upload, cache and log directories.
18. Block PHP execution in upload folders
Nginx example:
location ~* ^/wp-content/uploads/.*\.php$ {
deny all;
}
19. Harden php.ini
expose_php = Off
display_errors = Off
log_errors = On
allow_url_include = Off
Disable session.upload_progress if you do not need it. It is also one of the attack paths in PHP2Shell.
20. Keep secrets out of the web root
.env files, backups, Git folders and SQL dumps should never be reachable via HTTP. Block /.git and dotfiles explicitly.
Web server
21. TLS only, with modern settings
Redirect HTTP to HTTPS, disable old protocols (TLS 1.0/1.1) and renew certificates automatically.
22. Add security headers
Strict-Transport-Security, X-Content-Type-Options, Referrer-Policy, and a Content-Security-Policy where possible.
23. Limit request sizes
Set client_max_body_size (Nginx) or LimitRequestBody (Apache) to what your application needs.
24. Hide version information
server_tokens off; in Nginx, ServerTokens Prod in Apache.
Database
25. Separate database users per application
With only the privileges the application needs. No application should use the MySQL root user.
26. Strong passwords, no remote root
Run mysql_secure_installation or the equivalent on new servers.
Monitoring and response
27. Centralise logs
Send web server, PHP, auth and system logs to a central location the web server cannot modify.
28. Monitor file changes
Alert on new PHP files in upload folders and changes to core files.
29. Monitor uptime, resources and certificates
Unexpected CPU spikes, outgoing traffic or crashing PHP workers often signal problems.
Backups
30. Off-site, versioned, tested backups
Follow the 3-2-1 rule and test restores regularly. See my server backup strategy guide.
Quick priority list
If you only have one hour, do these first:
- Patch OS and PHP, restart services
- SSH keys only, no root login
- Firewall: only 22, 80, 443 open
- Databases and Redis not public
- Off-site backups running and monitored
Frequently asked questions
Do I need a hardening checklist if I use managed hosting?
The host handles part of it (OS, firewall, often PHP). You are still responsible for application updates, user accounts, file permissions and backups. Ask your host which parts they cover.
Is a control panel like cPanel or Plesk less secure?
Not necessarily, but it adds software that also needs updates. Keep it patched and restrict access to the panel.
How often should I review server security?
Run a quick review monthly and a full review at least once a year, and after major changes.
Want your servers hardened?
I set up, harden and maintain Linux servers for web shops and business applications, including patching, monitoring and backups. See my servers and backups service or request a security review.