Security

Block an IP address or subnet with UFW

Block single IP addresses and whole CIDR ranges with ufw deny, place deny rules above your allow rules so they actually work, find attacking IPs in your logs and unblock them later.

BeginnerLinux server5 min read

When one address hammers your login page or scans your server all day, the quickest answer is to block it at the firewall. UFW makes this a one-line job, with one catch: rule order. This guide shows how to block a single IP or a whole range so that the block really applies, how to find the addresses worth blocking and how to lift a block later.

Before you start

  • A Linux VPS running Ubuntu 22.04, Ubuntu 24.04 or Debian 12 with UFW active and SSH allowed. See Set up the UFW firewall on Ubuntu and Debian if needed.
  • A sudo user connected over SSH.
  • Your own public IP address. On your computer, search "what is my IP" or run curl -4 ifconfig.me.

Warning: Check that the address or range you block does not include your own IP. Blocking a /16 or larger range can easily catch your home or office connection and cut off SSH. If that happens, log in through the browser console in your VPS provider's control panel and delete the rule.

Why rule order matters

UFW checks rules from the top and uses the first one that matches. New rules go to the bottom of the list. So if your list starts with ALLOW 80/tcp Anywhere, a later DENY from 198.51.100.20 never applies to web traffic: the allow rule matches first.

The fix is to insert deny rules at the top with insert 1 (or prepend on newer UFW versions).

Block a single IP

Bash
sudo ufw insert 1 deny from 198.51.100.20 comment 'SSH brute force'

This drops all traffic from that address to every port. To block it from one port only:

Bash
sudo ufw insert 1 deny from 198.51.100.20 to any port 22 proto tcp

deny or reject

  • deny silently drops packets. The sender waits and times out. This is the normal choice for attackers.
  • reject sends back an error so the sender knows straight away. Use it for internal hosts you want to fail fast.
Bash
sudo ufw insert 1 reject from 198.51.100.20

Block a subnet

Use CIDR notation to block a range in one rule:

Bash
sudo ufw insert 1 deny from 198.51.100.0/24 comment 'Scanner range'

/24 covers 256 addresses (198.51.100.0 to 198.51.100.255). A /16 covers 65,536. Read CIDR notation and subnets explained before blocking anything larger than a /24.

IPv6 addresses

IPv6 deny rules belong in the IPv6 part of the list. insert 1 works for an IPv6 rule only if position 1 is an IPv6 rule, which it usually is not. Use prepend if your UFW version has it:

Bash
sudo ufw prepend deny from 2001:db8:1234::/48

Otherwise run sudo ufw status numbered, find the first (v6) rule and insert at that number. Attackers with IPv6 often hold a whole /64 or larger, so blocking a single IPv6 address rarely helps.

Find attacking IPs in your logs

Failed SSH logins. Count the addresses behind failed password attempts:

Bash
sudo journalctl -u ssh --since today | grep 'Failed password' | grep -oE 'from [0-9a-f.:]+' | sort | uniq -c | sort -rn | head

On Ubuntu 22.04 and Debian 12 the unit may be named ssh or sshd; if one returns nothing, try the other.

Firewall blocks. If UFW logging is on, see who is hitting closed ports most:

Bash
sudo journalctl -k --since today | grep 'UFW BLOCK' | grep -o 'SRC=[^ ]*' | sort | uniq -c | sort -rn | head

Web attacks. Check your Nginx access log for repeated hits on login pages:

Bash
sudo awk '{print $1}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head

Manual blocks suit a handful of persistent offenders. For the constant flow of bots, let Fail2ban ban and unban automatically; see Install and configure Fail2ban. For thousands of addresses, an ipset or nftables set is far faster than one UFW rule per IP.

Check it works

List the rules and confirm the deny sits above any allow rule for the same traffic:

Bash
sudo ufw status numbered
[ 1] Anywhere                   DENY IN     198.51.100.20              # SSH brute force
[ 2] 22/tcp                     ALLOW IN    Anywhere
[ 3] 443/tcp                    ALLOW IN    Anywhere

With logging on, blocked attempts from that address now appear as [UFW BLOCK] lines with SRC=198.51.100.20.

Unblock an IP later

Delete by number, after listing again:

Bash
sudo ufw status numbered
sudo ufw delete 1

Or delete by repeating the exact rule text:

Bash
sudo ufw delete deny from 198.51.100.20

Comments help here. A rule tagged with a reason and date is easy to review and remove months later.

Troubleshooting

  • The blocked IP still gets through: the deny rule is below an allow rule. Delete it and add it again with insert 1.
  • "ERROR: Invalid position": you tried to insert an IPv4 rule among IPv6 rules, or the reverse. Choose a number inside the right block, or use prepend.
  • You blocked yourself: use your VPS provider's browser console, run sudo ufw status numbered and delete the rule. See Locked out by your firewall? How to get back in.
  • The attacker keeps coming back from new IPs: block the range, or rely on Fail2ban and key-only SSH logins.

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.