A fresh server is a liability until you harden it. Default SSH ports, root login enabled, no firewall rules—common patterns that turn up in breach post-mortems. This checklist covers the baseline tasks I walk through on every Linux and Windows server before it sees production traffic.
You can finish most of these in an hour. Some require planning (patch schedules, backup retention). All of them reduce your attack surface measurably.
Initial Access and Account Hygiene
First thing: stop using root or Administrator for day-to-day work.
Disable root SSH login (Linux)
Create a non-root user with sudo privileges, then lock out direct root access over SSH. Open /etc/ssh/sshd_config and set:
PermitRootLogin no
Restart SSH:
systemctl restart sshd
Test the new user account in a second terminal before you close your root session. I've seen admins lock themselves out by skipping this step.
Enforce key-based authentication
Passwords are guessable. SSH keys are not. Generate a key pair on your local machine:
ssh-keygen -t ed25519 -C "[email protected]"
Copy the public key to the server:
ssh-copy-id user@server_ip
Then disable password authentication in /etc/ssh/sshd_config:
PasswordAuthentication no
ChallengeResponseAuthentication no
Restart SSH and confirm you can still connect with your key.
Rename or disable Administrator (Windows)
The built-in Administrator account is a known target. Rename it via Local Security Policy or disable it entirely if you have another admin account. Create a new user with administrative privileges and a non-obvious name.
Open Computer Management → Local Users and Groups → Users. Right-click Administrator, choose Rename, and pick something that doesn't advertise privilege.
Network Surface Reduction
Open ports are open doors.
Change the default SSH port
Port 22 gets hammered by bots. Moving SSH to a non-standard port (say, 2200 or 49222) cuts the noise. Edit /etc/ssh/sshd_config:
Port 2200
Update your firewall rules to allow the new port before restarting SSH, or you'll lock yourself out. For UFW:
ufw allow 2200/tcp
ufw delete allow 22/tcp
systemctl restart sshd
This is security through obscurity, yes. It still works.
Configure a firewall and default-deny
Linux servers should run a firewall with a default-deny policy. UFW is the simplest starting point on Ubuntu/Debian:
ufw default deny incoming
ufw default allow outgoing
ufw allow 2200/tcp # SSH
ufw allow 80/tcp # HTTP
ufw allow 443/tcp # HTTPS
ufw enable
For CentOS/RHEL, use firewalld:
firewall-cmd --set-default-zone=public
firewall-cmd --add-service=ssh --permanent
firewall-cmd --add-service=http --permanent
firewall-cmd --add-service=https --permanent
firewall-cmd --reload
On Windows Server, enable Windows Firewall with default inbound block. Open Windows Defender Firewall with Advanced Security and configure rules for RDP (if needed), HTTP, and HTTPS only.
Close unused services
List listening ports and kill anything you don't recognize:
ss -tulnp
Common culprits: Sendmail running when you use an external SMTP relay, old MySQL instances, Telnet (disable immediately). Stop and disable them:
systemctl stop sendmail
systemctl disable sendmail
On Windows, open Services (services.msc) and set startup type to Disabled for unused services like Remote Registry, Print Spooler (if not printing), and older SMB versions.
Patch Management and Automatic Updates
Unpatched software is the easiest entry point.
Enable automatic security updates (Linux)
On Debian/Ubuntu, install unattended-upgrades:
apt install unattended-upgrades
dpkg-reconfigure --priority=low unattended-upgrades
Edit /etc/apt/apt.conf.d/50unattended-upgrades to auto-reboot if required:
Unattended-Upgrade::Automatic-Reboot "true";
Unattended-Upgrade::Automatic-Reboot-Time "03:00";
For RHEL/CentOS, dnf-automatic does the same job:
dnf install dnf-automatic
systemctl enable --now dnf-automatic.timer
Configure Windows Update
Open Settings → Update & Security → Windows Update → Advanced options. Set active hours to avoid surprise reboots during business time. Enable automatic installation of updates.
For Windows Server, consider WSUS if you manage multiple machines. Manual patching doesn't scale.
Keep your control panel and web stack updated
If you run cPanel, WHM, Plesk, or DirectAdmin, check for updates weekly. Same for PHP, MySQL, Apache, or Nginx. A forgotten PHP 7.2 instance with known CVEs is a liability.
cPanel example:
/scripts/upcp
For manual stacks, subscribe to security mailing lists for your software and test updates on staging first.
User Privilege and Password Policy
Enforce strong password requirements
Install and configure libpam-pwquality on Linux:
apt install libpam-pwquality
Edit /etc/security/pwquality.conf:
minlen = 14
minclass = 3
maxrepeat = 2
This enforces 14-character passwords with at least three character classes and blocks excessive repetition.
On Windows, open Local Security Policy → Account Policies → Password Policy. Set minimum length to 14, enable complexity requirements, and set maximum password age to 90 days.
Limit sudo/admin access
Don't hand out sudo to every user. Create a dedicated admin group and grant it sudo access via /etc/sudoers:
%admingroup ALL=(ALL:ALL) ALL
Use visudo to edit safely. For Windows, avoid adding users to the Administrators group unless they genuinely need system-wide access. Use the Remote Desktop Users group for remote access without admin rights.
Audit user accounts regularly
List all users on Linux:
cut -d: -f1 /etc/passwd
Delete or lock unused accounts:
usermod -L olduser
userdel -r olduser
On Windows, open Computer Management → Local Users and Groups → Users and disable stale accounts.
Logging, Monitoring, and Intrusion Detection
You can't respond to what you don't see.
Centralize and retain logs
Configure syslog forwarding to a remote log server or a service like Papertrail. If the server is compromised, local logs can be wiped. Remote logs survive.
Edit /etc/rsyslog.conf and add:
*.* @@logserver.example.com:514
Restart rsyslog:
systemctl restart rsyslog
On Windows, forward Event Logs using Windows Event Forwarding (WEF) to a collector server.
Install Fail2Ban (Linux)
Fail2Ban blocks IPs after repeated failed login attempts. Install it:
apt install fail2ban
Copy the default config:
cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
Edit jail.local to enable SSH protection:
[sshd]
enabled = true
port = 2200
maxretry = 3
bantime = 3600
Restart Fail2Ban:
systemctl restart fail2ban
Enable audit logging
On Linux, install auditd to track file access, command execution, and privilege escalation:
apt install auditd
systemctl enable auditd
Add rules in /etc/audit/rules.d/audit.rules to monitor sensitive files:
-w /etc/passwd -p wa -k passwd_changes
-w /etc/shadow -p wa -k shadow_changes
Reload rules:
auditctl -R /etc/audit/rules.d/audit.rules
On Windows, enable Object Access auditing via Group Policy or Local Security Policy to track file and registry changes.
File System and Permission Hardening
Set correct ownership and permissions
Web root directories should not be world-writable. For Apache/Nginx on Linux:
chown -R www-data:www-data /var/www/html
find /var/www/html -type d -exec chmod 755 {} \;
find /var/www/html -type f -exec chmod 644 {} \;
Never set chmod 777 on production files. If an application demands it, the application is broken.
Disable unused filesystems
Edit /etc/modprobe.d/disable-filesystems.conf and add:
install cramfs /bin/true
install freevxfs /bin/true
install jffs2 /bin/true
install hfs /bin/true
install hfsplus /bin/true
install udf /bin/true
These are rarely needed and widen the kernel attack surface.
Enable disk encryption
If the server stores sensitive data, encrypt the disk. On Linux, use LUKS at install time. For existing volumes, migrating to encrypted partitions requires downtime and backups.
On Windows Server, enable BitLocker via Server Manager → File and Storage Services → Volumes. Store recovery keys securely off-server.
Application and Service Hardening
Harden Apache
Hide version information. Edit your Apache config (often /etc/apache2/conf-available/security.conf):
ServerTokens Prod
ServerSignature Off
Disable directory listing:
<Directory /var/www/html>
Options -Indexes
</Directory>
Restart Apache:
systemctl restart apache2
Harden Nginx
Hide the version in responses. Add to nginx.conf:
server_tokens off;
Set security headers in your server block:
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
Reload Nginx:
nginx -s reload
Harden MySQL/MariaDB
Run the security script:
mysql_secure_installation
Remove anonymous users, disable remote root login, and drop the test database. Bind MySQL to localhost unless you need remote access:
[mysqld]
bind-address = 127.0.0.1
Restart MySQL:
systemctl restart mysql
Backup and Disaster Recovery
Hardening doesn't prevent every breach. Backups do.
Automate daily backups
Use rsync, Restic, or Duplicity to back up to remote storage. Schedule via cron:
0 2 * * * /usr/local/bin/backup.sh
Test restores quarterly. Untested backups are wishes.
Store backups off-server
Local backups are useless if the server is ransomwared. Use S3, Backblaze B2, or a secondary VPS in a different datacenter.
Implement snapshot policies
If your host offers filesystem or VM snapshots, schedule daily snapshots with seven-day retention. Snapshots aren't backups, but they buy you rollback time.
Final Sweep
So what if you've checked every box here but still feel exposed?
Run a vulnerability scanner
Use OpenVAS, Nessus, or Lynis (for Linux) to find misconfigurations you missed:
lynis audit system
Review the report and address high-priority findings.
Enable two-factor authentication
For SSH, install Google Authenticator PAM module:
apt install libpam-google-authenticator
Run google-authenticator as your user and follow the prompts. Edit /etc/pam.d/sshd to add:
auth required pam_google_authenticator.so
In /etc/ssh/sshd_config, set:
ChallengeResponseAuthentication yes
Restart SSH. You'll now need both your key and a TOTP code.
For Windows RDP, Azure MFA or Duo can integrate with Network Policy Server.
Document your configuration
Write down what you changed, where, and why. Future-you will thank present-you when you need to audit or replicate the setup.
What You Can Skip (and What You Can't)
You can defer disk encryption if you don't handle payment data or personal information. You can skip intrusion detection on a low-value staging box.
You cannot skip firewalls, SSH hardening, or patch management. Those three are the baseline. Everything else adds depth, but without the baseline you're already breached—you just don't know it yet.
Run through this list before your next deployment. An hour now beats a weekend incident response later.
![Server Security Hardening Checklist [2026 Updated]](/images/blog/server-security-hardening-checklist-2026-updated.jpg)