Skip to content

Blog · How-to

The first fifteen minutes on a new VPS

A freshly built server is at its most exposed in the window before you have configured anything. It has a public IP, a password, and an SSH daemon answering the whole internet. Automated scanners find new IPs in minutes — not hours. This is the order we do things in, and why.

1. Get in, and change the password you were emailed

Your handover email contains a root password in plain text. That email has been through at least two mail servers and is sitting in your inbox indefinitely. Treat it as compromised from the moment it arrives.

ssh root@203.0.113.10
passwd

You will replace password authentication entirely in step three, but do this first anyway. If something interrupts you, the emailed password should already be dead.

2. Make an unprivileged user with sudo

Working as root full-time means every typo is executed with full authority. The point of an ordinary user is not that you cannot become root — it is that you have to mean it.

# Debian / Ubuntu
adduser yourname
usermod -aG sudo yourname

# Rocky / Alma
adduser yourname
passwd yourname
usermod -aG wheel yourname

3. Keys in, passwords off

This is the step that matters most. Password authentication on a public SSH port is the single largest cause of compromised servers, and no password policy fixes it — the attacker has unlimited attempts and infinite patience.

From your own machine, not the server:

ssh-copy-id yourname@203.0.113.10

Then open a second terminal and confirm the key works before you disable passwords. Locking yourself out of a box you have just paid for is a rite of passage worth skipping.

# /etc/ssh/sshd_config
PermitRootLogin no
PasswordAuthentication no
KbdInteractiveAuthentication no
sudo systemctl restart ssh   # or sshd on RHEL-family

Modern distributions often override these in /etc/ssh/sshd_config.d/*.conf, and a file there wins over the main config regardless of order. If your change appears to do nothing, that is why. Check with sudo sshd -T | grep -E 'passwordauthentication|permitrootlogin', which prints what the daemon has actually concluded rather than what you hoped it would.

Should you move SSH off port 22?

It cuts log noise dramatically and stops the dumbest scanners. It is not security — anyone running a port scan finds it in seconds. Do it if the noise bothers you, but do not count it as a control, and never do it instead of disabling passwords.

4. A firewall that will not lock you out

Allow SSH before you enable the firewall. Every single time.

# Debian / Ubuntu
sudo apt install ufw
sudo ufw allow OpenSSH
sudo ufw allow 80,443/tcp
sudo ufw enable

# Rocky / Alma
sudo firewall-cmd --permanent --add-service={ssh,http,https}
sudo firewall-cmd --reload

Default-deny inbound, allow outbound. If you are running a database, do not expose it: bind it to 127.0.0.1 and reach it over an SSH tunnel or a private network. An open MySQL port with a weak password is how a great many servers end up mining somebody else's coins.

5. Automatic security updates

The gap between a patch being published and you applying it is the window everybody gets caught in. Unattended upgrades for security packages only is close to risk-free and removes that window.

# Debian / Ubuntu
sudo apt install unattended-upgrades
sudo dpkg-reconfigure -plow unattended-upgrades

# Rocky / Alma
sudo dnf install dnf-automatic
sudo systemctl enable --now dnf-automatic.timer

Kernel updates still need a reboot to take effect. Either schedule one, or install a live-patching service, but do not assume an up-to-date package list means an up-to-date running kernel. needrestart on Debian-family will tell you what is still running old code.

6. Fail2ban, with realistic expectations

Once passwords are off, fail2ban's SSH jail is doing very little — key auth cannot be brute forced. It earns its place on the application logs: your web login form, your mail server, your control panel.

sudo apt install fail2ban
sudo systemctl enable --now fail2ban

If you administer from a static address, allowlist it in ignoreip. Being banned by your own tooling during an incident is a special kind of frustrating.

7. Know what "backup" means here

Node redundancy is not a backup. RAID protects you from a disk dying. It does not protect you from DROP DATABASE, a bad deploy, or ransomware — all of which are faithfully replicated across every disk in the array, instantly.

A backup lives somewhere else, is taken automatically, and has been restored at least once. The third part is the one everyone skips, and an untested backup is a hypothesis rather than a backup.

The two mistakes that account for most of it

  1. Password authentication left on. Everything else on this page is optional tuning by comparison. If you do one thing, do this.
  2. A service bound to 0.0.0.0 that was meant to be internal. Redis, MySQL, Postgres, Elasticsearch, Docker publishing a port straight past your firewall. sudo ss -tlnp shows you exactly what is listening and on which address. Run it before you consider the box finished, and again after you install anything.

Fifteen minutes, and the box is in a state where the boring automated attacks slide off it. What remains is keeping your actual application secure, which no amount of server configuration does for you.

Related reading

Need a server to try this on?

KVM, full root, billed in bitcoin. From $12.00 a month.

See the plans