Set Up SSH, UFW, and Fail2Ban on a Fresh VPS

Start with the right session, not the firewall
This guide shows you how to set up SSH, UFW, and Fail2Ban on a fresh VPS without locking yourself out. It is written for a new Hostperl server, whether you run a small business site, a staging box, or a client migration on a Hostperl VPS.
Use these placeholders throughout the tutorial: SERVER_IP is your VPS address, for example 203.0.113.10. DOMAIN_NAME is the hostname you want, for example server1.example.com. ADMIN_USER is the new sudo user you will create, for example perladmin.
On your local computer, open your first SSH session with root access:
ssh root@SERVER_IPIf your provider gives you a default non-root account, use that instead. Keep this original terminal open until you finish testing the new login later.
On the VPS as root, check the operating system before you install anything:
cat /etc/os-releaseYou should see either Ubuntu/Debian or AlmaLinux/Rocky Linux details. The commands below are split by family so you do not mix apt and dnf, or UFW and firewalld rules.
Create a non-root admin user safely
A new admin account gives you a recovery path if SSH settings change. Hostperl support teams see fewer lockouts when customers test this step before touching root login settings, which is why it belongs near the top of the workflow. If you want a broader walkthrough of that sequence, Hostperl already documents it in Create a Non-Root Admin User on Ubuntu and AlmaLinux.
Ubuntu and Debian
On the VPS as root, create the user, set a password, and add it to sudo:
adduser ADMIN_USER
usermod -aG sudo ADMIN_USER
id ADMIN_USERReplace ADMIN_USER with your chosen account name. The last command should show the sudo group in the user’s supplementary groups.
Now create the SSH directory and copy your key. Replace the key contents with your public key from ~/.ssh/id_ed25519.pub on your local machine:
install -d -m 700 -o ADMIN_USER -g ADMIN_USER /home/ADMIN_USER/.ssh
cat > /home/ADMIN_USER/.ssh/authorized_keys <<'EOF'
PASTE_YOUR_PUBLIC_KEY_HERE
EOF
chown ADMIN_USER:ADMIN_USER /home/ADMIN_USER/.ssh/authorized_keys
chmod 600 /home/ADMIN_USER/.ssh/authorized_keysCheck the permissions right away. SSH will reject loose ownership or mode settings:
ls -ld /home/ADMIN_USER /home/ADMIN_USER/.ssh /home/ADMIN_USER/.ssh/authorized_keysOn the VPS as root, open a second terminal and test the new user before changing SSH policy:
ssh ADMIN_USER@SERVER_IP
sudo -vIf sudo asks for your password and then returns without an error, the account is ready.
AlmaLinux and Rocky Linux
On the VPS as root, create the account, set its password, and add it to wheel:
useradd -m ADMIN_USER
passwd ADMIN_USER
usermod -aG wheel ADMIN_USER
id ADMIN_USERThen install the SSH key with the correct ownership and permissions:
install -d -m 700 -o ADMIN_USER -g ADMIN_USER /home/ADMIN_USER/.ssh
cat > /home/ADMIN_USER/.ssh/authorized_keys <<'EOF'
PASTE_YOUR_PUBLIC_KEY_HERE
EOF
chown ADMIN_USER:ADMIN_USER /home/ADMIN_USER/.ssh/authorized_keys
chmod 600 /home/ADMIN_USER/.ssh/authorized_keysTest the account from a second terminal:
ssh ADMIN_USER@SERVER_IP
sudo -vWait until this works before you tighten root access.
Update packages, time sync, and hostname
A fresh VPS should be patched before it goes live. Time sync matters too. Expired TLS certificates, broken cron jobs, and confusing log timestamps often start with a drifting clock.
Ubuntu and Debian
sudo apt update
sudo apt -y upgrade
sudo apt -y install chrony
sudo systemctl enable --now chrony
sudo timedatectl set-timezone Pacific/Auckland
sudo hostnamectl set-hostname server1.example.com
hostnamectlExpected result: package indexes refresh, updates apply, Chrony starts, and your hostname changes immediately.
AlmaLinux and Rocky Linux
sudo dnf -y update
sudo dnf -y install chrony
sudo systemctl enable --now chronyd
sudo timedatectl set-timezone Pacific/Auckland
sudo hostnamectl set-hostname server1.example.com
hostnamectlHostperl customers in APAC often pair this with a quick reboot window after migrations so monitoring and mail logs line up cleanly.
Set up SSH hardening without cutting off access
Now that the new admin login works, you can harden SSH. Do not disable root or password login until you confirm the new account from a second terminal.
If you are planning a larger migration or control-panel move, Hostperl’s notes on cPanel vs Plesk for Hosting Migrations in 2026 help teams decide where this hardening belongs in the cutover plan.
Ubuntu and Debian
On the VPS as root, edit the SSH daemon config:
sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak
sudo nano /etc/ssh/sshd_configAdd or adjust these lines:
PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes
KbdInteractiveAuthentication no
AllowUsers ADMIN_USERSave and exit, then test syntax before reloading:
sudo sshd -t
sudo systemctl reload sshOn Ubuntu and Debian, the service name is usually ssh. The syntax test must return no output.
AlmaLinux and Rocky Linux
On the VPS as root, edit the SSH config:
sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak
sudo nano /etc/ssh/sshd_configUse the same settings:
PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes
KbdInteractiveAuthentication no
AllowUsers ADMIN_USERThen verify and reload:
sudo sshd -t
sudo systemctl reload sshdOn AlmaLinux and Rocky Linux, the service name is usually sshd. If you use SELinux, these SSH settings are normally allowed without extra policy changes.
From your local computer, open a fresh SSH session in a second terminal:
ssh ADMIN_USER@SERVER_IPLeave the original root session open until this succeeds.
Open the firewall before you close anything else
Your firewall should allow SSH before you enable stricter SSH settings. That sequence prevents the classic lockout: a working SSH daemon with no reachable port.
Ubuntu and Debian with UFW
On the VPS as the non-root sudo user, allow SSH, turn on UFW, and confirm the rules:
sudo apt -y install ufw
sudo ufw allow OpenSSH
sudo ufw enable
sudo ufw status verboseExpected result: UFW shows OpenSSH allowed and the firewall active.
AlmaLinux and Rocky Linux with firewalld
On the VPS as the non-root sudo user, enable SSH in firewalld and reload the runtime rules:
sudo dnf -y install firewalld
sudo systemctl enable --now firewalld
sudo firewall-cmd --permanent --add-service=ssh
sudo firewall-cmd --reload
sudo firewall-cmd --list-allExpected result: the ssh service appears in the active zone.
Install and configure Fail2Ban
Fail2Ban watches authentication logs and bans repeat offenders. It is a practical layer, not a replacement for key-based SSH. For customers who also run WordPress or panel logins, this can reduce noisy brute-force attempts on a small VPS.
Ubuntu and Debian
sudo apt -y install fail2ban
sudo systemctl enable --now fail2ban
sudo nano /etc/fail2ban/jail.localPaste this configuration:
[sshd]
enabled = true
mode = aggressive
maxretry = 3
findtime = 10m
bantime = 1hSave and reload the service after a quick config check:
sudo fail2ban-client -t
sudo systemctl restart fail2ban
sudo fail2ban-client status sshdYou should see the sshd jail active.
AlmaLinux and Rocky Linux
sudo dnf -y install fail2ban
sudo systemctl enable --now fail2ban
sudo nano /etc/fail2ban/jail.localUse the same jail content:
[sshd]
enabled = true
mode = aggressive
maxretry = 3
findtime = 10m
bantime = 1hThen validate and restart:
sudo fail2ban-client -t
sudo systemctl restart fail2ban
sudo fail2ban-client status sshdIf the sshd jail does not appear, check the backend and logs first.
Check logs, ports, and service health
Verification matters because customers often discover issues only after a reboot or a maintenance window. These checks confirm that SSH is listening, the firewall is active, and Fail2Ban is running.
On the VPS as the non-root sudo user, run:
sudo ss -tulpn | grep -E ':(22)\s'
sudo systemctl status ssh 2>/dev/null || sudo systemctl status sshd
sudo systemctl status fail2ban
sudo journalctl -u fail2ban -n 50 --no-pagerOn Ubuntu and Debian, the SSH service should be ssh. On AlmaLinux and Rocky Linux, it should be sshd. The port check should show the SSH daemon listening on 0.0.0.0:22 or [::]:22.
From your local computer, test a real login and a sudo action:
ssh ADMIN_USER@SERVER_IP
sudo whoamiThe command should print root. That confirms the new account, keys, and sudo path are all working.
Reboot test and rollback points
Reboot once before you call the job done. A restart exposes missing services, bad enable-at-boot settings, and SSH configs that only looked fine in the current session.
sudo rebootAfter the server comes back, reconnect from your local computer and check the same services again. If you cannot reach the server, use your Hostperl console access or rescue path, then restore the backups you made of /etc/ssh/sshd_config and /etc/fail2ban/jail.local.
Troubleshooting the likely failures
SSH refuses the key: check ownership and modes.
ls -ld /home/ADMIN_USER /home/ADMIN_USER/.ssh /home/ADMIN_USER/.ssh/authorized_keys
sudo journalctl -u ssh -n 50 --no-pager 2>/dev/null || sudo journalctl -u sshd -n 50 --no-pagerFix with:
sudo chown -R ADMIN_USER:ADMIN_USER /home/ADMIN_USER/.ssh
sudo chmod 700 /home/ADMIN_USER/.ssh
sudo chmod 600 /home/ADMIN_USER/.ssh/authorized_keysFirewall is active but SSH still fails: confirm the service rule exists and the daemon listens.
sudo ufw status verbose
sudo firewall-cmd --list-all
sudo ss -tulpn | grep ':22'Fail2Ban shows no jail: test the configuration again.
sudo fail2ban-client -t
sudo tail -n 50 /var/log/fail2ban.log 2>/dev/null || sudo journalctl -u fail2ban -n 50 --no-pagerFor a new VPS that needs to stay reliable during launches, this baseline is a better starting point than a rushed hardening job. If you are still choosing infrastructure, compare options on Hostperl VPS and keep your migration window short.
Hostperl VPS plans give you room to set up SSH hardening, UFW or firewalld, and Fail2Ban before you move live traffic. If you want help with the migration window, our support team works with real server setups, not generic scripts.
For a clean launch path, start with Hostperl VPS and keep your SSH policy, firewall rules, and recovery access documented from day one.
FAQ
Should I disable root SSH login immediately?
No. First confirm the new sudo user works in a second terminal, then remove root access.
Do I need Fail2Ban if I already use SSH keys?
Yes, it still helps reduce repeated connection noise and protects any other exposed login services you run.
Can I use UFW on AlmaLinux or Rocky Linux?
You can install it, but firewalld is the native choice on those systems and usually fits cleaner with the rest of the stack.
What if I lose SSH access after hardening?
Use your provider console or rescue access, restore the SSH backup file, and recheck sshd -t before reloading.
