Stockio

How to Secure an Ubuntu VPS With UFW, Fail2ban and SSH

Harden an Ubuntu VPS with tested SSH keys, carefully staged UFW rules, and a verified Fail2ban jail while preserving a reliable emergency access path.

By Ethan Clarke

Performance & SEO Specialist ·

On this page

A newly provisioned VPS needs more than a strong password. Reliable access control combines tested SSH keys, a narrow network policy, and monitoring that can slow repeated authentication abuse without locking out the administrator.

This walkthrough stages those changes on an Ubuntu server you control. Keep the provider's recovery console available throughout, and leave your original SSH session open until a second connection succeeds after every significant change.

Map your access paths before changing rules

Write down the SSH port, administrator account, public addresses, and services that must remain reachable. Include IPv6, backup connections, monitoring, and any private VPN interface. Recovery access should not depend on the firewall configuration you are about to edit.

Use the Subnet & CIDR Calculator below to inspect an IPv4 address and prefix before writing an allow rule. It shows whether the intended administrator address falls within a network and how many addresses that rule covers. A single-host prefix such as /32 is usually narrower than an office-wide subnet.

Documentation addresses in this guide are placeholders. Replace 198.51.100.25 with your actual trusted public egress address; it is not the laptop's private Wi-Fi address. If that address changes frequently, establish a controlled VPN or another documented access method instead of maintaining a fragile allowlist.

Read the Ubuntu UFW guide before enabling filtering on an unfamiliar setup. Container-published ports and cloud firewalls introduce additional paths, so host rules alone may not describe the server's effective exposure.

Create and test key-based access

Use a non-root administrator account with sudo privileges. If your provider already supplied one, verify it rather than creating duplicate accounts. Generate a passphrase-protected key on your workstation and copy only its public portion to the server:

# On your workstation
ssh-keygen -t ed25519 -a 64 -f ~/.ssh/example_vps
ssh-copy-id -i ~/.ssh/example_vps.pub admin@203.0.113.10
ssh -i ~/.ssh/example_vps -o IdentitiesOnly=yes admin@203.0.113.10

# In the new server session
sudo -v

Confirm the server's host-key fingerprint through a trusted provider console before accepting it. Do not reflexively delete a changed host-key warning; first determine whether the server was rebuilt or the connection is being intercepted. Host verification and user authentication solve different problems.

Keep private keys on trusted devices, protected by a passphrase and appropriate filesystem permissions. Do not upload them into the server's authorized_keys file. That file contains public keys, one per line. A hardware-backed key can further reduce exposure where your client and workflow support it.

Before proceeding, open a second terminal and repeat the key login. Verify sudo there too. Successful key login must be demonstrated independently of an old session that may still be using password authentication or an SSH connection-sharing socket.

Stage UFW without cutting off administration

Inspect existing rules before adding anything. The following example assumes SSH is actually listening on TCP port 22 and that the machine serves public HTTP and HTTPS. Adapt the source address and port before execution:

sudo apt update
sudo apt install ufw fail2ban
sudo ufw status verbose
sudo ss -lntp
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow from 198.51.100.25/32 to any port 22 proto tcp
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable
sudo ufw status numbered

Do not add web ports unless the server needs them. For a non-web host, omit those rules. Default deny incoming is a useful starting point, but existing permissive rules still apply; review and remove obsolete entries deliberately. Never reset a remote firewall casually.

Mirror the required access in the provider's firewall if one is enabled. Check /etc/default/ufw for IPv6 handling and audit IPv6 listeners separately. The IPv4 calculator cannot validate an IPv6 allowlist, and disabling IPv6 filtering does not safely close IPv6 services.

Test a new SSH connection immediately while the original session stays open. Verify expected public services from another network and check that database ports are not public. External verification catches differences between the rules you intended and the path packets actually take.

Harden SSH only after the key test passes

On Ubuntu, use a local SSH configuration snippet if the packaged configuration includes that directory. Check existing snippets and provider-generated files first: OpenSSH generally uses the first obtained value for a setting, and Match blocks can change the effective result.

sudo tee /etc/ssh/sshd_config.d/00-local-hardening.conf >/dev/null <<'EOF'
PubkeyAuthentication yes
PasswordAuthentication no
KbdInteractiveAuthentication no
PermitRootLogin no
EOF
sudo /usr/sbin/sshd -t
sudo /usr/sbin/sshd -T | grep -E 'pubkeyauthentication|passwordauthentication|kbdinteractiveauthentication|permitrootlogin'
sudo systemctl reload ssh

Only reload if syntax validation succeeds. For configurations containing Match, inspect effective settings with sshd -T -C and connection-specific values as described in the OpenSSH manual. Disabling keyboard-interactive authentication can disable PAM-based second-factor workflows; preserve the appropriate mechanism if your deployment intentionally uses one.

Try another fresh key connection after reloading. Confirm password login is unavailable without repeatedly hammering production authentication. Root login restriction assumes the tested non-root account has working sudo access. Keep emergency recovery through the provider console documented and protected with strong account authentication.

Configure Fail2ban and verify the actual jail

Fail2ban reacts to logged failures; it does not patch vulnerable services or replace firewall policy. Use the project's official documentation repository for configuration behavior and distribution-specific details. Start with one SSH jail rather than enabling many untested filters.

Create /etc/fail2ban/jail.d/sshd.local with an [sshd] section containing enabled = true, backend = systemd, port = 22, maxretry = 5, findtime = 10m, and bantime = 1h, each on its own line. Set the actual SSH port if different. This assumes the distribution's SSH journal integration is available.

Run sudo fail2ban-client -t before restarting the service, then use sudo systemctl restart fail2ban and sudo fail2ban-client status sshd. Inspect sudo journalctl -u fail2ban if the jail is missing or reports errors. An active service does not necessarily mean the intended jail is reading authentication events.

Test banning only with a separate source you control and a recovery route ready. Know the unban command: sudo fail2ban-client set sshd unbanip 198.51.100.25. Use the CIDR calculator again before adding trusted ranges to any ignore list; broad exemptions weaken protection.

Maintain updates, backups, and access reviews afterward. The offsite backup guide complements hardening, while the Web Hosting & Servers category covers related operational tasks.

Schedule periodic access reviews to remove unused public keys and confirm that remaining administrators still need their permissions.

Key takeaways

  • Preserve console recovery and a working session throughout firewall and SSH changes.
  • Test keys and sudo before disabling passwords or root access.
  • Validate IPv4, IPv6, cloud firewalls, and container exposure separately.
  • Check effective SSH settings and confirm Fail2ban is reading real events.
  • Keep updates and recovery testing part of normal server maintenance.
Featured sponsor

Reach designers & developers at work

Put your product next to the tools people use every day. One sponsor per placement, no tracking pixels.

Become a sponsor

Keep reading

Related articles

More in Web Hosting & Servers
Web Hosting & Servers

10 Best VPS Hosting Providers

Explore ten VPS providers for growing websites and applications, with notes on managed support, cloud flexibility, and the extra maintenance that comes with virtual servers.

Includes: Subnet calculatorRavi DesaiRavi Desai
Web Hosting & Servers

Host Multiple Node.js Apps on One Server With Docker

Deploy two Node.js apps with Docker Compose, isolated networks, and an NGINX proxy, then plan HTTPS, resource limits, backups, and safe production updates.

Includes: Subnet calculatorEthan ClarkeEthan Clarke
DevOps & Deployment

10 Best Domain Registrars for Developers

Find a domain registrar that fits a developer's workflow, from DNS controls and email forwarding to privacy options, plus practical checks for renewals, transfers, and deployment.

Includes: Subnet calculatorRavi DesaiRavi Desai
VPN & Online Privacy

10 Best Free Online Privacy Check Tools

Use ten reputable free privacy checkers to review browser tracking, account exposure, connection settings, and data breaches, with practical notes on what each result can and cannot tell you.

Includes: Subnet calculatorRavi DesaiRavi Desai
Smart Home & Gadgets

How to Put Smart Devices on a Separate Wi-Fi Network

Move smart devices onto a guest or isolated network without breaking everyday controls. Learn what isolation means, how to test it, and when a VLAN makes sense.

Includes: Subnet calculatorGrace ChenGrace Chen
VPN & Online Privacy

Share a VPN Connection to Xbox or PlayStation via Ethernet

Share a supported Windows VPN connection with a console over Ethernet, avoid bridge mistakes, verify routing, and test what happens when the tunnel drops.

Includes: Subnet calculatorRavi DesaiRavi Desai