Every public SSH server receives a steady stream of password-guessing bots. ufw limit is a one-line defence: it lets normal logins through but blocks an address that opens connections too quickly. This guide explains what the rule actually does, how to apply it to the right port, and where it fits alongside Fail2ban.
Before you start
- A Linux VPS running Ubuntu 22.04, Ubuntu 24.04 or Debian 12 with UFW installed. See Set up the UFW firewall on Ubuntu and Debian if you have not set it up.
- A
sudouser connected over SSH. - The port SSH listens on. Check it with:
sudo ss -tlpn | grep sshdWarning: A limit rule replaces your SSH allow rule, so get the port right. If you limit the wrong port and then delete the real SSH rule, the next login fails. Keep the browser console in your VPS provider's control panel ready as a way back in.
How ufw limit works
A limit rule is an allow rule with a counter. For each source IP address, UFW tracks new incoming connections to that port. If one address tries to start 6 or more connections within 30 seconds, UFW refuses further new connections from it until the rate drops.
Key points:
- It counts new connections, not packets or failed passwords. An open SSH session is not affected.
- It counts per source IP. One noisy bot does not affect other users.
- The block is temporary and clears itself. Nothing is stored or banned for long.
- The threshold is fixed in UFW. If you need a different rate, use Fail2ban or nftables instead.
This makes limit a good fit for SSH, where a person opens a few connections at most. It is a poor fit for web ports, where one browser may open many connections at once.
Apply the limit to SSH
For SSH on the default port:
sudo ufw limit 22/tcp comment 'SSH rate limit'If SSH runs on a custom port such as 2222, limit that port instead:
sudo ufw limit 2222/tcp comment 'SSH rate limit'If an allow rule for the same port and protocol already exists, UFW updates it to a limit rule and prints Rule updated. If your existing rule was written differently (for example allow OpenSSH or allow 22 without a protocol), it is a separate rule. Because UFW uses the first matching rule, an allow rule above the limit rule means the limit never runs.
Check the list:
sudo ufw status numbered[ 1] 22/tcp LIMIT IN Anywhere # SSH rate limit
[ 2] 22/tcp (v6) LIMIT IN Anywhere (v6) # SSH rate limitIf an old ALLOW rule for SSH is still listed, open a new SSH session to confirm the limit rule lets you in, then remove the old one:
sudo ufw delete allow OpenSSHTip: Tools that open many SSH connections in a row, such as Ansible, rsync scripts or some SFTP clients, can trip the limit. Turn on SSH connection sharing (ControlMaster in ~/.ssh/config) on your computer, or allow your own fixed IP with a plain allow rule placed above the limit rule.
To put a trusted IP above the limit rule:
sudo ufw insert 1 allow from 203.0.113.10 to any port 22 proto tcp comment 'Admin IP, no limit'Pair it with Fail2ban
ufw limit and Fail2ban do different jobs, and they work well together:
- ufw limit reacts to connection speed. It stops fast floods straight away but ignores slow attackers who try one password every few minutes.
- Fail2ban reads the SSH log and reacts to failed logins. It catches slow attackers and can ban them for hours or days.
Use both on a public SSH port. If Fail2ban is not installed yet, follow Install and configure Fail2ban. If you use a custom SSH port, set the same port in the Fail2ban sshd jail so its bans block the right port.
Better still, use SSH keys and turn off password logins. Rate limiting slows guessing; key-only logins make guessing pointless.
Check it works
Test from another machine, never from your only admin connection. This loop opens eight quick connections to port 22:
for i in $(seq 1 8); do nc -vz -w 3 203.0.113.10 22; doneThe first few attempts succeed. After that, attempts time out or are refused. Wait 30 seconds and a new attempt works again.
On the server, look for the limit log entries:
sudo journalctl -k | grep 'UFW LIMIT BLOCK'Each line shows the blocked SRC= address and DPT= port. On Ubuntu the same lines are usually also in /var/log/ufw.log. Logging must be on for these lines to appear; check with sudo ufw status verbose. Read and tune UFW firewall logs explains each field.
Troubleshooting
- The limit never triggers: an
ALLOWrule for the same port sits above it. List withsudo ufw status numberedand remove or move the allow rule. - You get blocked during normal work: your tools open too many connections. Use SSH connection sharing, or allow your fixed IP above the limit rule.
- Limit set on the wrong port: add
sudo ufw limit <real-port>/tcp, test a new login, then delete the wrong rule. - Locked out completely: log in through your VPS provider's browser console and run
sudo ufw allow 22/tcp. See Locked out by your firewall? How to get back in.
Next steps
- Move SSH off port 22 before you rate-limit it: Change the SSH port safely.
- Tune bans for slow attackers: Configure Fail2ban jails: bantime, findtime and maxretry.
- Block persistent offenders outright: Block an IP address or subnet with UFW.
