Skip to content
Back to Blog
Security10 min read

Server Security Best Practices: 7 Steps to Lock Down 2026

Walk through the seven configuration, patching, and access-control steps that stop the majority of server breaches before they start.

Written by Abdul AbrorTechnical Hosting Support Engineer
Server Security Best Practices: 7 Steps to Lock Down 2026
On this page

Most server compromises trace back to the same handful of misconfigurations. An SSH daemon left open to password guessing. Unpatched software sitting idle for months. A firewall rule that says "yes" to everything.

I've seen production VPS instances owned within hours of deployment because someone skipped the basics. The good news: you don't need enterprise-grade tools or a security degree to close those doors. You need seven deliberate steps, applied in order, before you put any public service online.

Step 1: Harden SSH access immediately

SSH is your server's front door, and leaving it unlocked is the fastest way to hand root access to a botnet. Disable password authentication first—key-based auth only. Then move the daemon off port 22.

Edit /etc/ssh/sshd_config:

Port 2849
PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes
PermitEmptyPasswords no
X11Forwarding no
MaxAuthTries 3
ClientAliveInterval 300
ClientAliveCountMax 2

Pick any high port above 1024 that isn't already in use. Restart SSH with systemctl restart sshd and test your key login from a second terminal before closing the original session. I cannot count the number of times someone locked themselves out by skipping that verification.

For multi-admin environments, create individual user accounts instead of sharing keys. Each account gets its own key, and you revoke access by removing one authorized_keys entry instead of rotating a shared credential everywhere.

Step 2: Configure a default-deny firewall

A firewall should block everything by default and allow only the specific ports your services require. Most distributions ship with ufw (Debian/Ubuntu) or firewalld (RHEL/CentOS), and both work fine.

Using ufw:

ufw default deny incoming
ufw default allow outgoing
ufw allow 2849/tcp comment 'SSH'
ufw allow 80/tcp comment 'HTTP'
ufw allow 443/tcp comment 'HTTPS'
ufw enable
ufw status verbose

That's it. Three services, three rules. If you're running mail, add ports 25, 587, 465, 993, and 995 as needed. Web control panels like cPanel need their management ports open (2083, 2087), but only from your office IP if possible—use ufw allow from 203.0.113.50 to any port 2087 proto tcp to restrict the source.

Check the active rules every month. Old test rules pile up and create unexpected exposure.

Step 3: Automate security patches

Manual patching fails because humans forget. Automate it, and your server stays current without you remembering to SSH in every week.

On Debian and Ubuntu, install unattended-upgrades:

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

Edit /etc/apt/apt.conf.d/50unattended-upgrades to enable security updates:

Unattended-Upgrade::Allowed-Origins {
    "${distro_id}:${distro_codename}-security";
};
Unattended-Upgrade::AutoFixInterruptedDpkg "true";
Unattended-Upgrade::MinimalSteps "true";
Unattended-Upgrade::Mail "[email protected]";
Unattended-Upgrade::Automatic-Reboot "false";

On RHEL-based systems, enable dnf-automatic:

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

Set apply_updates = yes in /etc/dnf/automatic.conf to apply security patches automatically. I recommend leaving automatic reboots off and scheduling those manually during maintenance windows—some kernel updates require a reboot, and you want control over that timing.

Step 4: Deploy intrusion prevention with Fail2Ban

Fail2Ban watches your logs for repeated authentication failures and blocks the offending IPs at the firewall level. It's simple, effective, and stops brute-force attempts cold.

Install and configure:

apt install fail2ban  # or dnf install fail2ban
cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local

Edit /etc/fail2ban/jail.local:

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

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

Restart with systemctl restart fail2ban and monitor with fail2ban-client status sshd. Adjust maxretry down to 3 if you're seeing heavy scanning traffic.

For web servers, enable the HTTP auth and Apache jails. For cPanel, add a custom jail that watches /usr/local/cpanel/logs/login_log.

So what about user account hygiene?

Firewalls and Fail2Ban stop outside attacks, but compromised user accounts hand attackers a valid key. Enforce strong passwords, disable unused accounts, and audit sudo privileges regularly.

Set password policy in /etc/security/pwquality.conf:

minlen = 14
minclass = 3
maxrepeat = 2

That requires 14-character passwords with at least three character classes (upper, lower, digit, symbol) and no more than two repeated characters. Not perfect, but a significant step up from "password123."

List all accounts with cat /etc/passwd | grep -v nologin and lock any you don't recognize:

usermod -L suspicious-username

Review sudo access with visudo and the /etc/sudoers.d/ directory. Every entry should have a clear business reason. "Bob needed sudo once in 2023" is not a reason to leave it there in 2026.

Step 5: Enable and monitor audit logging

You can't investigate what you didn't log. Enable auditd to record every privileged command, file access, and system call.

apt install auditd audispd-plugins  # or dnf install audit
systemctl enable --now 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/log/auth.log -p wa -k auth_log_changes
-a always,exit -F arch=b64 -S execve -k exec_commands

Reload with augenrules --load. Query logs with ausearch -k passwd_changes to see who touched sensitive files. In support tickets I handled, audit logs were often the only way to trace how an attacker escalated privileges after the initial compromise.

Ship logs off-server to a centralized syslog collector or a managed service. Local logs disappear if the attacker gets root and covers their tracks.

Step 6: Minimize installed software and services

Every package is attack surface. Every running service is a potential entry point. Remove what you don't use.

List installed packages:

apt list --installed  # Debian/Ubuntu
dnf list installed    # RHEL/CentOS

Remove anything that isn't actively required for your application stack. Old PHP versions, unused databases, ancient mail daemons—get rid of them.

List active services:

systemctl list-units --type=service --state=running

Disable anything unnecessary:

systemctl disable --now service-name

A typical web server needs SSH, your web server (Apache or Nginx), your database, and maybe a few monitoring agents. That's it. If you see Bluetooth, CUPS, Avahi, or other desktop services running on a VPS, stop and mask them.

Step 7: Implement least-privilege access control

Root access should be the exception, not the default. Use sudo for specific tasks, give web applications their own restricted users, and never run production services as root.

For web apps, create a dedicated user:

useradd -r -s /bin/false -d /var/www/myapp -M myapp
chown -R myapp:myapp /var/www/myapp

Configure your web server to run as that user. For systemd services, set User= and Group= in the unit file.

Database accounts follow the same principle. Create one DB user per application, grant only the required privileges, and never use the root database account from application code:

CREATE USER 'appuser'@'localhost' IDENTIFIED BY 'strong-password';
GRANT SELECT, INSERT, UPDATE, DELETE ON appdb.* TO 'appuser'@'localhost';
FLUSH PRIVILEGES;

Review privileges quarterly. Access tends to accumulate—someone needed elevated access for a one-time migration and it never got revoked.

What to monitor after you lock it down

You've hardened the server, but configuration drift is real. Set monthly calendar reminders to check:

  • SSH config for unauthorized changes
  • Firewall rules for cruft
  • User accounts and sudo access
  • Package update status
  • Fail2Ban stats and ban counts
  • Audit log volume and anomalies

Run a baseline scan with lynis or OpenSCAP and compare subsequent scans to catch regressions.

Do I need a WAF or DDoS protection?

A web application firewall and DDoS mitigation (like Cloudflare) sit upstream from your server and handle threats before they reach you. They're not a substitute for server hardening—defense in depth means both. But for high-traffic sites or anything facing serious adversaries, add them.

Should I disable IPv6?

Only if you're not using it and your hosting provider doesn't route it anyway. Disabling IPv6 on a dual-stack server without updating firewall rules just creates an unmonitored path. Either configure your firewall for both protocols or disable IPv6 entirely at the network level.

How often should I rotate SSH keys?

Rotate them when someone leaves the team, when you suspect compromise, or on a yearly schedule for compliance. Rotating SSH keys just to rotate them creates work without meaningfully improving security—focus on protecting the private keys.

What about SELinux or AppArmor?

Both are mandatory access control systems that add another security layer. Enable them. RHEL ships with SELinux enforcing by default; Debian and Ubuntu ship with AppArmor. Don't disable them because an application complains—fix the policy or the application.

Where to start tomorrow

You don't have to implement all seven steps in one session. Start with SSH hardening and the firewall today, automate patches this week, and layer in the rest over the next month.

The servers I've seen compromised always skipped at least three of these steps. Usually five. They had password auth on default SSH ports, no firewall, packages six months out of date, and root running everything.

Your server is online right now, and so are the bots. Pick step one and do it before you close this tab.