To secure a VPS server you need a clear sequence: lock down SSH first, then enable a firewall, then automate updates. A freshly provisioned virtual private server is exposed to the internet within minutes — brute-force bots and vulnerability scanners hit new IPs constantly. This guide walks you through securing a VPS server step-by-step on Ubuntu or Debian, with real config paths and commands you can run today. By the end you will have a production-ready baseline: key-only SSH, UFW firewall rules, and automatic security patches.

Why Securing Your VPS Matters From Day One

An unhardened VPS is a high-value target. Default SSH on port 22 with password authentication means automated scripts can try thousands of combinations per hour. Once one credential works, attackers often install miners, backdoors, or use your server for relay attacks. VPS security is not optional — it is the first thing you do before installing applications or opening extra ports.

In my experience, the biggest mistake is disabling password auth before confirming key-based login works. If you lock yourself out, you will need your provider’s recovery console. So we will set up SSH keys first, test them, then turn off passwords. The same principle applies to the firewall: allow SSH (and only SSH) before enabling UFW, or you risk losing access.

Initial Access and System Updates

Connect to your VPS with the credentials from your provider (Hetzner, DigitalOcean, Linode, etc.). On Ubuntu and Debian, update the package index and upgrade installed packages. This closes known CVEs in the base system before we harden further.

sudo apt update
sudo apt upgrade -y

Install the tools we will use next: UFW for the firewall and unattended-upgrades for automatic security updates. Optionally install Fail2Ban now (we will configure it later) so it is ready:

sudo apt install -y ufw unattended-upgrades
# Optional, for brute-force protection:
# sudo apt install -y fail2ban

SSH Key Authentication and Hardening

Password-based SSH is the main entry point for automated attacks. Switch to key-based authentication and then disable passwords. Do this while you still have a working session.

Generate and Copy Your SSH Key (from your laptop)

On your local machine, generate an ed25519 key if you do not have one yet. Ed25519 is fast and widely supported:

ssh-keygen -t ed25519 -C "[email protected]" -f ~/.ssh/id_ed25519_vps -N ""

Copy the public key to the server. Replace root and 203.0.113.50 with your server user and IP:

ssh-copy-id -i ~/.ssh/id_ed25519_vps.pub [email protected]

Open a second terminal and log in with the key to confirm it works. Only after a successful key login should you change the server’s SSH config.

Edit SSH Server Config

The SSH daemon config on Ubuntu/Debian lives at /etc/ssh/sshd_config. Use sudo nano /etc/ssh/sshd_config or your preferred editor. Set or uncomment these lines:

# /etc/ssh/sshd_config — ensure these are set:
PermitRootLogin prohibit-password
PubkeyAuthentication yes
PasswordAuthentication no
MaxAuthTries 3
ClientAliveInterval 300
ClientAliveCountMax 2
X11Forwarding no
AllowTcpForwarding yes

Should I disable root login completely or use prohibit-password?

PermitRootLogin prohibit-password allows root only via key — this is the safer first step because you keep root access as a fallback while you set up a non-root sudo user. Once your sudo user is confirmed working, switch to PermitRootLogin no for a full audit trail where every action maps to a named user. MaxAuthTries 3 limits brute-force attempts per connection. Apply changes by restarting the SSH service:

sudo systemctl restart sshd

On some systems the service is named ssh instead of sshd. Check with systemctl status ssh. Keep your current session open until you have verified a new login in another terminal; if something is wrong, you can still fix it from the open session.

Firewall Configuration with UFW

UFW (Uncomplicated Firewall) is the standard way to manage iptables on Ubuntu and Debian. Default-deny incoming traffic and explicitly allow only what you need. Always allow SSH before enabling UFW, or you will lock yourself out.

sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow 22/tcp
# If you will serve web traffic:
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable

What ports should I open in UFW for a web server?

For a standard web server, you need exactly three ports: 22 (SSH), 80 (HTTP), and 443 (HTTPS). Do not open additional ports until you have a service actively listening on them. Check status with sudo ufw status verbose. If you change SSH to a non-standard port later, add ufw allow 2222/tcp (or your port) and remove ufw allow 22/tcp only after you have confirmed the new port works.

Automatic Security Updates

Manual updates get forgotten. Unattended-upgrades can install security updates automatically. On Ubuntu, enable it with:

sudo dpkg-reconfigure -plow unattended-upgrades

Select “Yes” when asked. Configuration lives in /etc/apt/apt.conf.d/50unattended-upgrades. The default “security” origin is usually enough. To avoid unexpected reboots, ensure Unattended-Upgrade::Automatic-Reboot is set to false unless you want the server to reboot when a kernel update requires it. You can add a reboot window if you enable it:

# In /etc/apt/apt.conf.d/50unattended-upgrades (optional):
Unattended-Upgrade::Automatic-Reboot "true";
Unattended-Upgrade::Automatic-Reboot-Time "04:00";

Optional: Fail2Ban for Brute-Force Protection

Do I still need Fail2Ban if I use SSH key authentication?

Strictly speaking, key-only SSH is already immune to password brute-force. But Fail2Ban still adds value: it bans IPs that repeatedly fail authentication, reducing log noise, wasted CPU cycles, and the risk of undiscovered SSH vulnerabilities being exploited. On servers with any password-based service (web panels, mail), Fail2Ban becomes essential.

Fail2Ban scans log files (e.g. /var/log/auth.log) and temporarily bans IPs that exceed a failure threshold. For SSH, a typical jail looks like this. Create or edit /etc/fail2ban/jail.local:

[sshd]
enabled = true
port = ssh
filter = sshd
logpath = /var/log/auth.log
maxretry = 3
bantime = 3600
findtime = 600

This bans an IP for one hour (3600 seconds) after three failures within 10 minutes. Restart Fail2Ban:

sudo systemctl restart fail2ban
sudo fail2ban-client status sshd

Moving Beyond Basic VPS Hardening

With SSH keys, UFW, and unattended-upgrades in place, your VPS has a solid security baseline. Next steps depend on your stack: add a reverse proxy and SSL (e.g. Docker Compose with Nginx), set up monitoring, or follow a broader Linux server hardening checklist. For application-level security, keep services listening only on localhost where possible and put Nginx or another proxy in front. Never expose database or admin ports directly to the internet.