Skip to content
Launch offerNew accounts: we double your first deposit of $100 or more, up to $250 bonus.Claim my bonus
LiteKeep
Sign inDeploy a server

Complete guide, 2026

How to secure a VPS. Without locking yourself out.

We switched on a brand-new server. Within 24 minutes, a stranger was guessing its root password. This guide shows what happened next, and exactly how to make sure it doesn’t matter.

  • 21 min read
  • 8 chapters
  • Updated
fail2ban switched onServer first boots69 hours later1,780 guesses in one hour

The short answer

Do five things, in this order: install updates, create a sudo user with an SSH key, test that login in a second window, allow SSH in the firewall before you switch it on, then turn off root and password logins.

Add automatic security updates, fail2ban and an off-server backup, and you have stopped the attacks that hit every new server. The order matters as much as the steps: get it wrong and you lock yourself out. On a LiteKeep server the web console turns even that into a five-minute fix.

That chart above isn’t a stock image. It’s every hour of password guessing against one of our own brand-new servers, read from its logs.

14,526 failed logins in about 70 hours. From 219 different addresses. Nearly half of them aimed straight at root.

Nobody targeted us. Bots scan the whole internet and knock on every door they find. Yours too, from the minute your server gets an IP address.

Here’s the good news: stopping them takes about half an hour. And none of it is hard.

The hard part is the order. Switch the firewall on before allowing SSH, or turn off root before a second login exists, and you’re locked out of your own machine.

So this guide is built around one rule: test before you lock.

In this guide you’ll learn

  • What actually attacks a new server, with our own real numbers
  • The lockout-safe order, with two test gates that keep you in
  • A free plan generator that writes your exact commands
  • Ubuntu 24.04 vs 22.04: the SSH change most guides miss
  • Why Docker can punch holes in your firewall, and the fix
  • Backups, monitoring, and what to do if something goes wrong

Chapter 1

Before you touch anything

Security work changes how you get into your server. So first, make sure you always have another way in.

Three things. Five minutes. They turn every mistake in this guide from a disaster into an inconvenience.

1. Open your web console once

Every LiteKeep server has a web console on its page in your account. It works even when SSH doesn’t: it’s like plugging a screen into the server. Open it now, before you need it, and check that you can log in there.

2. Take a snapshot

Take one from the server’s Snapshots tab. If you break something badly, you can roll the whole server back in minutes.

3. Keep your first session open

The SSH window you’re logged in with right now is your lifeline. Don’t close it until the very last test passes. Changes to SSH don’t kick out a session that’s already connected, so this window keeps working even if a setting goes wrong.

Chapter 2

Your lockout-safe plan

Here’s the whole job on one page. Then a tool that writes every command for your exact server.

Every step in this guide fits into this sequence. The two highlighted boxes are tests. You don’t move past them until they pass.

  1. 1Safety netConsole, snapshot, keep this session open
  2. 2UpdatePatch now, then automatically
  3. 3Your user + keysudo user, ed25519 key
  4. ✓TestSecond window: log in, sudo
  5. 4FirewallAllow SSH first, then enable
  6. 5Lock SSHKeys only, no root, sshd -t
  7. ✓Test againKey works, root refused
  8. 6fail2ban + backupsQuiet the noise, copy off-server
Figure 2. The lockout-safe order. The two highlighted steps are tests: don’t move on until they pass.

Why this order? Because each step only takes something away after you’ve proven its replacement works. A new user before root goes away. A firewall rule for SSH before the firewall goes up. A working key before passwords go off.

Generate your exact commands

Pick your system, choose a username, tick what you need. The plan updates as you type. It handles the Ubuntu 24.04 SSH change for you, and it warns you if you pick a username the bots already guess.

Operating system

Runs in your browser. Nothing you type here is sent anywhere.

  1. 1

    Set up your safety net

    Open your server’s web console once (on LiteKeep it’s on the server’s page in your account, and it works even when SSH doesn’t) and take a snapshot. Then keep this first SSH session open until the very end.

  2. 2

    Install every update

    In your root session

    Most break-ins use holes that already have a fix. Patch first.

    apt update && apt full-upgrade -y
  3. 3

    Turn on automatic security updates

    In your root session

    So the next fix installs itself, even when you’re asleep.

    apt install -y unattended-upgrades
    dpkg-reconfigure -plow unattended-upgrades

    Check: cat /etc/apt/apt.conf.d/20auto-upgrades

  4. 4

    Create your admin user "maria"

    In your root session

    You’ll log in as this user and use sudo, so root never needs to log in over SSH.

    adduser maria
    usermod -aG sudo maria
    install -d -m 700 -o maria -g maria /home/maria/.ssh
    cp /root/.ssh/authorized_keys /home/maria/.ssh/authorized_keys
    chown maria:maria /home/maria/.ssh/authorized_keys
    chmod 600 /home/maria/.ssh/authorized_keys
  5. 5

    Test the new login in a second window

    On your own computer

    Open a new terminal on your own computer. Leave the root session open.

    ssh [email protected]
    sudo whoami

    Stop and test. It must print "root". If it doesn’t, stop here and fix it from the root session.

  6. 6

    Switch on the firewall, SSH first

    As your new user

    Allow SSH before you enable the firewall. Enabling it first is how people lock themselves out.

    sudo apt install -y ufw
    sudo ufw default deny incoming
    sudo ufw default allow outgoing
    sudo ufw allow 22/tcp
    sudo ufw allow 80,443/tcp
    sudo ufw enable

    Check: sudo ufw status verbose

    Stop and test. ufw asks to confirm because it may disrupt SSH. Answer y. Your session stays up because port 22 is allowed.

  7. 7

    Lock down SSH: keys only, no root

    As your new user

    Drop-in files are read in name order and for SSH the first value wins. Some server images ship their own, often allowing passwords. 00-hardening sorts before them; the check below shows which value actually won.

    sudo tee /etc/ssh/sshd_config.d/00-hardening.conf > /dev/null <<'EOF'
    PermitRootLogin no
    PasswordAuthentication no
    KbdInteractiveAuthentication no
    AllowUsers maria
    EOF
    sudo sshd -t
    sudo systemctl restart ssh

    Check: sudo sshd -T | grep -Ei '^(permitrootlogin|passwordauthentication|kbdinteractiveauthentication|allowusers|port) '

    Stop and test. "sudo sshd -t" must print nothing. If it prints an error, do not restart: fix the file first.

  8. 8

    Test again before you close anything

    On your own computer

    One more new terminal. Your key should work, and root should be refused.

    Stop and test. The first must log you in. The second must fail with "Permission denied (publickey)".

  9. 9

    Ban password guessers with fail2ban

    As your new user

    With passwords off, guessing can’t succeed. fail2ban keeps the noise and log spam down.

    sudo apt install -y fail2ban python3-systemd
    sudo tee /etc/fail2ban/jail.local > /dev/null <<'EOF'
    [sshd]
    enabled = true
    backend = systemd
    port = 22
    maxretry = 5
    findtime = 10m
    bantime = 1h
    EOF
    sudo systemctl enable --now fail2ban
    sudo systemctl restart fail2ban

    Check: sudo fail2ban-client status sshd

  10. 10

    If you ever get locked out

    In your root session

    Log in through your server’s web console (on LiteKeep, on the server’s page in your account) and undo the SSH and firewall changes.

    rm /etc/ssh/sshd_config.d/00-hardening.conf
    systemctl restart ssh
    ufw disable

Want a clean server to run this on? A Lite 2 is usually ready within 15 minutes, comes with a web console for lockouts, and bills by the hour. Deploy a Lite 2 and paste this plan

No server yet? Deploy a Lite 2, paste this plan in its first minute online, and you start hardened instead of catching up. It bills by the hour, so a practice run costs cents.

Prefer to understand each step before you run it? Good instinct. The next five chapters walk through them one at a time.

Chapter 3

Update now, and forever

Most break-ins don’t use clever new tricks. They use old holes that already have a fix nobody installed.

Start with every update available:

apt update && apt full-upgrade -y

Then make sure the next fix installs itself. On Ubuntu Server, unattended-upgrades is installed by default and applies security updates automatically. Some images ship without it, so check. On Debian, you usually need to switch it on:

apt install -y unattended-upgrades
dpkg-reconfigure -plow unattended-upgrades

Then prove it runs. We’ve seen a server with it switched on and its timers masked, so it had never installed anything. Our unattended upgrades tutorial has a one-paste checker.

Confirm it’s on:

cat /etc/apt/apt.conf.d/20auto-upgrades

You want to see both lines set to "1".

Why this matters: a real example

In July 2024, a serious flaw in OpenSSH known as regreSSHion (CVE-2024-6387) let attackers run code on a server without logging in. Ubuntu 22.04 and 24.04 were affected. Fixed packages shipped on 1 July 2024, and servers with automatic security updates picked them up on their own.

Servers without them waited for someone to remember.

Chapter 4

Your own user and an SSH key

Every bot on the internet knows your server has a user called root. Make sure that knowledge is worthless.

Create an SSH key on your computer

An SSH key is a pair of files: a private one that never leaves your computer, and a public one you give to the server. There’s nothing to guess. macOS and Linux include the tool, and on Windows 10 and 11 it’s a built-in optional feature (our Windows walkthrough checks and installs it):

ssh-keygen -t ed25519

Press Enter to accept the location, then set a passphrase. Your public key is the file ending in .pub.

Create your own user on the server

Pick a username bots don’t guess. On our server, admin was tried 411 times, ubuntu 342 times and user 206 times. Then give it sudo:

adduser maria
usermod -aG sudo maria

Give your user the key

If you already log in as root with a key, copy it across. If you log in with a password, run ssh-copy-id maria@your-server-ip from a Mac or Linux computer instead. Windows has no ssh-copy-id; use the one-line PowerShell copy from our tutorial.

install -d -m 700 -o maria -g maria /home/maria/.ssh
cp /root/.ssh/authorized_keys /home/maria/.ssh/
chown maria:maria /home/maria/.ssh/authorized_keys
chmod 600 /home/maria/.ssh/authorized_keys

Test gate 1

Open a new terminal on your computer. Keep the old one open. Then:

ssh maria@your-server-ip
sudo whoami

If it prints root, you have a working way in that doesn’t need root or a password. If it doesn’t, stop here and fix it from your first session.

Chapter 5

Lock down SSH

Now that your key works, turn off everything the bots were hoping for.

Don’t edit the main SSH config file. Create your own small file instead:

sudo tee /etc/ssh/sshd_config.d/00-hardening.conf > /dev/null <<'EOF'
PermitRootLogin no
PasswordAuthentication no
KbdInteractiveAuthentication no
AllowUsers maria
EOF

Why the “00-” in the name? Ubuntu’s main config reads every file in that folder, in alphabetical order. And for SSH, the first value it reads for a setting is the one it uses. A file starting with 00 is read first, so your settings win over anything another tool drops in later.

Now check before you apply. This one command catches typos that would stop SSH from starting:

sudo sshd -t

No output means no errors. Then apply it:

sudo systemctl restart ssh

And confirm what SSH is really using, after every file has been read:

sudo sshd -T | grep -Ei '^(permitrootlogin|passwordauthentication|kbdinteractiveauthentication|allowusers) '

Test gate 2

New terminal again. Your key should get you in. Root should be refused:

ssh maria@your-server-ip
ssh root@your-server-ip

The second one must fail with Permission denied (publickey). If both behave, you can finally close that first session.

Want a safety net that undoes a bad change by itself, and a checker for your live settings? Our SSH hardening tutorial has both, with the before-and-after numbers from our own server.

Ubuntu 24.04 vs 22.04: the change most guides miss

Since Ubuntu 22.10, SSH starts through systemd socket activation. For most settings nothing changes. For the port, it does:

Applying SSH changes by version
Ubuntu 22.04Ubuntu 24.04
How SSH startsssh.servicessh.socket starts ssh.service
After normal settingssystemctl restart sshsystemctl restart ssh
After changing the portsystemctl restart sshsystemctl daemon-reload, then restart ssh.socket
Service namesshssh

Should you change the SSH port?

It’s optional. A new port makes your logs much quieter, because most bots only knock on port 22. It doesn’t stop anyone who scans properly. Keys stop attackers. A port change just stops noise. If you do it, allow the new port in the firewall first, test it, and only then close 22. The generator in Chapter 2 does this in the right order.

Chapter 6

A firewall that can’t lock you out

A firewall closes every door you’re not using. Just make sure SSH is on the guest list before you lock up.

Ubuntu’s firewall tool is ufw, and it starts out disabled. Set it up in this order:

sudo apt install -y ufw
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow 22/tcp
sudo ufw allow 80,443/tcp
sudo ufw enable

Only add the web line if the server runs websites. When ufw warns that enabling it may disrupt SSH, answer y. You already allowed port 22, so your session survives.

Check the result:

sudo ufw status verbose

On LiteKeep, DDoS filtering at the network edge is included with every Lite. Floods are dealt with before they reach your server, so ufw only has to decide which doors are open.

Chapter 7

What attacks really look like

We didn’t want to guess what hits a new server. So we measured it.

We read the logs of one of our own servers from the moment it first booted. No addresses were kept, just counts.

24 minfrom first boot to the first password guess
14,526failed password attempts in about 70 hours
209attempts an hour, on average
219different addresses doing the guessing

Usernames bots guessed most (none existed with a password)

  1. admin411
  2. ubuntu342
  3. user206
  4. deploy183
  5. test148
  6. user197
  7. ftpuser70

7,110 more attempts went straight for root.

Figure 1. What hit a brand-new LiteKeep server (Ubuntu 22.04, SSH on port 22) between 19 and 22 October 2026, read from its own logs. One server and one window: an example, not a global rate.

Look at the usernames. admin, ubuntu, user, test, postgres. These bots don’t know anything about you. They try the same list on every server on the internet.

That’s exactly why the steps in this guide work so well. With passwords off, every one of those 14,526 guesses was guaranteed to fail.

So why add fail2ban?

fail2ban watches your logs and blocks addresses that keep failing. It doesn’t make weak passwords safe. What it does is cut the noise.

On our server, after we switched fail2ban on, failed attempts in the log fell from an average of 324 an hour to 23. You can see the drop in the chart at the top of this guide.

sudo apt install -y fail2ban python3-systemd
sudo tee /etc/fail2ban/jail.local > /dev/null <<'EOF'
[sshd]
enabled = true
backend = systemd
maxretry = 5
findtime = 10m
bantime = 1h
EOF
sudo systemctl enable --now fail2ban
sudo systemctl restart fail2ban

MythChanging the SSH port secures SSH.

Fact

It quiets your logs. Keys are what stop attackers.

Mythfail2ban makes password logins safe.

Fact

It slows guessing down. Turning passwords off makes guessing pointless.

MythNobody would bother attacking my small server.

Fact

Ours was being guessed at 24 minutes after first boot. Bots don’t check who you are.

MythMy firewall hides my Docker containers.

Fact

Published Docker ports bypass ufw. Bind private services to 127.0.0.1.

Chapter 8

Backups, checks and bad days

Hardening makes trouble unlikely. Backups make it survivable. Here’s how to finish the job.

Back up somewhere else

A snapshot lives with your server. If the account, the location or the disk has a bad day, so does the snapshot. A real backup lives somewhere else: another server, ideally in another country. A Vault in a second location works well for this.

And a backup you’ve never restored is a hope, not a backup. Once a month, restore one file. Once a quarter, restore the whole thing to a test server.

Check your work

Run through this list after hardening, and again whenever you change something:

  1. Root can’t log in over SSHHow to check: From your computer, ssh root@your-server-ip fails with “Permission denied (publickey)”.
  2. Passwords are offHow to check: sudo sshd -T | grep passwordauthentication prints no.
  3. Only the ports you need are openHow to check: sudo ufw status verbose and sudo ss -tlnp match what you expect.
  4. Security updates install themselvesHow to check: Both lines in /etc/apt/apt.conf.d/20auto-upgrades are "1", both apt timers are enabled (not masked), and /var/log/unattended-upgrades/ has recent entries.
  5. fail2ban is watching SSHHow to check: sudo fail2ban-client status sshd shows the jail with a failure count.
  6. A backup exists off the serverHow to check: You restored a file from it this month.

If you get locked out

Open your server’s web console in your LiteKeep account, log in, and undo the last change. Removing your SSH file and restarting puts SSH back to its defaults:

rm /etc/ssh/sshd_config.d/00-hardening.conf
systemctl restart ssh
ufw disable

Fix the mistake, then go through the steps again, testing as you go.

If you think you’ve been hacked

Don’t try to clean a compromised server. You can’t be sure you found everything.

  1. Cut it off. Stop the server or block its traffic, but keep the disk for evidence.
  2. Change every secret it held. SSH keys, API keys, database and hosting passwords.
  3. Build a fresh server and harden it with this guide before anything else.
  4. Restore your data from a backup made before the break-in.
  5. Find the way in so it doesn’t happen twice.

Quick answers

How long does all this take? About 30 minutes the first time, less with the generator.

Does a VPS come with a firewall? LiteKeep filters DDoS traffic at the network edge on every Lite. That stops floods, not logins, so set up ufw yourself too.

Is a VPS more secure than shared hosting? It can be, because nobody else runs code on your system. But you’re responsible for the security, which is what this guide is for.

Now it’s your move

Remember the first chart in this guide? Thousands of guesses an hour, from strangers who didn’t know or care whose server it was.

After half an hour of work, every one of those guesses fails. That’s the whole point.

Start with a clean server and do it right from minute one. Deploy a Lite, run the generator’s plan, and you’re hardened before the bots finish their first scan. It bills by the hour, so a practice run costs cents, and the web console is there if anything goes wrong.