Skip to content
Back to Blog
Security10 min read

How to Prevent Data Breaches: 6 Controls That Work

Six prioritized security controls—from access management to incident response—that reduce breach risk in hosting environments without enterprise overhead.

Written by Abdul AbrorTechnical Hosting Support Engineer
How to Prevent Data Breaches: 6 Controls That Work
On this page

Most breaches happen because basic controls were missing or misconfigured. Not zero-days. Not APTs. Just open database ports, default passwords, unpatched software, and no one noticing the intrusion for weeks.

I've seen customer servers compromised through phpMyAdmin left at /phpmyadmin with root access and no password. SSH brute-forced because password auth was still enabled. WordPress sites serving malware because a plugin hadn't been updated in two years. The six controls below won't stop nation-state actors, but they will stop the automated scans and opportunistic attacks that cause most breaches in shared hosting and VPS environments.

1. Lock Down Access at Every Layer

Start with SSH. Disable password authentication entirely and use keys.

# /etc/ssh/sshd_config
PasswordAuthentication no
PermitRootLogin prohibit-password
PubkeyAuthentication yes

Restart sshd after changes. Move SSH to a non-standard port if you want to cut down on log noise from bots, but key-only auth is what actually matters.

For web applications, enforce strong passwords and enable two-factor authentication everywhere it's available. cPanel, WHM, WordPress admin, database management tools—every login surface needs 2FA. WordPress plugins like WP 2FA or Wordfence handle this without much configuration.

Database access is where I see the most mistakes. MySQL and PostgreSQL should never listen on public interfaces unless you have a specific architectural reason and firewall rules to match.

# /etc/my.cnf or /etc/mysql/my.cnf
[mysqld]
bind-address = 127.0.0.1

Applications connect locally. Remote admin happens through SSH tunnels. If you need a GUI tool, tunnel it:

ssh -L 3306:localhost:3306 [email protected]

Then point your local MySQL client to localhost:3306. The connection is encrypted and you're not exposing port 3306 to the internet.

Finally, apply least privilege to file permissions. Web server processes should not own the files they serve. On a typical LAMP stack, files should be owned by your user account and readable by the www-data or apache group. Writable directories (uploads, cache) need careful ACLs, not 777.

chown -R youraccount:www-data /var/www/html
find /var/www/html -type d -exec chmod 755 {} \;
find /var/www/html -type f -exec chmod 644 {} \;

Adjust upload directories as needed, but make them specific.

2. Encrypt Data Everywhere It Sits and Moves

Encryption in transit is non-negotiable now. Every site needs a valid TLS certificate, and Let's Encrypt makes this free and automated. In cPanel, AutoSSL handles it. On a plain VPS, Certbot does the job.

sudo certbot --apache -d example.com -d www.example.com

Set up a cron job to renew:

0 3 * * * certbot renew --quiet

Force HTTPS by redirecting all HTTP traffic. In Apache, add this to your VirtualHost or .htaccess:

RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]

For Nginx:

server {
    listen 80;
    server_name example.com www.example.com;
    return 301 https://$server_name$request_uri;
}

Don't forget SMTP. Mail servers should enforce TLS for submission (port 587) and reject plaintext auth. In Postfix:

# /etc/postfix/main.cf
smtpd_tls_security_level = encrypt
smtpd_tls_auth_only = yes

Encryption at rest protects you if physical hardware is stolen or when decommissioning drives. Full-disk encryption with LUKS is the standard approach on Linux. For existing servers, enabling it requires a rebuild, so plan it during initial provisioning or migration.

Database-level encryption (like MySQL's tablespace encryption) and application-level encryption (encrypting sensitive columns before storing them) are alternatives when full-disk encryption isn't feasible. The tradeoff is complexity and key management.

Backups need encryption too. Whether you're using rsync, Duplicity, or a managed backup service, ensure the archives are encrypted before they leave the server. Duplicity does this by default with GPG:

duplicity /var/www/html s3://bucket-name/backups --encrypt-key YOUR_GPG_KEY

3. Turn On Audit Logging and Actually Read It

Logs are how you detect breaches in progress or understand what happened after the fact. Enable detailed logging for SSH, sudo, web server access, application errors, and authentication events.

Most distributions log SSH and sudo to /var/log/auth.log or /var/log/secure. Make sure that's happening:

tail -f /var/log/auth.log

For Apache, set a custom log format that captures more detail:

LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %D" combined_plus
CustomLog /var/log/apache2/access.log combined_plus

The %D at the end logs request duration in microseconds, which helps spot slow or suspicious requests.

WordPress and other CMSs have their own activity log plugins. WP Activity Log and Simple History record admin actions, login attempts, file changes, and plugin installs. Install one and configure it to keep at least 30 days of history.

Centralize logs if you manage multiple servers. Syslog forwarding to a dedicated log host or a service like Papertrail keeps logs safe even if a compromised server is wiped. In rsyslog:

# /etc/rsyslog.conf
*.* @@loghost.example.com:514

That forwards everything via TCP. Use TLS if your log server supports it.

Set up alerts for critical events: root logins, sudo usage, repeated failed auth attempts, changes to /etc/passwd or shadow, modifications to web root directories. A simple script watching auth.log with grep and sending an email is better than nothing:

#!/bin/bash
tail -Fn0 /var/log/auth.log | grep --line-buffered 'session opened for user root' | while read line; do
  echo "$line" | mail -s "Root login detected" [email protected]
done

Run it in a screen session or as a systemd service.

4. Scan for Vulnerabilities Before Attackers Do

Patch management is the single highest-impact control after access management. Outdated software is still the leading entry point. Automate security updates where possible.

On Debian and Ubuntu, unattended-upgrades handles this:

sudo apt install unattended-upgrades
sudo dpkg-reconfigure -plow unattended-upgrades

Configure it to apply security updates automatically and email you a report.

For CentOS and RHEL, yum-cron does the same:

sudo yum install yum-cron
sudo systemctl enable yum-cron
sudo systemctl start yum-cron

Edit /etc/yum/yum-cron.conf to set apply_updates = yes for automatic patching.

cPanel servers have a built-in update system (cPanel & WHM Update in WHM). Enable automatic updates unless you need to test them first in a staging environment.

Web application vulnerabilities need a different approach. WPScan for WordPress, OWASP ZAP or Nikto for general web scanning. Run them monthly or after major changes.

wpscan --url https://example.com --enumerate vp,vt,u

That enumerates vulnerable plugins, themes, and users. Fix what it finds.

For server-level scanning, Lynis is a solid open-source auditing tool:

sudo lynis audit system

It checks hardening status, file permissions, running services, kernel parameters, and more. The report includes a hardening index and specific suggestions. Run it quarterly and act on high-priority findings.

Vulnerability scanners generate noise. Focus on remotely exploitable issues first—RCE, SQLi, auth bypass. Fix those before spending time on low-severity findings that require local access.

5. Back Up Everything and Test the Restores

Backups don't prevent breaches but they limit the damage. Ransomware, data corruption, accidental deletion—backups are your fallback when prevention fails.

Three copies, two media types, one offsite. That's the 3-2-1 rule. In practice, that means:

  • Live data on the server
  • Local backup on the same server or a nearby storage volume
  • Remote backup to a different location (S3, offsite server, cloud storage)

Automate daily backups and retain enough history to go back before an incident was noticed. Thirty days is a reasonable baseline. For critical systems, keep weekly backups for a year.

Here's a simple rsync-based backup to a remote server:

#!/bin/bash
rsync -avz --delete /var/www/html/ backup@remote:/backups/html/
rsync -avz /var/lib/mysql/ backup@remote:/backups/mysql/

Add it to cron for 2 AM daily. The --delete flag mirrors deletions, so keep versioned backups on the remote side or use snapshots.

For MySQL, dump databases before backing up:

mysqldump --all-databases --single-transaction > /backup/mysql-$(date +%F).sql

Then back up the dump files.

Test restores at least quarterly. Pick a random backup, spin up a test server, and restore it. Time how long it takes and document any missing steps. A backup you've never restored is Schrödinger's backup.

Store backups encrypted and ensure the decryption keys are accessible during a disaster but not on the same server as the backups themselves. A password manager with offline export capability works for small setups.

6. Have an Incident Response Plan Written Down

When you discover a breach, you need a checklist, not a brainstorming session. Document your response steps before an incident happens.

Your plan should cover:

  • Who gets notified first (your team, hosting provider, customers)
  • How to isolate compromised systems without destroying evidence
  • Where logs and backups are stored
  • How to preserve forensic data (copy logs, snapshot disks)
  • Steps to contain the breach (kill processes, block IPs, disable accounts)
  • How to communicate with affected users and regulatory bodies if required
  • Post-incident review process

A simple runbook is enough. Mine looks like this:

  1. Confirm the breach (check logs, running processes, network connections)
  2. Notify the team via Signal group
  3. Isolate affected server (firewall rules or pull from load balancer)
  4. Snapshot disk and copy logs to secure location
  5. Identify entry point and scope (what data was accessed)
  6. Contain (kill malicious processes, revoke credentials, block IPs)
  7. Eradicate (remove malware, close vulnerability, patch system)
  8. Restore from clean backup if necessary
  9. Monitor for re-infection (check logs hourly for 48 hours)
  10. Document timeline and root cause
  11. Notify affected parties within 72 hours if personal data involved
  12. Update security controls and runbook based on lessons learned

Store this document somewhere accessible during an outage—not just on the server that might be compromised. A printed copy, a USB drive, or a separate cloud account all work.

Practice the plan. Schedule a tabletop exercise where you walk through a scenario: "WordPress admin account compromised, attacker uploaded a web shell." Talk through each step, identify gaps, update the runbook.

The goal is to reduce decision fatigue when you're under pressure. You want to execute a checklist, not figure out next steps while an attacker is still in the system.

Start With Access and Build From There

You don't need to implement all six controls at once. Prioritize them.

Week one: lock down SSH and database access, enforce 2FA on admin panels. Week two: get TLS certificates deployed and force HTTPS. Week three: enable automatic security updates and set up log forwarding. Week four: configure backups and test a restore. Month two: run vulnerability scans and write your incident response runbook.

Most breaches exploit gaps in basic hygiene. Close those gaps and you're ahead of the majority of internet-facing servers. The controls above won't make you invincible but they will make you a much harder target than the next server over.