A fresh VPS is usually reachable from the whole internet within minutes, which means it starts attracting password guesses and random scans long before you finish installing your first real app. Doing a small amount of hardening early saves you from cleaning up preventable mistakes later.
In this guide, you will secure an Ubuntu VPS with SSH keys, tighten the SSH login path, enable a simple firewall with UFW, and add Fail2ban so repeated login abuse is automatically blocked.
What this tutorial covers
This is a practical beginner baseline, not an enterprise security policy.
By the end, your server should have:
- SSH key authentication working
- password-based SSH login disabled
- root SSH login disabled
- UFW allowing only the traffic you actually want
- Fail2ban watching SSH and banning repeated failed logins
What you need before you start
Have these ready first:
- an Ubuntu VPS with public internet access
- the server IP address
- a Linux user with
sudoprivileges - a local machine you can SSH from
- an SSH key pair on your local machine, or the ability to create one
If you are still building the rest of your stack, these guides pair well with this one:
- How to Install Docker on Ubuntu and Run Your First Container
- Docker Compose for Self-Hosted Apps: A Beginner-Friendly Guide
- How to Install Nginx Proxy Manager with Docker Compose
- How to Use Caddy as a Reverse Proxy for Self-Hosted Apps
Important safety rule before you change SSH settings
Keep your current SSH session open until you have tested a second login successfully.
That one habit prevents a lot of self-inflicted lockouts. If you edit SSH settings, reload the service, and discover that your new login no longer works, the still-open session is your recovery path.
Step 1: Connect to the server
From your local machine, connect to the VPS with SSH.
ssh your-user@your-server-ip
Replace:
your-userwith your Ubuntu usernameyour-server-ipwith the server's public IP address
If you are logging in as root today, plan to stop doing that once this guide is finished.
Step 2: Update package lists and install pending upgrades
Before changing security settings, bring the base system up to date.
sudo apt update
sudo apt upgrade -y
This reduces the chance that you harden a server that is already behind on security fixes.
Step 3: Check whether you already have an SSH key on your local machine
Run this on your local machine, not on the VPS.
ls -al ~/.ssh
If you already see files such as id_ed25519 and id_ed25519.pub, you may already have a usable key pair.
If not, create one.
Step 4: Create an SSH key pair if needed
On your local machine, generate a modern Ed25519 key pair.
ssh-keygen -t ed25519 -C "[email protected]"
You can accept the default file path unless you specifically want a separate key for this server. A passphrase is optional, but it is strongly recommended if this key lives on a laptop or desktop you carry around.
Step 5: Copy your public key to the server
From your local machine, use ssh-copy-id if it is available.
ssh-copy-id your-user@your-server-ip
This appends your local public key to the server's ~/.ssh/authorized_keys file for that user.
If ssh-copy-id is not installed on your local machine, you can still copy the contents of your .pub file into ~/.ssh/authorized_keys manually, but ssh-copy-id is the cleaner path for most beginners.
Step 6: Open a second SSH session and confirm key login works
Before you disable any password-based access, test a fresh login from a second terminal window.
ssh your-user@your-server-ip
If the login succeeds with your key, keep going. If it fails, stop here and fix key authentication first.
Do not disable password logins until this second SSH test works.
Step 7: Back up the SSH server config
Now make a backup of the SSH daemon config on the VPS.
sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak
That gives you a simple rollback point if you need it.
Step 8: Edit the SSH daemon config
Open the SSH config file on the VPS.
sudoedit /etc/ssh/sshd_config
Look for these settings and make sure they end up like this:
PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes
ChallengeResponseAuthentication no
What these settings do
PermitRootLogin nostops direct root login over SSHPasswordAuthentication noturns off password-based SSH loginPubkeyAuthentication yeskeeps SSH key login enabledChallengeResponseAuthentication nodisables interactive challenge/response logins that most beginners do not need
If one of these lines already exists elsewhere in the file, edit the existing line instead of adding conflicting duplicates.
Step 9: Check the SSH config for syntax problems
Before reloading SSH, validate the config.
sudo sshd -t
If this command returns no output, that usually means the config syntax is valid. If it prints an error, fix that before moving on.
Step 10: Reload the SSH service
Once the config test passes, reload the SSH daemon.
sudo systemctl reload ssh
Reloading applies the new config without fully rebooting the server.
Step 11: Test SSH again in a new session
Now do another fresh login test from your local machine.
ssh your-user@your-server-ip
You want this login to work before you close your original session.
If it fails, go back to the still-open session and restore your backup.
sudo cp /etc/ssh/sshd_config.bak /etc/ssh/sshd_config
Then reload SSH again.
sudo systemctl reload ssh
Step 12: Install UFW
Ubuntu commonly uses UFW as a simpler frontend for firewall rules. Install it if it is not already present.
sudo apt install ufw -y
Step 13: Allow SSH before enabling the firewall
This step matters a lot. If you enable UFW before allowing SSH, you can lock yourself out.
sudo ufw allow OpenSSH
Ubuntu's OpenSSH package normally provides this application profile for port 22.
Step 14: Set sensible default firewall policies
Deny unsolicited inbound traffic by default.
sudo ufw default deny incoming
Allow outbound traffic by default.
sudo ufw default allow outgoing
This is a good beginner baseline for a VPS that only needs a small number of public services.
Step 15: Enable UFW
Now turn the firewall on.
sudo ufw enable
UFW will warn you that this may affect existing SSH connections.
That is normal, and it is why you allowed OpenSSH first.
Step 16: Check firewall status
Confirm the firewall is active and that SSH is allowed.
sudo ufw status verbose
A healthy result should show:
Status: active- default incoming policy set to deny
- a rule allowing OpenSSH
Step 17: Allow only the extra ports you actually need
Do not open web ports just because you might use them later. Only allow what your server needs right now.
For example, if you later publish a reverse proxy, you might add HTTP and HTTPS like this:
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
If you are not serving public websites yet, leave those ports closed for now.
Step 18: Install Fail2ban
Fail2ban watches logs for repeated authentication failures and temporarily bans abusive IP addresses. Install it on the VPS.
sudo apt install fail2ban -y
Step 19: Create a local Fail2ban override file
Instead of editing the main package config directly, create a local override.
sudo tee /etc/fail2ban/jail.local >/dev/null <<'EOF'
[sshd]
enabled = true
backend = systemd
maxretry = 5
findtime = 10m
bantime = 1h
EOF
This enables the SSH jail and keeps the settings in a file that package updates are less likely to overwrite.
What these values mean
enabled = trueturns on the SSH jailbackend = systemdtells Fail2ban to read log events from systemd's journalmaxretry = 5bans after five failed attempts within the windowfindtime = 10mdefines the matching windowbantime = 1hsets a one-hour ban duration
You can make these stricter later, but this is a reasonable beginner starting point.
Step 20: Enable and restart Fail2ban
Make sure the service starts now and at boot.
sudo systemctl enable --now fail2ban
Then restart it so the new jail file is loaded cleanly.
sudo systemctl restart fail2ban
Step 21: Check Fail2ban status
Confirm the service is healthy.
sudo systemctl status fail2ban
Then ask Fail2ban which jails are active.
sudo fail2ban-client status
You should see sshd listed as one of the enabled jails.
To inspect the SSH jail directly, run:
sudo fail2ban-client status sshd
That gives you the current filter counts and any active bans.
What your baseline should look like now
At this point, your VPS should have a much better starting posture than a fresh default install:
- you log in with SSH keys instead of passwords
- root SSH login is disabled
- the firewall is active
- only required ports are open
- repeated SSH login abuse gets banned automatically
That is not “perfectly secure forever,” but it is a solid beginner baseline before you start exposing self-hosted apps.
Common mistakes to avoid
Disabling passwords before testing keys
This is the easiest way to lock yourself out. Always test a second SSH session first.
Enabling UFW before allowing SSH
If OpenSSH is not allowed before ufw enable, remote access can break immediately.
Editing package defaults directly
For Fail2ban, prefer jail.local over modifying the main packaged config files.
That makes future changes easier to track.
Opening ports you are not actually using
A firewall is more useful when it stays small and intentional. If you do not need a public port today, leave it closed.
Good next tutorials after this one
Once the server baseline is in place, the next useful steps are usually:
- How to Install Docker on Ubuntu and Run Your First Container
- Docker Compose for Self-Hosted Apps: A Beginner-Friendly Guide
- How to Install Nginx Proxy Manager with Docker Compose
- How to Use Caddy as a Reverse Proxy for Self-Hosted Apps
Those guides build naturally on a VPS that already has safer SSH access and a basic firewall policy.
Final thought
Security tutorials sometimes get presented like you need a 40-step checklist before you are allowed to host anything at all. In reality, a small number of careful changes make a huge difference early on.
SSH keys, a firewall, and Fail2ban will not solve every problem, but they move your VPS from “fresh internet-facing default” to “much less easy to abuse” without turning the setup into a full-time job.
