How to delete all ufw rules for a certain port?

I am using ansible to configure ufw on my DB servers to only let accept connections from certain servers connection to a specific port (lets say 1234).

When a server that used to have access is taken out of the pool, it might be forgotten to remove the access rule for that server.

My solution: When setting up the rules, I want to delete all rules for port 1234, and then recreate them with the servers from the current pool.

Unfortunately ufw delete requires to precisely specify the rule to be deleted (port,protocol, scr IP,...).

I tried a solution like ufw delete $(ufw status numbered | grep 1234 | <get all the numbers of the rules> ), but it got really ugly, really fast.

Is there a better way to delete all rules for a certain port?


There are two problems that need to be solved here:

  1. generate a list of ufw rule numbers which match a desired string.
  2. have the shell expand this list and tack it on the end of a sequence of 'ufw delete [rule number]' commands.

I think I have a solution for problem #1 via this one liner in bash:

ufw status numbered |(grep '80/tcp'|awk -F"[][]" '{print $2}')

The example above matches any firewall rule for the string '80/tcp' and prints just the rule number with the brackets stripped.

I have not solved problem #2 yet because as best I can tell, the 'ufw delete' command does not have a switch that suppresses the '(y|n)' confirmation prompt, thus foiling automation.

You can run the command below however and manually hammer out each rule deletion by hitting the 'y' key to confirm and then up arrow => enter to rinse and repeat

ufw delete $(ufw status numbered |(grep '80/tcp'|awk -F"[][]" '{print $2}'))

I know this is very old question but google brought me here and the answers so far were helpful, so I wanted to share my full solution. The answer from @Seth got me most of the way there.

My goal is to remove all UFW rules allowing connections to the local MySQL server on port 3306. Here's what I used:

for NUM in $(ufw status numbered | grep 3306 | awk -F"[][]" '{print $2}' | tr --delete [:blank:] | sort -rn); do
    yes | ufw delete $NUM
done

The key to automating this is to delete rules in reverse order. When you delete from the end, the numbers above don't change.

When you run ufw status numbered you'll get output like this:

     To                         Action      From
     --                         ------      ----
[ 1] 22                         ALLOW IN    10.181.225.123
[ 2] 3306/tcp                   ALLOW IN    10.181.225.123
[ 3] 3306/tcp                   ALLOW IN    10.181.226.45
[ 4] 3306/tcp                   ALLOW IN    10.181.226.77
[ 5] 3306/tcp                   ALLOW IN    10.181.225.196
[ 6] 3306/tcp                   ALLOW IN    10.181.226.3
[ 7] Anywhere                   ALLOW IN    10.181.226.45
[ 8] 3306/tcp                   ALLOW IN    10.181.224.55
[ 9] 3306/tcp                   ALLOW IN    10.181.224.80
[10] 3306/tcp                   ALLOW IN    10.208.6.136
[11] 3306/tcp                   ALLOW IN    10.178.128.13

A few things to know:

  • The output from awk -F"[][]" '{print $2}' will include a leading space for numbers below 10, tr --delete [:blank:] will delete it
  • Once the leading spaces are deleted, sort -rn will sort the numbers in reverse numerical order.
  • I'm piping yes to ufw instead of using --force because I've got a very old ufw. If you've got a modern version, you can use --force.

If you need to wipe-out all your rules (not just specific ports):

ufw --force reset

(--force if you don't want to be prompted for confirmation)


Most of the solutions here will delete the wrong rules because of UFW renumbering rules after deletion.

To workaround the new numbering after each deletion, we need to rerun the command and pick the first number then delete that rule and loop like this:

while true; do n=$(ufw status numbered | grep DENY | head -n 1 | awk -F"[][]" '{print $2}');[ "$n" != "" ] || break; yes | ufw delete $n; done;