Bots start trying to log in to a new VPS within minutes. Here's the half-hour checklist for Ubuntu 24.04: SSH keys, no root login, a firewall, fail2ban and updates.
A new VPS gets its first login attempts within minutes of going online. Automated scanners sweep public IP ranges around the clock, and port 22 on a fresh server with a root password is exactly what they are looking for. Nobody has to know your server exists for this to happen. Being on the internet is enough.
The changes that shut out nearly all of this traffic take about half an hour, and you only make them once. This walkthrough assumes Ubuntu 24.04 LTS, which is also the version NexPanel installs on, but the steps are close to identical on Debian.
Most of the steps below change how you log in. If you make a mistake in the SSH configuration, you can lock yourself out, so it's worth knowing the recovery route first.
Every Lvato VPS has a VNC console in the dashboard. It connects to the server's screen directly rather than over SSH, so it still works when SSH is broken or blocked by the firewall. If you lose the root password as well, open a support ticket and it can be reset for you. Keep one SSH session open the whole time you work through this guide, and test every change from a second terminal before closing the first.
The image your server was built from is a snapshot, and packages have usually been patched since it was made. Log in as root with the credentials from provisioning and run:
apt update && apt upgrade -y
If the upgrade installs a new kernel, reboot now with reboot so you aren't running the old one. It's a better time to reboot than later, when the server is doing real work.
Working as root all the time means every typo runs with full privileges. Create your own user and give it sudo rights instead. Replace deploy with any name you like:
adduser deploy
usermod -aG sudo deploy
adduser asks for a password. Pick a strong one, because sudo will ask for it, even after you switch SSH logins to keys.
A key pair replaces the password for SSH logins. The private key stays on your computer, and the server only holds the public half, so there is nothing for a scanner to guess.
On your own computer (Linux, macOS, or Windows 10 and 11, which include the OpenSSH client), generate a key if you don't have one already:
ssh-keygen -t ed25519
Accept the default file location and set a passphrase when asked. Then copy the public key to the new user. On Linux or macOS:
ssh-copy-id deploy@203.0.113.10
Windows doesn't ship ssh-copy-id, so in PowerShell use this instead:
type $env:USERPROFILE\.ssh\id_ed25519.pub | ssh deploy@203.0.113.10 "mkdir -p ~/.ssh && chmod 700 ~/.ssh && cat >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys"
Replace the IP with your server's address. Now open a new terminal and check that the key works:
ssh deploy@203.0.113.10
If it logs you in without asking for the account password (it may ask for the key's passphrase), move on. If it still asks for the account password, the key didn't copy correctly, and you should fix that before going further.
With key login working, you can stop SSH from accepting passwords at all. On Ubuntu 24.04 the main config file reads extra settings from /etc/ssh/sshd_config.d/, and the first value SSH reads for a setting is the one it uses. Cloud images often include a file in that folder that turns password login on, so give your file a name that sorts first:
sudo nano /etc/ssh/sshd_config.d/01-hardening.conf
Add these lines:
PermitRootLogin no
PasswordAuthentication no
KbdInteractiveAuthentication no
Check the syntax, then restart SSH:
sudo sshd -t
sudo systemctl restart ssh
sshd -t prints nothing when the config is valid. If it prints an error, fix it before restarting. Then, keeping your current session open, try to log in from a second terminal as deploy with your key, and confirm that ssh root@203.0.113.10 is now refused.
Some people also move SSH to a port other than 22. It cuts down the noise in your logs, but it isn't real protection, since scanners check other ports too. With passwords disabled, the login attempts in your logs can't succeed anyway.
Ubuntu includes ufw, a simple front end for the Linux firewall. It comes installed but switched off. The order of these commands matters: allow SSH before you enable the firewall, or you will cut off your own session.
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow OpenSSH
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable
That leaves SSH and web traffic open and blocks everything else coming in. Check the result with sudo ufw status verbose. If the server won't host a website, leave out the 80 and 443 lines.
Open other ports only when something needs them, and only as far as it needs them. A database that only your own app uses should listen on 127.0.0.1 and never be reachable from the internet. If you need to reach it from one fixed address, such as your office, allow only that address:
sudo ufw allow from 198.51.100.25 to any port 3306 proto tcp
fail2ban watches log files and blocks IP addresses that keep failing to log in. With passwords disabled, those attempts can't get in, but banning them keeps the logs readable and stops the server wasting time on them.
sudo apt install fail2ban -y
On Ubuntu the SSH jail is enabled by default, so it starts protecting SSH as soon as it's installed. Check it with:
sudo fail2ban-client status sshd
The output lists how many addresses it has banned so far. On a server that has been online for a day, that number is rarely zero.
Ubuntu Server ships with unattended-upgrades, which installs security updates automatically. It's usually on already, but confirm it rather than assuming:
systemctl status unattended-upgrades
If it isn't installed or isn't running, set it up with:
sudo apt install unattended-upgrades -y
sudo dpkg-reconfigure -plow unattended-upgrades
Automatic updates cover security patches, not new major versions, and they don't reboot the server on their own unless you configure them to. When you log in and see "System restart required", plan a reboot at a quiet time.
Everything above lowers the chance of a break-in. Backups decide how bad your day is if something goes wrong anyway, whether that's an attack, a bad update or a deleted folder. Two rules matter more than which tool you use. Store at least one copy somewhere other than the server itself, and restore a backup once on purpose, so you know it actually works before you need it.
If the server is going to run NexPanel, you can skip steps 5 and 6. The installer brings up its own nftables firewall and checks that it is actually filtering traffic before it finishes. It opens SSH, HTTP, HTTPS and the panel's own port 5000, and keeps the OpenLiteSpeed admin ports (7080 and 8088) closed. It also installs fail2ban, which bans SSH brute force as well as bad bots, secret probes and 404 floods, and it runs ModSecurity with the OWASP core rule set on every site. Scheduled backups with an optional off-site SFTP destination are built in too, which covers step 8.
If you've already enabled ufw, that's fine. NexPanel respects an existing ufw setup and applies its port changes to every active firewall, so when you add mail later its ports open in both. Port changes are best made from the panel's firewall page from then on, so the two firewalls don't contradict each other. The same page can change the SSH port, and it opens the new port in the firewall before switching.
Steps 1 to 4 and step 7 are still yours to do, because NexPanel doesn't manage your SSH keys or logins. Do them before you run the installer, which needs a fresh Ubuntu 24.04 server and root access. The full install instructions are on the NexPanel website.
| Step | Command or change |
|---|---|
| Update packages | apt update && apt upgrade -y |
| Create a sudo user | adduser deploy, usermod -aG sudo deploy |
| Install your SSH key | ssh-keygen -t ed25519, then ssh-copy-id |
| Disable password and root login | /etc/ssh/sshd_config.d/01-hardening.conf |
| Firewall | ufw, allowing only SSH, 80 and 443 |
| Ban brute force | apt install fail2ban |
| Automatic security updates | Check unattended-upgrades |
| Backups | Off-server copy, tested once |
If you'd like to try this on a clean machine first, the smallest Lvato VPS (1 vCPU, 1GB RAM, 25GB NVMe, 2TB bandwidth) is $7.99 for the first month. Every plan comes with full root access, a dedicated IP, the VNC console mentioned above, and a choice of operating systems including Ubuntu, Debian, AlmaLinux and Rocky Linux. You can also start from a one-click app such as NexPanel or Coolify instead of a bare OS. If you haven't picked a data centre yet, the guide on choosing a VPS location covers how to test the candidates before you order.