A few minutes after a VPS boots, its SSH port starts receiving login attempts from unknown addresses. It is nothing personal: bots constantly scan the internet for open servers and try weak passwords. Before you install a website or application, run through a few basic steps. The commands below target Ubuntu 22.04 and 24.04 and work almost unchanged on Debian.
1. First login and updates
You will receive an IP address plus a root password or SSH key. Connect and update the packages first, since images may be weeks or months old:
ssh root@203.0.113.10
apt update && apt upgrade -y
If the kernel was updated, /var/run/reboot-required will exist. Finish the remaining steps and reboot once at the end.
2. A regular user instead of root
Working as root all day is risky, and root is the account bots target most. Create your own user with sudo rights (replace deploy with your name of choice). The password you set is for confirming sudo commands, so make it long:
adduser deploy
usermod -aG sudo deploy
3. SSH key login
Generate a key pair on your own computer and copy the public half to the server. On Windows 10 and 11 this works in PowerShell too; if ssh-copy-id is missing, copy the public key manually:
ssh-keygen -t ed25519 -C "laptop-office"
ssh-copy-id deploy@203.0.113.10
Open a new terminal and log in with ssh deploy@203.0.113.10, then run sudo -v to confirm sudo works.
4. Disable root and password logins
Recent Ubuntu releases also read files in /etc/ssh/sshd_config.d/, and one of them, such as 50-cloud-init.conf on cloud images, may re-enable passwords. SSH uses the first value it finds and reads these files alphabetically, so put your settings in a file that sorts first:
sudo nano /etc/ssh/sshd_config.d/00-hardening.conf
PermitRootLogin no
PasswordAuthentication no
KbdInteractiveAuthentication no
sudo sshd -t
sudo grep -ri passwordauthentication /etc/ssh/sshd_config /etc/ssh/sshd_config.d/
sudo systemctl restart ssh
Do not close your current session. Test a fresh login in a new window first; one typo can otherwise lock you out.
5. Firewall
Allow SSH before enabling UFW, then open web ports if you will host a site:
sudo ufw allow OpenSSH
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable
sudo ufw status verbose
Keep MySQL, Redis and app ports on 127.0.0.1. sudo ss -tulpn lists what is listening.
6. Time zone and hostname
sudo timedatectl set-timezone Asia/Tashkent
sudo hostnamectl set-hostname web1.example.uz
Correct time makes logs, cron jobs and backups readable, and a clear hostname stops you from typing into the wrong terminal.
7. Automatic security updates and fail2ban
sudo apt install unattended-upgrades fail2ban
sudo dpkg-reconfigure --priority=low unattended-upgrades
sudo systemctl enable --now fail2ban
sudo fail2ban-client status sshd
Unattended upgrades cover system packages only; your CMS, plugins and app libraries are still your job. fail2ban temporarily bans addresses after repeated failures, and on Ubuntu its SSH jail is enabled by default.
Example: preparing a small shop's server
A Tashkent clothing store is moving from shared hosting to a VPS. On day one the developer completes these steps, reboots, and only then installs Nginx, PHP and MySQL under the new user with only the needed ports open. The domain's DNS record is switched to the new server last, after the site is fully tested; on sayt.uz this is done in the DNS section of the cabinet. Finally, run sudo reboot and confirm you can still log in with your key. Half an hour spent here saves many hours of trouble later.