Skip to content
Back to Blog
Security10 min read

Server Security Best Practices: 11 Steps [2026 Update]

A hardening checklist covering SSH keys, firewall rules, patch cycles, and audit logging to secure Linux and Windows servers against common threats.

Written by Abdul AbrorTechnical Hosting Support Engineer
Server Security Best Practices: 11 Steps [2026 Update]
On this page

Every compromised server I've investigated shared the same pattern: basic hardening steps were skipped. The entry point was usually SSH brute-force, an unpatched service, or a wide-open firewall rule left from a quick test months earlier.

This checklist covers eleven server security best practices that stop most attacks before they start. Each step is something you can implement today, whether you run a single VPS or manage a fleet of dedicated boxes.

1. Disable password authentication for SSH

Passwords are guessable. Key-based authentication is not.

Generate an SSH key pair on your local machine if you don't have one:

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

Copy the public key to your server:

ssh-copy-id user@server-ip

Then edit /etc/ssh/sshd_config and set:

PasswordAuthentication no
PubkeyAuthentication yes
PermitRootLogin prohibit-password

Restart the SSH daemon:

systemctl restart sshd

Test your key login from a new terminal before you close the current session. I've seen admins lock themselves out by skipping this step.

2. Change the default SSH port

Port 22 gets hammered by automated scanners. Moving SSH to a high port (above 1024) cuts noise in your auth logs by an order of magnitude.

In /etc/ssh/sshd_config:

Port 2849

Pick a random number between 10000 and 65535. Update your firewall rules first, then restart SSH. Security through obscurity isn't a defense by itself, but it does reduce log clutter and failed login attempts.

3. Configure a firewall with default-deny

Your firewall should block everything except the services you explicitly need.

On Linux, use ufw for simplicity:

ufw default deny incoming
ufw default allow outgoing
ufw allow 2849/tcp  # your SSH port
ufw allow 80/tcp
ufw allow 443/tcp
ufw enable

For more control, use iptables or firewalld. On Windows Server, configure Windows Defender Firewall with the same principle: inbound blocked by default, outbound allowed, explicit rules for needed ports.

Check your current rules:

ufw status verbose

Every open port is a potential attack surface. Close what you don't need.

4. Set up automatic security updates

Patching is not optional. Most breaches exploit known vulnerabilities that already have fixes.

On Debian/Ubuntu, enable unattended-upgrades:

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

Edit /etc/apt/apt.conf.d/50unattended-upgrades to control what gets updated automatically. At minimum, enable security updates.

On RHEL/Rocky/AlmaLinux, use dnf-automatic:

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

For Windows, enable automatic updates through Group Policy or Windows Update settings. Schedule them for a maintenance window if you need uptime predictability, but don't skip them.

Check your last update date right now:

stat /var/log/apt/history.log  # Debian/Ubuntu
dnf history                    # RHEL family

If it's been more than two weeks, you're behind.

5. Install and configure fail2ban

Fail2ban watches your logs for repeated failed login attempts and bans the source IP automatically.

Install it:

apt install fail2ban         # Debian/Ubuntu
dnf install fail2ban         # RHEL family

Create /etc/fail2ban/jail.local:

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

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

Start the service:

systemctl enable --now fail2ban

Check banned IPs:

fail2ban-client status sshd

In support tickets I handled, fail2ban stopped brute-force attacks within minutes of installation. The configuration above bans an IP for one hour after five failed attempts in ten minutes.

6. Disable unused services and remove unnecessary packages

Every running service is a potential exploit target.

List active services:

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

Disable anything you don't recognize or use:

systemctl disable --now service-name

Common candidates: cups (printing), avahi-daemon (network discovery), bluetooth. If your server doesn't need it, turn it off.

Remove packages you don't need:

apt autoremove

A smaller attack surface is a more secure one.

7. Enable and monitor audit logging

Audit logs tell you who did what and when. You need them for incident response and compliance.

On Linux, use auditd:

apt install auditd
systemctl enable --now auditd

Add rules to watch sensitive files and directories. Example:

auditctl -w /etc/passwd -p wa -k passwd_changes
auditctl -w /etc/shadow -p wa -k shadow_changes
auditctl -w /var/log/auth.log -p wa -k auth_log_changes

Make rules persistent by adding them to /etc/audit/rules.d/audit.rules.

Search audit logs:

ausearch -k passwd_changes

On Windows, enable auditing through Group Policy and review the Security event log regularly. Focus on logon events, account changes, and privilege escalations.

Ship your logs to a central location. If an attacker gets root, they'll erase local logs.

8. Harden kernel parameters with sysctl

The Linux kernel has tunable parameters that improve security.

Edit /etc/sysctl.conf or create /etc/sysctl.d/99-hardening.conf:

# Ignore ICMP ping requests
net.ipv4.icmp_echo_ignore_all = 1

# Disable IP forwarding
net.ipv4.ip_forward = 0

# Enable SYN cookies (DDoS protection)
net.ipv4.tcp_syncookies = 1

# Ignore ICMP redirects
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.default.accept_redirects = 0

# Disable source packet routing
net.ipv4.conf.all.accept_source_route = 0
net.ipv4.conf.default.accept_source_route = 0

# Log martians (packets with impossible addresses)
net.ipv4.conf.all.log_martians = 1

Apply the changes:

sysctl -p

These settings reduce the risk of network-based attacks and information leakage.

9. Use a file integrity monitoring tool

File integrity monitoring detects unauthorized changes to system files and configurations.

Install AIDE (Advanced Intrusion Detection Environment):

apt install aide

Initialize the database:

aideinit

This creates a snapshot of your filesystem. Run checks regularly:

aide --check

AIDE will report any modified, added, or deleted files. Schedule it in cron:

0 3 * * * /usr/bin/aide --check | mail -s "AIDE Report" [email protected]

Alternatively, use Tripwire or OSSEC for more features.

10. Restrict user privileges and use sudo

Never run services as root. Never log in as root for daily tasks.

Create a regular user account if you haven't:

adduser adminuser
usermod -aG sudo adminuser  # Debian/Ubuntu
usermod -aG wheel adminuser # RHEL family

Then enforce root login restrictions in /etc/ssh/sshd_config:

PermitRootLogin no

Use sudo for administrative tasks. Configure /etc/sudoers carefully:

visudo

Grant only the permissions each user needs. Avoid ALL=(ALL:ALL) ALL unless absolutely necessary.

For services, create dedicated users with no shell:

useradd -r -s /usr/sbin/nologin serviceuser

Run the service under that user account.

11. Schedule regular security audits

Automation catches most issues, but manual reviews catch the rest.

Run Lynis, an open-source security auditing tool:

git clone https://github.com/CISOfy/lynis
cd lynis
./lynis audit system

Lynis produces a detailed report with warnings and suggestions. Review it quarterly at minimum.

Check for: - Unnecessary open ports: netstat -tuln or ss -tuln - World-writable files: find / -xdev -type f -perm -0002 - Files without an owner: find / -xdev -nouser -o -nogroup - SUID/SGID binaries: find / -perm /6000 -type f

Audit your user accounts:

cat /etc/passwd

Remove old accounts and disable unused ones:

usermod -L username  # lock the account

Document what you find and fix issues on a schedule.

What if you're already compromised?

If you suspect a breach, act fast. Isolate the server from the network, preserve logs, snapshot the disk, and rebuild from a known-good backup.

Don't try to clean an infected system in place. Rootkits and backdoors persist through partial cleanups. A full rebuild is faster and more reliable.

After rebuilding, walk through this checklist before you bring the server back online.

Start with SSH and the firewall

If you do nothing else today, disable SSH password authentication and configure a default-deny firewall. Those two steps stop the majority of automated attacks.

The rest of this checklist builds defense in depth. No single control is perfect, but together they make your server a hard target. Walk through each step, test your changes, and document what you did. Your future self will thank you when the next vulnerability drops.

FAQ

How often should I update my server?

Security updates should be automatic. Feature updates can wait for a maintenance window, but don't delay them more than a month.

Is antivirus necessary on Linux servers?

Malware for Linux exists, but proper hardening is more important than antivirus. ClamAV can catch known threats if you need it for compliance.

Should I use SELinux or AppArmor?

Yes, if they're available. SELinux (RHEL family) and AppArmor (Debian/Ubuntu) add mandatory access control. Keep the default policies enabled unless you have a specific reason to disable them.

What's the most overlooked server security step?

Audit logging. Most admins set up firewalls and SSH keys but never configure or review logs. You can't investigate an incident without them.

How do I secure a Windows Server?

Disable unnecessary services, enable Windows Firewall with strict inbound rules, use Windows Update, enable audit logging, restrict administrator accounts, and deploy endpoint protection.