Debian 12 minimal server checklist
Every new VPS gets the same treatment before anything else is installed. None of this is clever; the point is to do it every time, in the same order, so nothing is forgotten.
1. Update and enable unattended upgrades
apt update && apt full-upgrade -y
apt install -y unattended-upgrades apt-listchanges
dpkg-reconfigure -plow unattended-upgrades
The default policy installs security updates only, which is what I want on a server. Check /var/log/unattended-upgrades/ after a day to confirm it ran.
2. A user, a key, and no passwords over SSH
adduser deploy
usermod -aG sudo deploy
install -d -m 700 -o deploy -g deploy /home/deploy/.ssh
# paste your public key into /home/deploy/.ssh/authorized_keys
Then put the SSH policy in a drop-in file instead of editing the main config, so package upgrades never conflict with it:
# /etc/ssh/sshd_config.d/10-hardening.conf
PasswordAuthentication no
KbdInteractiveAuthentication no
PermitRootLogin prohibit-password
sshd -t && systemctl reload ssh
3. Firewall
Debian 12 uses nftables. A small ruleset that allows SSH, HTTP and HTTPS and drops the rest:
#!/usr/sbin/nft -f
flush ruleset
table inet filter {
chain input {
type filter hook input priority 0; policy drop;
iif lo accept
ct state established,related accept
ct state invalid drop
meta l4proto { icmp, ipv6-icmp } accept
tcp dport { 22, 80, 443 } accept
}
}
nft -c -f /etc/nftables.conf && systemctl enable --now nftables
Docker writes its own rules and published container ports bypass this chain — keep that in mind if you run containers.
4. Time, logs and swap
- Time:
timedatectlshould show "System clock synchronized: yes".systemd-timesyncdis enough for most servers. - Journal size: set
SystemMaxUse=500Min/etc/systemd/journald.confon small disks. - Swap: small instances often ship without it. A 1 GB swap file avoids the OOM killer during
aptruns.
fallocate -l 1G /swapfile && chmod 600 /swapfile
mkswap /swapfile && swapon /swapfile
echo '/swapfile none swap sw 0 0' >> /etc/fstab
5. Look at what is listening
ss -tulpn
Anything listening on 0.0.0.0 or [::] that you did not expect should be stopped or bound to 127.0.0.1. Images from hosting providers sometimes ship with extras enabled — test servers, agents, panels. Disable what you do not use with systemctl disable --now.
6. Write it down
Keep a short text file in /root or your notes with what was changed and why. Six months later it is the only documentation that exists.