← All Articles
Last updated: 2026-03-30

Is Your Server Secure? A Quick Security Checklist

Server security checklist: SSH hardening, firewall, exposed ports, automatic updates, fail2ban — with commands for each step.

TL;DR

Server security is not a one-time task — it is an ongoing process. This checklist covers the most critical areas: locking down SSH, configuring a firewall, auditing open ports and running services, enabling automatic updates, setting up intrusion detection with fail2ban, and hunting for leaked secrets. Work through each section from top to bottom. Most steps take less than five minutes and dramatically reduce your attack surface.

Prerequisites

1. SSH Security Hardening

SSH is the front door to your server. A misconfigured SSH daemon is the number one cause of unauthorized access.

1.1 Disable Root Login

Edit the SSH daemon configuration:

sudo nano /etc/ssh/sshd_config

Find and set the following directive:

PermitRootLogin no

1.2 Enforce Key-Only Authentication

Password-based logins are vulnerable to brute-force attacks. Switch to key-only authentication:

# On your LOCAL machine, generate a key pair if you don't have one
ssh-keygen -t ed25519 -C "your_email@example.com"

# Copy the public key to your server
ssh-copy-id -i ~/.ssh/id_ed25519.pub user@your-server-ip

Then disable password authentication on the server:

# In /etc/ssh/sshd_config
PasswordAuthentication no
ChallengeResponseAuthentication no
UsePAM no

1.3 Change the Default SSH Port

Changing the port does not provide true security, but it eliminates the vast majority of automated bot scans:

# In /etc/ssh/sshd_config
Port 2222

Apply all changes:

sudo sshd -t          # Test configuration for syntax errors
sudo systemctl restart sshd

Warning: Before restarting, ensure your firewall allows the new port and that you have an active session as a fallback.

2. Firewall Configuration

2.1 UFW (Uncomplicated Firewall)

UFW is the recommended firewall frontend on Ubuntu/Debian:

# Allow SSH (use your custom port if changed)
sudo ufw allow 2222/tcp comment 'SSH'

# Allow HTTP and HTTPS
sudo ufw allow 80/tcp comment 'HTTP'
sudo ufw allow 443/tcp comment 'HTTPS'

# Deny everything else inbound by default
sudo ufw default deny incoming
sudo ufw default allow outgoing

# Enable the firewall
sudo ufw enable

# Check status
sudo ufw status verbose

2.2 Basic iptables Examples

If you prefer working with iptables directly:

# Allow established connections
sudo iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

# Allow SSH on custom port
sudo iptables -A INPUT -p tcp --dport 2222 -j ACCEPT

# Allow HTTP/HTTPS
sudo iptables -A INPUT -p tcp --dport 80 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 443 -j ACCEPT

# Allow loopback
sudo iptables -A INPUT -i lo -j ACCEPT

# Drop everything else
sudo iptables -A INPUT -j DROP

# Persist rules across reboots
sudo apt install iptables-persistent
sudo netfilter-persistent save

3. Checking Exposed Ports

You should know exactly which ports are open on your server and which processes are listening.

# Show all listening TCP ports with process names
sudo ss -tlnp

# Same for UDP
sudo ss -ulnp

# Scan your own server from localhost
sudo nmap -sT -O localhost

# Scan from an external machine to see what the internet sees
nmap -sV your-server-ip

Review the output carefully. Every open port that is not explicitly required should be closed via the firewall or by stopping the service entirely.

4. Automatic Security Updates

Unpatched software is the easiest entry point for attackers. Automatic security updates are essential.

# Install unattended-upgrades
sudo apt update
sudo apt install unattended-upgrades apt-listchanges

# Enable it
sudo dpkg-reconfigure -plow unattended-upgrades

Verify the configuration:

# Check the config file
cat /etc/apt/apt.conf.d/50unattended-upgrades

Ensure the following lines are uncommented:

Unattended-Upgrade::Allowed-Origins {
    "${distro_id}:${distro_codename}-security";
};
Unattended-Upgrade::Automatic-Reboot "true";
Unattended-Upgrade::Automatic-Reboot-Time "04:00";

Test a dry run:

sudo unattended-upgrades --dry-run --debug

5. Checking for Leaked Secrets

Misconfigured deployments frequently leak database credentials, API keys, and environment files.

# Find all .env files on the system
sudo find / -name ".env" -type f 2>/dev/null

# Check if .env files are accessible from the web root
sudo find /var/www -name ".env" -type f
sudo find /var/www -name "*.bak" -o -name "*.sql" -o -name "*.log" 2>/dev/null

# Check for config files in publicly served directories
sudo find /var/www -name "wp-config.php" -exec ls -la {} \;
sudo find /var/www -name "config.php" -exec ls -la {} \;

# Search for hardcoded passwords in common config files
sudo grep -r "password" /var/www --include="*.php" --include="*.env" -l
sudo grep -r "DB_PASSWORD\|API_KEY\|SECRET" /var/www -l

Ensure your web server blocks access to sensitive files. For Nginx, add:

location ~ /\.env {
    deny all;
    return 404;
}

6. fail2ban Setup

fail2ban monitors log files and bans IPs that show malicious behaviour such as repeated failed login attempts.

# Install
sudo apt update
sudo apt install fail2ban

# Create a local config (never edit jail.conf directly)
sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local

6.1 Configure SSH Jail

Edit /etc/fail2ban/jail.local:

[sshd]
enabled = true
port = 2222
filter = sshd
logpath = /var/log/auth.log
maxretry = 3
bantime = 3600
findtime = 600

6.2 Configure Nginx Jail

[nginx-http-auth]
enabled = true
port = http,https
filter = nginx-http-auth
logpath = /var/log/nginx/error.log
maxretry = 5
bantime = 3600

[nginx-botsearch]
enabled = true
port = http,https
filter = nginx-botsearch
logpath = /var/log/nginx/access.log
maxretry = 2
bantime = 86400

Start and enable fail2ban:

sudo systemctl enable fail2ban
sudo systemctl start fail2ban

# Check status
sudo fail2ban-client status
sudo fail2ban-client status sshd

7. User Accounts & Sudo Audit

Regularly audit who has access to your server.

# Show currently logged-in users
who

# Show recent logins
last -20

# Show failed login attempts
sudo lastb -20

# List all users with a login shell
grep -v '/nologin\|/false' /etc/passwd

# Check who has sudo privileges
sudo grep -v '^#' /etc/sudoers | grep -v '^$'
ls -la /etc/sudoers.d/

# List members of the sudo group
getent group sudo

Remove any accounts that are no longer needed:

sudo userdel -r old_username

8. File Permissions

World-writable files are a common vector for privilege escalation.

# Find world-writable files (excluding /proc and /sys)
sudo find / -path /proc -prune -o -path /sys -prune -o -perm -002 -type f -print 2>/dev/null

# Find world-writable directories without the sticky bit
sudo find / -path /proc -prune -o -path /sys -prune -o -perm -002 -type d ! -perm -1000 -print 2>/dev/null

# Find files with SUID/SGID bits set
sudo find / -path /proc -prune -o -path /sys -prune -o \( -perm -4000 -o -perm -2000 \) -type f -print 2>/dev/null

# Fix web directory permissions
sudo chown -R www-data:www-data /var/www
sudo find /var/www -type d -exec chmod 750 {} \;
sudo find /var/www -type f -exec chmod 640 {} \;

9. Checking Running Services

# List all active services
sudo systemctl list-units --type=service --state=running

# List enabled services (start at boot)
sudo systemctl list-unit-files --type=service --state=enabled

# Check for services listening on network interfaces
sudo ss -tlnp | awk 'NR>1 {print $4, $6}'

Ask yourself: does this service need to be running? Does it need to be accessible from the network, or only locally?

10. Quick Wins

10.1 Update All Packages

sudo apt update && sudo apt upgrade -y

10.2 Disable Unused Services

# Example: disable and stop a service you don't need
sudo systemctl disable --now cups
sudo systemctl disable --now avahi-daemon
sudo systemctl disable --now rpcbind

10.3 Secure Shared Memory

Add this line to /etc/fstab:

tmpfs /run/shm tmpfs defaults,noexec,nosuid 0 0

10.4 Set Login Banners

echo "Authorized access only. All activity is monitored and logged." | sudo tee /etc/issue.net
# In /etc/ssh/sshd_config:
# Banner /etc/issue.net

10.5 Enable Process Accounting

sudo apt install acct
sudo systemctl enable --now acct

Troubleshooting

Locked out of SSH after changing the port?

Use your hosting provider's console/VNC access. Fix the port in /etc/ssh/sshd_config and ensure the firewall allows it:

sudo ufw allow 2222/tcp
sudo systemctl restart sshd

fail2ban banned your own IP?

# Unban an IP address
sudo fail2ban-client set sshd unbanip YOUR_IP_ADDRESS

# Whitelist your IP permanently in jail.local
# ignoreip = 127.0.0.1/8 YOUR_IP_ADDRESS

UFW blocking legitimate traffic?

# Check which rule is blocking
sudo ufw status numbered

# Delete a specific rule by number
sudo ufw delete RULE_NUMBER

# Or temporarily disable to diagnose
sudo ufw disable

Unattended-upgrades not running?

# Check the log
sudo cat /var/log/unattended-upgrades/unattended-upgrades.log

# Verify the service timer
sudo systemctl status apt-daily-upgrade.timer

Prevention & Ongoing Maintenance

Need Expert Help?

Want a professional security check with a clear report? €39.

Book Now — €39

100% money-back guarantee

HR

Harald Roessler

Infrastructure Engineer with 20+ years experience. Founder of DSNCON GmbH.