Skip to content
Back to Blog
Security11 min read

How to Prevent Data Breaches: 6 Controls That Work

A step-by-step walkthrough of the six security controls that actually stop data breaches, with real commands and config examples you can deploy today.

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

Most data breaches happen because of missing basics, not zero-day exploits. In support tickets I've handled, the pattern is always the same: weak passwords, unpatched software, no monitoring, and services exposed to the internet that shouldn't be. The good news? Six controls, properly configured, stop the majority of attacks before they start.

This is a practical walkthrough. You'll implement access controls, encrypt sensitive data, set up monitoring, automate patching, configure backups, and segment your network. Each section includes the commands and config you need.

1. Lock down access with least privilege

Start here. Every breach investigation traces back to compromised credentials or excessive permissions. Your goal is simple: every user and service gets exactly the access it needs, nothing more.

Audit current access

Before you restrict anything, see what you're working with.

# List all users with shell access
grep -vE '(nologin|false)$' /etc/passwd

# Check sudo permissions
sudo cat /etc/sudoers
sudo ls -la /etc/sudoers.d/

# List SSH authorized keys for all users
for user in $(cut -d: -f1 /etc/passwd); do
  key_file="/home/$user/.ssh/authorized_keys"
  [ -f "$key_file" ] && echo "$user: $(wc -l < $key_file) keys"
done

Remove any accounts you don't recognize. Disable shell access for service accounts that don't need it by changing their shell to /sbin/nologin.

Implement SSH key authentication

Password authentication is a liability. Disable it.

On your local machine, generate a key if you don't have one:

ssh-keygen -t ed25519 -C "[email protected]"

Copy it to the server:

ssh-copy-id -i ~/.ssh/id_ed25519.pub user@your-server

Test the key-based login, then disable password auth. Edit /etc/ssh/sshd_config:

PasswordAuthentication no
PermitRootLogin prohibit-password
PubkeyAuthentication yes

Restart SSH:

sudo systemctl restart sshd

Set up sudo with limited scope

Don't give users full sudo. Grant specific commands instead. Create a file /etc/sudoers.d/limited-access:

# Allow www-data to restart web services
www-data ALL=(ALL) NOPASSWD: /bin/systemctl restart nginx, /bin/systemctl restart php*-fpm

# Allow backup user to run backup script only
backup ALL=(ALL) NOPASSWD: /usr/local/bin/backup.sh

Validate syntax before saving:

sudo visudo -c -f /etc/sudoers.d/limited-access

Enforce multi-factor authentication

For SSH, use Google Authenticator PAM module.

sudo apt install libpam-google-authenticator  # Debian/Ubuntu
sudo yum install google-authenticator          # RHEL/CentOS

Run the setup as each user:

google-authenticator

Save the emergency codes. Edit /etc/pam.d/sshd and add:

auth required pam_google_authenticator.so

In /etc/ssh/sshd_config, set:

ChallengeResponseAuthentication yes
AuthenticationMethods publickey,keyboard-interactive

Restart SSH. Now every login requires both the key and a TOTP code.

2. Encrypt data at rest and in transit

Encryption is non-negotiable for any system holding user data, credentials, or payment information.

Enable full-disk encryption

If you're provisioning a new server, use LUKS during installation. For existing systems, encrypting the root partition requires a rebuild, but you can encrypt data partitions.

Create an encrypted volume:

sudo cryptsetup luksFormat /dev/sdb1
sudo cryptsetup luksOpen /dev/sdb1 encrypted_data
sudo mkfs.ext4 /dev/mapper/encrypted_data

Mount it:

sudo mkdir /mnt/secure
sudo mount /dev/mapper/encrypted_data /mnt/secure

To auto-mount at boot, add a key file and update /etc/crypttab and /etc/fstab. Store the key file with restricted permissions.

Encrypt database connections

For MySQL/MariaDB, generate SSL certificates:

sudo mysql_ssl_rsa_setup --uid=mysql

Edit /etc/mysql/my.cnf:

[mysqld]
require_secure_transport=ON
ssl-ca=/var/lib/mysql/ca.pem
ssl-cert=/var/lib/mysql/server-cert.pem
ssl-key=/var/lib/mysql/server-key.pem

Restart MySQL. Verify:

mysql -u root -p -e "SHOW VARIABLES LIKE '%ssl%';"

Update application connection strings to use SSL. Most drivers support a ?ssl=true parameter.

Force HTTPS everywhere

Get a free Let's Encrypt certificate:

sudo apt install certbot python3-certbot-nginx
sudo certbot --nginx -d yourdomain.com -d www.yourdomain.com

Certbot configures your Nginx or Apache vhost automatically. Add a redirect for HTTP to HTTPS in your vhost config:

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

Set up auto-renewal:

sudo systemctl enable certbot.timer
sudo systemctl start certbot.timer

3. Monitor everything and alert on anomalies

You can't respond to what you don't see. Real-time monitoring catches intrusions before they escalate.

Set up centralized logging

Install and configure rsyslog to forward logs to a central server or external service. On each server, edit /etc/rsyslog.conf:

*.* @@log-server.example.com:514

Restart rsyslog:

sudo systemctl restart rsyslog

If you don't have a log server, use a managed service or set up a simple ELK stack (Elasticsearch, Logstash, Kibana) or Graylog instance.

Install and configure fail2ban

Fail2ban watches logs for repeated failed login attempts and bans the offending IPs.

sudo apt install fail2ban

Create /etc/fail2ban/jail.local:

[DEFAULT]
bantime = 3600
findtime = 600
maxretry = 5

[sshd]
enabled = true
port = ssh
logpath = /var/log/auth.log

[nginx-limit-req]
enabled = true
filter = nginx-limit-req
logpath = /var/log/nginx/error.log

Restart fail2ban:

sudo systemctl restart fail2ban

Check banned IPs:

sudo fail2ban-client status sshd

Enable auditd for file integrity monitoring

Auditd tracks file access and changes to critical system files.

sudo apt install auditd

Add rules in /etc/audit/rules.d/audit.rules:

-w /etc/passwd -p wa -k passwd_changes
-w /etc/shadow -p wa -k shadow_changes
-w /etc/sudoers -p wa -k sudoers_changes
-w /var/www/ -p wa -k webroot_changes

Reload rules:

sudo augenrules --load

Search audit logs:

sudo ausearch -k passwd_changes

Set up email alerts for critical events

Configure your server to send mail through an SMTP relay. Install msmtp:

sudo apt install msmtp msmtp-mta

Create /etc/msmtprc:

defaults
auth on
tls on
tls_trust_file /etc/ssl/certs/ca-certificates.crt

account default
host smtp.example.com
port 587
from [email protected]
user [email protected]
password your-password

Set permissions:

sudo chmod 600 /etc/msmtprc

Test:

echo "Test alert" | mail -s "Test" [email protected]

Configure fail2ban and auditd to email on specific events by adding action lines to their configs.

4. Automate patching and vulnerability scanning

Unpatched software is the easiest entry point. Automate updates so you're never running vulnerable versions.

Enable automatic security updates

On Debian/Ubuntu:

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

Edit /etc/apt/apt.conf.d/50unattended-upgrades to enable automatic reboots if needed:

Unattended-Upgrade::Automatic-Reboot "true";
Unattended-Upgrade::Automatic-Reboot-Time "03:00";

On RHEL/CentOS, use yum-cron or dnf-automatic:

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

Edit /etc/yum/yum-cron.conf:

apply_updates = yes

Scan for vulnerabilities with Lynis

Lynis is an open-source security auditing tool.

sudo apt install lynis

Run a full audit:

sudo lynis audit system

Review the report in /var/log/lynis.log and address high-priority findings. Run this monthly and track improvements.

Keep web applications updated

For WordPress, enable automatic updates in wp-config.php:

define( 'WP_AUTO_UPDATE_CORE', true );
add_filter( 'auto_update_plugin', '__return_true' );
add_filter( 'auto_update_theme', '__return_true' );

For custom apps, set up a CI/CD pipeline that runs dependency checks (e.g., npm audit, composer audit) and deploys updates automatically after passing tests.

5. Back up everything and test restores

Backups are your last line of defense. If everything else fails, a clean backup gets you back online.

Implement the 3-2-1 rule

Three copies of your data, on two different media types, with one copy off-site. For servers, that means:

  • Live data on the server (copy 1)
  • Local backup on a separate disk or NAS (copy 2)
  • Remote backup to cloud storage or another datacenter (copy 3)

Automate backups with restic

Restic is a fast, encrypted backup tool with support for many backends.

sudo apt install restic

Initialize a repository:

restic -r /mnt/backup init

For remote backups, use S3-compatible storage:

export AWS_ACCESS_KEY_ID="your-key"
export AWS_SECRET_ACCESS_KEY="your-secret"
restic -r s3:s3.amazonaws.com/your-bucket init

Create a backup script /usr/local/bin/backup.sh:

#!/bin/bash
set -e

export RESTIC_REPOSITORY="s3:s3.amazonaws.com/your-bucket"
export RESTIC_PASSWORD="your-restic-password"

restic backup /var/www /etc /home --exclude="*.tmp" --exclude="cache"
restic forget --keep-daily 7 --keep-weekly 4 --keep-monthly 6 --prune

Make it executable:

sudo chmod +x /usr/local/bin/backup.sh

Schedule it with cron:

sudo crontab -e

Add:

0 2 * * * /usr/local/bin/backup.sh >> /var/log/backup.log 2>&1

Test restores monthly

A backup you've never restored is just wishful thinking. Pick a random file and restore it:

restic -r s3:s3.amazonaws.com/your-bucket snapshots
restic -r s3:s3.amazonaws.com/your-bucket restore latest --target /tmp/restore-test --include /var/www/index.html

Verify the file matches the live version. Document the restore process so anyone on your team can do it under pressure.

6. Segment your network and limit exposure

Network segmentation contains breaches. If an attacker compromises one system, they shouldn't be able to pivot to everything else.

Use a firewall to restrict traffic

On each server, enable ufw (Uncomplicated Firewall):

sudo apt install ufw
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow ssh
sudo ufw allow http
sudo ufw allow https
sudo ufw enable

Check status:

sudo ufw status verbose

For database servers, only allow connections from your application servers:

sudo ufw allow from 192.168.1.10 to any port 3306
sudo ufw allow from 192.168.1.11 to any port 3306

Isolate services with VLANs or VPCs

If you're on a VPS or cloud platform, create separate networks for different tiers:

  • Public subnet: web servers, load balancers
  • Private subnet: application servers, databases
  • Management subnet: admin access, monitoring tools

In AWS, use Security Groups to enforce this. In a cPanel environment, you can achieve basic segmentation with firewall rules and private IPs.

Disable unused services and ports

List listening services:

sudo ss -tulnp

For each service you don't recognize, identify the process and decide whether it's needed. Disable and mask unused services:

sudo systemctl stop cups
sudo systemctl disable cups
sudo systemctl mask cups

Run a port scan from outside

Use nmap from an external machine to see what's visible to the internet:

nmap -sV -p- your-server-ip

Anything open that you didn't expect is a problem. Close it.

What if a breach still happens?

These six controls dramatically reduce your attack surface, but no system is invulnerable. Have an incident response plan ready: a checklist of who to notify, how to isolate compromised systems, where your backups live, and how to restore service. Run a tabletop exercise once a year so your team knows the drill.

The controls you just implemented give you visibility and containment. If an attacker gets in, your monitoring alerts you immediately, your segmentation limits their movement, and your backups let you rebuild clean. That's the difference between a contained incident and a catastrophic breach.

Frequently asked questions

How often should I rotate SSH keys?
Rotate them when someone leaves your team or if you suspect compromise. Otherwise, annual rotation is sufficient if keys are properly protected.

Do I need a dedicated SIEM for monitoring?
Not at small scale. Fail2ban, auditd, and centralized logging cover the basics. Add a SIEM when you're managing dozens of servers or have compliance requirements.

Can I automate all six controls with a single tool?
No single tool does everything well. Use specialized tools for each layer—SSH hardening, restic for backups, ufw for firewalls, unattended-upgrades for patching.

What's the biggest mistake you see in breach post-mortems?
No monitoring. Organizations run blind for months while attackers exfiltrate data, because nobody was watching the logs.

Should I segment applications on the same server?
Yes, use containers or separate user accounts with strict file permissions. Even on a single server, isolation limits blast radius.

Where to start today

Don't try to implement all six controls at once. Start with access management—lock down SSH, enforce MFA, audit permissions. That alone stops most opportunistic attacks. Then add monitoring so you can see what's happening. The rest follows naturally once you have visibility and control over who gets in.

These controls work because they're layered. Each one covers weaknesses in the others, and together they force an attacker to get past multiple defenses. Most give up and move to easier targets. The ones who don't? Your monitoring catches them, your segmentation slows them down, and your backups let you recover.

Pick the control that's weakest on your systems right now and spend an hour fixing it. Then move to the next. In a few weeks, you'll have a foundation that holds up under real attacks.