Skip to content
Back to Blog
Security11 min read

Data Breach Prevention Server: 7 Fixes That Stop Attacks

Seven server hardening steps that close the entry points attackers use most. SSH ports, outdated packages, weak passwords, and firewall gaps — fix them now.

Written by Abdul AbrorTechnical Hosting Support Engineer
Data Breach Prevention Server: 7 Fixes That Stop Attacks
On this page

Most breaches happen because a server had one open door. Not a zero-day exploit or nation-state toolkit — an SSH port exposed to the internet, a package three years out of date, or a service running as root. I've seen support tickets where an entire WordPress install got encrypted because fail2ban wasn't running and the login page took a million guesses.

You don't need expensive tooling or a SOC team to close the gaps attackers walk through every day. You need seven things in place, checked regularly, and enforced by policy. The payoff is huge: attacks that would have worked in minutes hit a wall and move on.

Change the default SSH port and disable root login

Port 22 gets hammered by bots constantly. Changing SSH to a non-standard port cuts automated scanning traffic by a dramatic amount overnight. Pick something above 1024 and below 65535 — I usually use a five-digit number that's easy to remember but not sequential.

Edit /etc/ssh/sshd_config:

Port 52914
PermitRootLogin no
PasswordAuthentication no

Then restart SSH:

systemctl restart sshd

Disabling root login forces attackers to know a valid username and password, then escalate separately. Disabling password auth entirely means they need your private key, which they don't have. These two lines stop the vast majority of brute-force attempts cold.

Don't forget to update your firewall rules before you restart SSH or you'll lock yourself out. Test the new port with a second terminal session before closing your active one.

Lock down the firewall to allow only necessary ports

Default firewall policies on fresh installs are often wide open or missing entirely. A data breach prevention server starts with deny-all inbound and explicit allow rules for every service you actually need.

With ufw on Debian/Ubuntu:

ufw default deny incoming
ufw default allow outgoing
ufw allow 52914/tcp comment 'SSH'
ufw allow 80/tcp
ufw allow 443/tcp
ufw enable

With firewalld on RHEL/Rocky/AlmaLinux:

firewall-cmd --set-default-zone=drop
firewall-cmd --zone=public --add-port=52914/tcp --permanent
firewall-cmd --zone=public --add-service=http --permanent
firewall-cmd --zone=public --add-service=https --permanent
firewall-cmd --reload

Every open port is an attack surface. If you're not running a mail server, close 25, 587, 465, 110, 143, and 993. If you don't use FTP, close 21 and the passive range. Database ports like 3306 and 5432 should never be exposed to the public internet — bind them to localhost and use SSH tunnels for remote admin.

Check what's listening:

ss -tuln

Anything on 0.0.0.0 or :: with a port you don't recognize needs investigation.

Keep packages up to date and enable automatic security patches

Outdated software is the second most common entry point I see in breach post-mortems. A PHP version with a known RCE, a kernel missing a privilege escalation patch, or an OpenSSL build vulnerable to a public exploit.

On Debian/Ubuntu, enable unattended-upgrades:

apt install unattended-upgrades
dpkg-reconfigure --priority=low unattended-upgrades

Edit /etc/apt/apt.conf.d/50unattended-upgrades and make sure the security repo is uncommented:

Unattended-Upgrade::Allowed-Origins {
    "${distro_id}:${distro_codename}-security";
};

On RHEL-based systems, enable dnf-automatic:

dnf install dnf-automatic
systemctl enable --now dnf-automatic.timer

Check for updates manually once a week:

apt update && apt list --upgradable  # Debian/Ubuntu
dnf check-update                      # RHEL/Rocky

Set a calendar reminder. Automatic security updates are good, but full system upgrades sometimes need a reboot and a plan. Kernel updates especially.

Install and configure fail2ban for intrusion prevention

fail2ban watches logs for repeated failed login attempts and bans the source IP temporarily or permanently. It's simple, effective, and catches attacks in progress.

Install it:

apt install fail2ban       # Debian/Ubuntu
dnf install fail2ban       # RHEL/Rocky
systemctl enable --now fail2ban

Create /etc/fail2ban/jail.local:

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

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

Restart:

systemctl restart fail2ban

Check who's banned:

fail2ban-client status sshd

You'll see IPs get added in real time as bots try to guess passwords. After a few days, the ban list grows and the attempts drop off. For mail servers, enable the postfix and dovecot jails too. For web apps, enable the apache-auth and nginx jails.

fail2ban won't stop a targeted attack, but it stops the automated scans that account for most breach attempts.

Audit file permissions and disable unnecessary SUID binaries

Files owned by root with the SUID bit set run with root privileges even when a normal user executes them. Attackers love finding an obscure SUID binary they can exploit for privilege escalation.

Find all SUID files:

find / -perm -4000 -type f 2>/dev/null

You'll get a list. Most are legitimate (sudo, passwd, ping), but occasionally you'll see something odd — an old backup utility, a custom script, or a binary left behind by a past admin.

Remove the SUID bit if the binary doesn't need it:

chmod u-s /usr/local/bin/suspicious-tool

Check world-writable directories:

find / -type d -perm -002 ! -path "/proc/*" 2>/dev/null

World-writable directories let any user drop files. /tmp and /var/tmp are expected, but anything else is a red flag. Make sure /tmp is mounted with noexec and nosuid in /etc/fstab:

tmpfs  /tmp  tmpfs  defaults,noexec,nosuid,nodev  0  0

Remount:

mount -o remount /tmp

Now scripts in /tmp can't execute directly and SUID binaries placed there won't escalate privileges.

Run services with dedicated unprivileged users

Running Apache, Nginx, or MySQL as root is asking for a full compromise the moment a vulnerability appears in that software. Every service should run as its own user with minimal permissions.

Check what user a service runs as:

ps aux | grep nginx
ps aux | grep mysql

If you see root in the output, fix it. For Nginx, the master process runs as root but workers run as www-data or nginx — that's fine. For MySQL, everything should run as mysql.

Create a dedicated user for a custom service:

useradd -r -s /bin/false appuser

The -r flag makes it a system user with no home directory. The -s /bin/false shell means no one can log in as that user. Then set ownership on the service's files:

chown -R appuser:appuser /opt/myapp

Update the systemd unit file to run as that user:

[Service]
User=appuser
Group=appuser

Reload and restart:

systemctl daemon-reload
systemctl restart myapp

Compartmentalizing services this way limits what an attacker can do after exploiting one process. They get appuser privileges, not root.

Enable mandatory access control with AppArmor or SELinux

MAC systems add a second layer of policy enforcement on top of traditional Unix permissions. Even if an attacker compromises a service running as a dedicated user, the MAC policy restricts what files that service can read, write, or execute.

Debian and Ubuntu ship with AppArmor enabled by default. Check status:

aa-status

You'll see profiles in enforce mode (active) or complain mode (logging only). Make sure critical services like Apache, Nginx, and MySQL have enforce-mode profiles:

aa-enforce /etc/apparmor.d/usr.sbin.nginx

RHEL, Rocky, and AlmaLinux use SELinux. Check it's enforcing:

getenforce

If it says Permissive or Disabled, enable it in /etc/selinux/config:

SELINUX=enforcing

Then reboot. SELinux in permissive mode logs violations without blocking them, which is useful for testing new policies. In production, enforce mode is what stops attacks.

SELinux errors show up in /var/log/audit/audit.log. If a service breaks after enabling enforcing mode, check the log:

grep denied /var/log/audit/audit.log | tail -20

Use audit2allow to generate a policy if needed, but understand the access being requested first. Blindly allowing everything defeats the purpose.

What if you're already under attack?

If you're reading this because logs show active intrusion attempts, take these steps immediately:

  1. Block the source IP at the firewall level.
  2. Check recent logins with last and lastlog.
  3. Look for unexpected processes with ps auxf.
  4. Check cron jobs with crontab -l for all users and /etc/cron.d/.
  5. Review recently modified files: find /home /var/www /etc -mtime -7 -type f.

If you find evidence of compromise — a backdoor script, an unknown user account, or a modified binary — isolate the server from the network and start incident response. Patch the entry point, rotate all credentials, and restore from a known-good backup if available.

Questions

Do I need all seven fixes or can I pick a few?
Every fix closes a different attack vector. SSH hardening stops brute force, firewalls stop port scans, package updates close known exploits, and fail2ban stops intrusion attempts in progress. Skipping one leaves a door open.

Will changing the SSH port break my backup scripts?
Yes, if they connect to port 22. Update your scripts, SSH config files, and any automation that connects to the server. Test them before you finalize the change.

Can I disable SELinux if it breaks something?
You can, but fixing the policy is better. SELinux in enforcing mode has stopped real privilege escalations in production. Set it to permissive, read the logs, and create a policy exception for the specific access needed.

How often should I check for updates?
Automatic security updates handle critical patches. For full system upgrades, check weekly and apply monthly during a maintenance window. Kernel updates need a reboot.

What if fail2ban bans a legitimate user?
Unban them: fail2ban-client set sshd unbanip 203.0.113.45. Then raise maxretry in jail.local if false positives are common.

Lock the doors before they get tested

Data breach prevention on a server isn't about bleeding-edge tools or compliance checklists. It's about closing the entry points attackers actually use: SSH credentials, outdated packages, wide-open firewalls, and services running with more privileges than they need.

Walk through these seven fixes once and schedule a monthly review. The first five take under an hour total. AppArmor or SELinux configuration takes longer but pays off when a vulnerability appears in production software.

Most attacks move on when they hit basic hardening. Make your server one of them.