How I secure a server, from first SSH access to the NSA guide
TL;DR
A new server exposed to the internet gets scanned within minutes by bots hunting for a weak password on port 22. The baseline: an SSH key instead of a password, a non-root user with limited rights, a firewall that closes everything but the strict minimum, fail2ban against the noise, and backups you actually restore to confirm they work. The NSA hardening guide, documented since 2011, formalizes the same principles: encrypt, shrink the attack surface, grant the fewest privileges.
1. An SSH key, never a password
When the server is created, I generate a key pair if I do not already have one available:
ssh-keygen -t ed25519
The public key (.pub) goes to the server, two ways depending on timing:
- At VPS creation: most hosts (Hostinger, DigitalOcean, Scaleway and others) show an "SSH key" field during instance setup, before first boot. Paste the contents of
~/.ssh/id_ed25519.pub(read it withcat ~/.ssh/id_ed25519.pub) into that field: the key is in place at first access, without ever typing a password. - On a server already created:
ssh-copy-id thomas@server-ip, or manually if that is unavailable:mkdir -p ~/.ssh && chmod 700 ~/.ssh echo "contents-of-the-public-key" >> ~/.ssh/authorized_keys chmod 600 ~/.ssh/authorized_keys
The private key never leaves my machine. A key replaces a password: nothing to remember, nothing to brute-force, and a compromise gets revoked by deleting one line from authorized_keys.
2. A non-root user, with counted rights
Logging in as root hands total access to whoever guesses the password or steals the key. I create a named user, never "admin" or "user" (those generic names do half an attacker's work, leaving only the secret to find):
adduser thomas
usermod -aG sudo thomas
By default the sudo group can do anything, without a password, from anywhere. visudo opens the configuration file (/etc/sudoers) in an editor that checks syntax before saving, so you do not lock yourself out with a broken file. A line like this restricts the user to a few precise commands rather than full access:
thomas ALL=(ALL) NOPASSWD: /usr/bin/systemctl restart nginx, /usr/bin/docker
That is least privilege applied to an account, not only to a service.
3. Updates, daily if possible
A VPS image is built at a point in time. Between that moment and the server's first boot, security patches ship. First reflex after connecting:
apt-get update && apt-get upgrade -y
The NSA guide recommends doing this daily, not weekly: a known, published flaw stays exploitable until the patch lands. A week of waiting is a week of exposure to a publicly documented vulnerability.
4. Harden the SSH configuration
In /etc/ssh/sshd_config, three lines to change before anything else:
PermitRootLogin no
PasswordAuthentication no
UsePAM no
The first closes direct root access. The second forces key use: without it, PermitRootLogin no can be bypassed if PAM stays active. The third disables the authentication module that, in some configurations, falls back to a password anyway. Restart the service after editing:
systemctl restart sshd
5. Fail2ban against noise, not against experts
With key authentication, a brute-force attack has close to no chance of landing. That is not the problem: an exposed server gets hammered with connection attempts continuously, and that traffic inflates the logs until they become useless.
apt-get install fail2ban
jail.conf gets overwritten on every package update: configuration goes in a dedicated copy, never in the original.
cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
In jail.local, under the [sshd] section, I set a loose threshold (maxretry = 15, findtime = 10m) rather than an aggressive one: too low a threshold eventually bans the office IP the day several keys get tried in a row. Then:
systemctl restart fail2ban
fail2ban-client status sshd
The last command confirms the sshd jail is active and shows currently banned IPs. Fail2ban limits the spam, it does not replace good authentication.
6. Firewall: two layers, not one
First reflex, iptables, allowing only what must pass:
iptables -A INPUT -i eth0 -p tcp --dport 22 -j ACCEPT
iptables -A INPUT -j DROP
These rules vanish at the next reboot unless they are saved. On Debian and Ubuntu:
apt-get install iptables-persistent
netfilter-persistent save
Second layer: the firewall the host provides, configured from its web interface rather than the command line. On Hostinger it lives in hPanel > VPS > Firewall; on DigitalOcean, Networking > Firewalls; on Scaleway, Network > Security Groups. The principle is the same everywhere: a list of inbound and outbound rules by port and source IP, applied before traffic even reaches the server. This firewall does not replace iptables, it adds to it, with one concrete advantage: a configuration mistake in iptables can cut off access to the server from the server itself. The provider firewall stays controllable from outside, so it remains recoverable even after a bad local move.
7. Private network and bastion, for everything that does not need the internet
A database has no reason to hold a public IP: only application servers should reach it. Most hosts offer a private network (typically the 10.0.0.0/8 range), created and attached to the relevant machines from their interface ("Private Network" section of the VPS panel, separate from the public network created by default). A machine can belong to both networks at once, or to the private network alone if nothing needs to reach it from the internet.
The classic setup: a bastion server, the single public entry point, running nothing but hardened SSH, connected to the private network where the databases and internal services live. From the bastion, a plain SSH connection (ssh user@private-ip) reaches internal machines without ever exposing them publicly. Everything goes through the bastion. Security effort concentrates on one machine, not ten.
8. Backups: restore them, do not just schedule them
A backup scheduled and never tested is false security. The failure comes, the restore fails, and you find out at the worst moment. Two ways to schedule backups:
- From the host's panel: most offer a "Backups" tab with a configurable frequency (daily, weekly) and retention, without installing anything on the server.
- By scripting it yourself, for finer control (database only, shipping to external storage): a
croncalling a dump script (pg_dump,mysqldumpand the like) followed by an upload to S3-compatible storage.
Either way, at regular intervals, restore a backup at random on a test machine and check the expected data is there, in full. A backup you have never restored is only a hypothesis.
9. What the NSA guide adds
The NSA's "Hardening Network Infrastructure" guide (documented since 2011, revised through 2016) formalizes three principles that overlap this checklist and push a little further:
- Shrink the attack surface: disable every unused service, not just secure it. An X11 server, a network printer or an NTP service running for no reason protects nothing: each active service is a potential hole, even one never exploited.
- SELinux or an equivalent module: a kernel module that checks, for every action a program takes (reading a file, opening a port), whether it has the right according to a central rule base. Rarely used in production because it is seen as hard to configure, but it is a control layer a firewall alone does not provide.
- Physical security: BIOS password, USB ports disabled on a datacenter server. If nobody is supposed to plug in a USB stick, make the port inert.
None of these replace the first eight. They close angles a checklist aimed at SSH and networking does not cover.