This is the order we work through on projects. Each step stands alone, so you can start at the top and stop wherever you like.

1. Lock down SSH

Disable password login and accept keys only:

# /etc/ssh/sshd_config
PermitRootLogin no
PasswordAuthentication no
KbdInteractiveAuthentication no
AllowUsers deploy
MaxAuthTries 3

After each change, test login from a separate terminal before closing your current session. That is the only way you don't lock yourself out.

2. Firewall with default-deny

ufw default deny incoming
ufw default allow outgoing
ufw allow 22/tcp
ufw allow 443/tcp
ufw enable

The golden rule: any port whose purpose you can't explain in one sentence should be closed.

3. Automatic security updates

apt install unattended-upgrades
dpkg-reconfigure --priority=low unattended-upgrades

Automate security patches only, not every package. Fully automatic upgrades can break a service in the middle of the night.

4. Remove unnecessary services

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

Investigate anything you don't recognise. A service that isn't running isn't vulnerable either.

5. A separate user per application

Nothing should run as root. Create a shell-less user for each service:

useradd --system --no-create-home --shell /usr/sbin/nologin appsvc

6. Fail2ban for repeated attempts

[sshd]
enabled = true
maxretry = 4
bantime = 3600
findtime = 600

7. File integrity

With AIDE, or the Arg Box agent, watch for changes in /etc, /bin and /usr/bin. A sudden change in those paths is almost always meaningful.

8. Synchronised time

timedatectl set-ntp true

Without synchronised clocks, correlating logs across servers is effectively impossible. This simple step earns its keep during an investigation.

9. Ship logs off the host

# /etc/rsyslog.d/60-forward.conf
*.* @@log-collector.internal:6514

If logs live only on that server, an attacker who owns the server can erase them.

10. Tested backups

A backup that has never been restored isn't a backup; it's an assumption. Rehearse a full restore at least quarterly, and record how long it took.


Final verification

Once every step is done, scan from outside:

nmap -sS -sV -p- your-server-ip

Any port in that output you weren't expecting is exactly what you work on next.