Why hardening beats detection every time
Ransomware groups scan the internet for weak SSH, open RDP, and unpatched services 24/7. Once they land on a box, they spread laterally, escalate privileges, delete your backups, and encrypt everything in under an hour. Detection tools slow them down; hardening stops them from getting in.
The server changes below assume a Linux VPS or dedicated box running a web stack, mail services, or databases. Most apply to cPanel servers too. Windows RDP hardening is similar in principle but uses different tooling.
Step 1: Lock SSH down to key-only auth
Password auth is the easiest way in. Disable it.
Edit /etc/ssh/sshd_config:
PasswordAuthentication no
ChallengeResponseAuthentication no
PermitRootLogin prohibit-password
Restart SSH:
systemctl restart sshd
Before you close the terminal, test login in a second session with your key to confirm you aren't locked out. If root login must stay enabled, use PermitRootLogin without-password on older distros or the prohibit-password directive on systemd-based systems. Both mean the same thing: keys only.
Move the SSH port from 22 to something between 10000 and 65000 to drop automated scans by 90 percent. Not security through obscurity—just noise reduction. Combine it with Fail2Ban watching auth logs, and you cut brute-force attempts to near zero.
Step 2: Deploy immutable or offline backups
If ransomware can reach your backups, they're gone. The first thing attackers do after gaining access is hunt for mounted backup drives, S3 buckets with write keys, and snapshot APIs.
Immutable backups use object-lock or append-only modes so files can't be deleted or modified for a set retention period. AWS S3 Object Lock, Backblaze B2 with retention, and Wasabi immutability all do this. Once the snapshot is written, even the root account can't touch it until the lock expires.
Set retention to match your recovery point objective. Seven days is the minimum; 30 days is safer if you need time to detect silent corruption before the original backup rotates out.
Offline or air-gapped backups live on external drives or tape that disconnect after the backup window. Less convenient but immune to network-based attacks. For VPS environments, use a cron job that writes to a secondary cloud account with write-once credentials, then rotates the key.
Test restoration monthly. A backup you've never restored is just hope.
Step 3: Harden file permissions and disable unused SUID binaries
Ransomware escalates privileges by exploiting SUID binaries—executables that run with the file owner's permissions instead of the caller's. The fewer SUID binaries on your system, the smaller the attack surface.
Find every SUID file:
find / -perm -4000 -type f 2>/dev/null
Review the list. Common legitimate binaries include sudo, passwd, ping, and mount. If you see anything unfamiliar, check its purpose. Remove the SUID bit from anything you don't need:
chmod u-s /path/to/binary
For web directories, enforce strict ownership. The web server user should own web files, and application directories should be 755 or 750. Never 777. Inside a typical WordPress or Laravel install:
chown -R www-data:www-data /var/www/html
find /var/www/html -type d -exec chmod 755 {} \;
find /var/www/html -type f -exec chmod 644 {} \;
If ransomware lands in a web shell, these permissions limit where it can write.
Step 4: Install and monitor file integrity with AIDE or Tripwire
File integrity monitoring (FIM) creates cryptographic hashes of critical system files and alerts you when anything changes. If /bin/bash suddenly has a different checksum, you know something is wrong.
AIDE (Advanced Intrusion Detection Environment) is open-source and runs on most Linux distros. Install it:
apt install aide # Debian/Ubuntu
yum install aide # CentOS/RHEL
Initialize the database:
aide --init
mv /var/lib/aide/aide.db.new.gz /var/lib/aide/aide.db.gz
Run a check:
aide --check
Schedule daily checks with cron and send results to an external email or logging service. If the results stay on the server, ransomware will delete them.
FIM won't stop encryption, but it tells you when binaries or configs change. In support tickets I handled, the usual alert was a modified cron file or a new entry in /etc/passwd hours before the encryption payload ran.
Step 5: Use AppArmor or SELinux to confine services
Mandatory access control (MAC) frameworks confine processes to a predefined set of actions. Even if an attacker compromises Apache or MySQL, the MAC policy prevents the process from touching files outside its allowed paths.
Ubuntu and Debian ship with AppArmor enabled. Check status:
aa-status
If Apache is in complain mode, switch it to enforce:
aa-enforce /etc/apparmor.d/usr.sbin.apache2
CentOS and RHEL use SELinux. Confirm it's running:
getenforce
If it returns Permissive, switch to Enforcing in /etc/selinux/config and reboot.
MAC policies take time to tune. Applications throw permission errors until you adjust the profile. The effort is worth it—ransomware that lands in a confined service hits a wall immediately.
Step 6: Patch the OS and software stack weekly
Unpatched services are the second most common ransomware entry point after weak credentials. Attackers scan for known CVEs in Exim, Apache, PHP, and kernel modules, then drop an exploit.
Automate updates on Debian-based systems:
apt install unattended-upgrades
dpkg-reconfigure -plow unattended-upgrades
On RHEL-based systems, enable yum-cron or dnf-automatic.
For cPanel servers, enable automatic updates in WHM under Server Configuration > Update Preferences. Set it to update the OS daily and cPanel/WHM on the stable release track.
Patch third-party software too. If you run WordPress, Nextcloud, or custom apps, subscribe to their security mailing lists and apply updates within 48 hours of release. Most ransomware campaigns start within a week of a public vulnerability disclosure.
What if you need to allow risky services?
Sometimes you must expose RDP, database ports, or legacy protocols. Whitelist access by IP.
For SSH, use AllowUsers or AllowGroups in sshd_config:
AllowUsers [email protected]
For other services, use firewall rules. With ufw:
ufw allow from 203.0.113.10 to any port 3306
With firewalld:
firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="203.0.113.10" port port="3306" protocol="tcp" accept'
firewall-cmd --reload
VPN access is cleaner. Put the server behind WireGuard or OpenVPN and close public ports entirely. Adds one step to your workflow but removes the server from public scans.
Step 7: Disable unused network services and close ports
Every open port is a potential entry point. List listening services:
ss -tuln
If you see ports you don't recognize, find the process:
sudo lsof -i :PORT
Disable services you don't use:
systemctl disable SERVICE_NAME
systemctl stop SERVICE_NAME
Common candidates: rpcbind, avahi-daemon, cups, and postfix (if you use an external mail relay). Close the ports in your firewall afterward.
Step 8: Enable audit logging and forward logs off-server
The Linux audit framework (auditd) logs system calls, file access, and authentication events. If ransomware runs, audit logs show you what it touched.
Install auditd:
apt install auditd # Debian/Ubuntu
yum install audit # CentOS/RHEL
Add rules to watch sensitive directories. Edit /etc/audit/rules.d/audit.rules:
-w /etc/passwd -p wa -k identity
-w /etc/shadow -p wa -k identity
-w /bin/ -p wa -k binaries
-w /usr/bin/ -p wa -k binaries
-w /var/www/ -p wa -k webroot
Restart the service:
systemctl restart auditd
Forward logs to an external syslog server or cloud logging platform (Papertrail, Logtail, or a self-hosted Graylog instance). Ransomware will wipe local logs to cover its tracks. Remote logs survive.
Step 9: Run periodic permission and backdoor scans
Schedule a weekly scan for world-writable files and directories:
find / -type f -perm -002 2>/dev/null > /root/world-writable-files.txt
find / -type d -perm -002 2>/dev/null > /root/world-writable-dirs.txt
Review the output. Temp directories like /tmp and /var/tmp are expected, but if you see web directories or home folders, fix them.
For web servers, scan for common PHP backdoors:
grep -r "eval(base64_decode" /var/www/
grep -r "system(\$_GET" /var/www/
Use rkhunter or chkrootkit to scan for rootkits:
apt install rkhunter
rkhunter --check --skip-keypress
False positives are common, so compare results over time. A new warning is worth investigating. An old one you've already cleared is noise.
Quick answers to common questions
How often should I test backups?
Monthly at minimum. Restore a full snapshot to a test VM and verify the application starts. Quarterly fire drills are even better.
Will immutable backups slow down my backup window?
No. Object-lock is a metadata flag set after the upload completes. Write speed stays the same.
Can I run AIDE checks more than once a day?
Yes, but each check consumes CPU and disk I/O. Hourly checks make sense for high-security environments; daily checks are enough for most hosting setups.
Does changing the SSH port actually help?
It stops automated scanners. Determined attackers will still find it with a port scan, but you drop 90 percent of the noise and reduce log clutter.
What if SELinux breaks my application?
Switch to permissive mode, reproduce the error, and check /var/log/audit/audit.log for denials. Use audit2allow to generate a policy module that permits the necessary access.
Lock the doors before the next scan
Ransomware attack prevention isn't a one-time checklist. Patch weekly, review logs, test your restore process, and harden each new service before it goes live. The steps above stop the majority of automated attacks and force human operators to work much harder for access.
Most ransomware campaigns succeed because of weak SSH passwords, missing backups, or services running as root with no MAC policy. Fix those three, and you're already ahead of 80 percent of targets. Add the rest, and attackers move on to easier infrastructure.
