Security

Rate-limit SSH and other ports with ufw limit

Use ufw limit to slow down SSH brute-force attempts. Learn how the 6-connections-in-30-seconds rule works, apply it to a custom SSH port, pair it with Fail2ban and test it.

BeginnerLinux server5 min read

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 sudo user connected over SSH.
  • The port SSH listens on. Check it with:
Bash
  sudo ss -tlpn | grep sshd

Warning: 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:

Bash
sudo ufw limit 22/tcp comment 'SSH rate limit'

If SSH runs on a custom port such as 2222, limit that port instead:

Bash
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:

Bash
sudo ufw status numbered
[ 1] 22/tcp                     LIMIT IN    Anywhere                   # SSH rate limit
[ 2] 22/tcp (v6)                LIMIT IN    Anywhere (v6)              # SSH rate limit

If 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:

Bash
sudo ufw delete allow OpenSSH

Tip: 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:

Bash
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:

Bash
for i in $(seq 1 8); do nc -vz -w 3 203.0.113.10 22; done

The 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:

Bash
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 ALLOW rule for the same port sits above it. List with sudo ufw status numbered and 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

Was this guide helpful?

Still stuck?

Ask MdmHost AI for a quick answer, or open a ticket and our team will take a look. We are here 24/7.