Ubuntu Server Security: UFW, fail2ban, SSH Hardening
Last updated: 23 September 2026
Every server exposed to the internet is subjected to automated attack scanning from the first minute it is up. The good news: basic hardening makes the vast majority of attacks pointless. This guide secures a new Ubuntu 22.04/24.04 server in the first hour.
1. Stay up to date
Unpatched software is the number one cause of server compromises.
sudo apt update && sudo apt upgrade -y
Enable automatic security updates:
sudo apt install unattended-upgrades -y
sudo dpkg-reconfigure --priority=low unattended-upgrades
2. Firewall: UFW
UFW (Uncomplicated Firewall) leaves only the ports you actually need open.
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow OpenSSH
sudo ufw allow 80,443/tcp
sudo ufw enable
sudo ufw status verbose
ufw enable command, you must run ufw allow OpenSSH. Otherwise your active SSH session drops and you cannot reach the server.
Never expose services like the database (3306) or Redis (6379) to the internet — access them only over localhost or a private network.
3. SSH hardening
First set up an SSH key and confirm it works. Then, in /etc/ssh/sshd_config:
PermitRootLogin no
PasswordAuthentication no
KbdInteractiveAuthentication no
X11Forwarding no
MaxAuthTries 3
sudo systemctl restart ssh
Do I need to change the SSH port?
Not required. If key login is mandatory, staying on the default port 22 is not a security problem; you can pick a different port just to reduce log noise. If you change it, update the UFW rule too.
4. fail2ban
fail2ban automatically bans IPs that repeatedly make failed login attempts.
sudo apt install fail2ban -y
sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
The [sshd] section in /etc/fail2ban/jail.local:
[sshd]
enabled = true
maxretry = 3
bantime = 1h
findtime = 10m
sudo systemctl restart fail2ban
sudo fail2ban-client status sshd
5. Shared responsibility: the application layer
- Web server: disable the server signature in Nginx/Apache, add security headers (HSTS, X-Content-Type-Options, X-Frame-Options).
- Database: separate, strong passwords;
bind-address = 127.0.0.1; delete unused default accounts. - Application: keep the framework and dependencies up to date; do not put
.envand backup files in the web root. - SSL: HTTPS on every site with Let's Encrypt.
6. Backups — an inseparable part of security
Against ransomware, deletion mistakes or disk failure, a backup is the only real protection.
- The 3-2-1 rule: 3 copies, 2 different media, 1 in a different location.
- Send backups to another server/storage — a backup on the same server is gone when the server is gone.
- Do a restore test once a month; an untested backup is not a backup.
7. Monitoring
sudo journalctl -u ssh --since "1 hour ago"— login attemptssudo lastb— failed loginssudo apt install auditd -y— system-call auditing (optional, advanced)- Use an uptime/monitoring service to check from the outside that the server is up.
Quick checklist
- ☐ System up to date + unattended-upgrades on
- ☐ UFW enabled, only 22/80/443 open
- ☐ SSH: root off, password off, key mandatory
- ☐ fail2ban running
- ☐ Database bound to localhost only
- ☐ Automatic, off-server backup + restore test
- ☐ All sites on HTTPS