A new server on a public IP address gets its first SSH login attempts within minutes. Most of them are automated and simple, so a few basic steps stop nearly all of them. This checklist is the baseline we apply to every Linux server we manage, in the order we do it.
The commands are for Ubuntu and Debian. Run them as a user with sudo.
Before you start
Keep a second SSH session open while you change SSH or firewall settings. If a change locks you out, you can still fix it from the open session. Most cloud providers also offer a web console as a last resort.
1. Update everything
sudo apt update && sudo apt full-upgrade -y
sudo reboot
Reboot if the kernel was updated. A server running an old kernel is still exposed to the bugs the update fixed.
2. Create a named admin user
Don't work as root. A named user makes the logs show who did what, and lets you remove one person's access without touching anyone else's.
sudo adduser alice
sudo usermod -aG sudo alice
3. Use SSH keys, then turn off passwords
On your own computer, create a key if you don't have one and copy it to the server:
ssh-keygen -t ed25519 -C "alice@company"
ssh-copy-id alice@203.0.113.10
Log in with the key in a new terminal to confirm it works. Then create /etc/ssh/sshd_config.d/10-hardening.conf on the server:
PermitRootLogin no
PasswordAuthentication no
KbdInteractiveAuthentication no
PubkeyAuthentication yes
MaxAuthTries 3
LoginGraceTime 30
X11Forwarding no
AllowUsers alice
Check the config and reload SSH:
sudo sshd -t && sudo systemctl reload ssh
sshd -t prints nothing when the config is valid. Test a new login before you close your current session.
4. Turn on a default-deny firewall
Allow only what the server actually serves. For a web server:
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow OpenSSH
sudo ufw allow 80,443/tcp
sudo ufw enable
sudo ufw status verbose
If only your office or VPN needs SSH, limit it to that address with sudo ufw allow from 198.51.100.7 to any port 22 proto tcp, then delete the general OpenSSH rule.
Your cloud provider's firewall (AWS security groups, DigitalOcean or Hetzner cloud firewalls) adds a second layer in front of the server. Use both.
5. Install automatic security updates
sudo apt install unattended-upgrades -y
sudo dpkg-reconfigure --priority=low unattended-upgrades
This installs security patches every day. To reboot automatically at a quiet hour when an update needs it, set these in /etc/apt/apt.conf.d/50unattended-upgrades:
Unattended-Upgrade::Automatic-Reboot "true";
Unattended-Upgrade::Automatic-Reboot-Time "04:00";
6. Block brute-force attempts with Fail2ban
sudo apt install fail2ban -y
Create /etc/fail2ban/jail.local:
[DEFAULT]
bantime = 1h
findtime = 10m
maxretry = 5
[sshd]
enabled = true
sudo systemctl enable --now fail2ban
sudo fail2ban-client status sshd
Add jails for Nginx, Postfix or your application's login page once those are installed.
7. Remove services you don't use
List everything listening on a network port:
sudo ss -tulpn
Each line should be something you can explain. Stop and disable the rest, for example:
sudo systemctl disable --now cups
Databases such as MySQL, PostgreSQL and Redis should listen on 127.0.0.1 only, unless another server needs to reach them over a private network.
8. Check sudo access and accounts
getent group sudo
sudo awk -F: '$3 == 0 {print $1}' /etc/passwd
The first command lists who can use sudo. The second must print only root; any other account with user ID 0 has full root access. Lock accounts that shouldn't log in with sudo usermod -L username.
9. Secure shared memory and temporary files
Stop programs being run from /tmp and /dev/shm, a common trick in web exploits. Add to /etc/fstab:
tmpfs /dev/shm tmpfs defaults,noexec,nosuid,nodev 0 0
Then run sudo mount -o remount /dev/shm. If /tmp is a separate partition, mount it with the same options. Test your application afterwards: a few installers expect to run scripts from /tmp.
10. Apply safe kernel network settings
Create /etc/sysctl.d/99-hardening.conf:
net.ipv4.tcp_syncookies = 1
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.all.accept_redirects = 0
net.ipv6.conf.all.accept_redirects = 0
net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.all.accept_source_route = 0
net.ipv4.icmp_echo_ignore_broadcasts = 1
kernel.dmesg_restrict = 1
kernel.kptr_restrict = 2
fs.protected_hardlinks = 1
fs.protected_symlinks = 1
Load it with sudo sysctl --system. Leave out the rp_filter line on servers that route traffic, such as VPN gateways.
11. Keep time in sync
Logs, TLS certificates and two-factor codes all depend on the correct time.
timedatectl status
Check that it shows System clock synchronized: yes. If not, run sudo timedatectl set-ntp true.
12. Keep logs, and keep them somewhere else
Logs on a hacked server can be deleted by the attacker. Make the system journal persistent, and send copies to a separate log service or server:
sudo mkdir -p /var/log/journal
sudo systemctl restart systemd-journald
For a record of who ran what and which sensitive files changed, install auditd. To read failed logins quickly:
sudo journalctl -u ssh --since "24 hours ago" | grep -i "failed"
13. Watch for file changes
A file integrity checker records a fingerprint of system files and reports when one changes. AIDE is the standard tool:
sudo apt install aide -y
sudo aideinit
Run it daily from cron and email the report. On web servers, also watch the website folders for new PHP files, which is how most web shells arrive.
14. Take backups you have tested
Back up the data and the configuration (/etc, web server and database config), not just the website files. Store at least one copy off the server and outside the same cloud account, so one compromised login can't delete both.
A backup you have never restored is a guess. Restore to a test server at least once a quarter.
15. Monitor the server
At a minimum, get alerts for:
- the server or website going down
- disk space above 80%
- sustained high CPU or memory usage
- failed SSH logins and Fail2ban bans
- changes to system files or new admin users
Alerts only help if someone reads them, including at night and at weekends.
Check your work
Run a free audit tool to catch anything you missed:
sudo apt install lynis -y
sudo lynis audit system
Lynis prints a hardening index and a list of suggestions. Not every suggestion fits every server, so read them rather than applying them all.
When to bring in help
The checklist is the starting point. Keeping it in place is the harder part: updates that need a reboot, new users, expiring certificates, and alerts at 3 a.m. That is the work our Linux server management plans cover, with 24/7 security monitoring for failed logins, file changes and malware.

