diff --git a/roles/fail2ban/files/fail2ban.xml b/roles/fail2ban/files/fail2ban.xml
new file mode 100644
index 0000000000000000000000000000000000000000..4dbbdb6833b0f0534db34ff4cde5e6539699cecd
--- /dev/null
+++ b/roles/fail2ban/files/fail2ban.xml
@@ -0,0 +1,3 @@
+<?xml version="1.0" encoding="utf-8"?>
+<ipset type="hash:net">
+</ipset>
diff --git a/roles/fail2ban/tasks/main.yml b/roles/fail2ban/tasks/main.yml
index dc06420299fb31c7fbcede98ffa578118d028fa8..856fa42e602db68e3e1e133491d4adc05bd1c182 100644
--- a/roles/fail2ban/tasks/main.yml
+++ b/roles/fail2ban/tasks/main.yml
@@ -36,8 +36,8 @@
 
 - name: Install firewallcmd-allports.local
   template:
-    src: "firewallcmd-allports.local.j2"
-    dest: "/etc/fail2ban/action.d/firewallcmd-allports.local"
+    src: "firewallcmd-ipset-allports.conf.j2"
+    dest: "/etc/fail2ban/action.d/firewallcmd-ipset-allports.conf"
     owner: "root"
     group: "root"
     mode: '0644'
@@ -88,6 +88,17 @@
   notify:
     - Reload fail2ban jails
 
+- name: Install fail2ban ipset for firewalld
+  copy: src=fail2ban.xml dest=/etc/firewalld/ipsets/ owner=root group=root mode=0644
+  register: result
+
+- name: Restart firewalld
+  systemd: name=firewalld state=restarted
+  when: result.changed
+
+- name: Add fail2ban ipset to the firewalld drop zone
+  ansible.posix.firewalld: source=ipset:fail2ban zone=drop permanent=true immediate=true state=enabled
+
 - name: Start and enable service
   systemd:
     name: "fail2ban.service"
diff --git a/roles/fail2ban/templates/firewallcmd-allports.local.j2 b/roles/fail2ban/templates/firewallcmd-allports.local.j2
deleted file mode 100644
index 26352a00adee5c10fe2291b0e23ba921d8e2c42a..0000000000000000000000000000000000000000
--- a/roles/fail2ban/templates/firewallcmd-allports.local.j2
+++ /dev/null
@@ -1,8 +0,0 @@
-#
-# {{ansible_managed}}
-#
-
-# creates the requisite chains in firewalld when fail2ban starts instead
-# of creating them on first use (ie, when first IP is banned)
-[Definition]
-actionstart_on_demand = false
diff --git a/roles/fail2ban/templates/firewallcmd-ipset-allports.conf.j2 b/roles/fail2ban/templates/firewallcmd-ipset-allports.conf.j2
new file mode 100644
index 0000000000000000000000000000000000000000..9cbbd23b9e75ebcefb3f08cff673af296d7226d3
--- /dev/null
+++ b/roles/fail2ban/templates/firewallcmd-ipset-allports.conf.j2
@@ -0,0 +1,8 @@
+#
+# {{ansible_managed}}
+#
+
+[Definition]
+
+actionban = firewall-cmd --ipset=fail2ban --add-entry=<ip>
+actionunban = firewall-cmd --ipset=fail2ban --remove-entry=<ip>
diff --git a/roles/fail2ban/templates/jail.local.j2 b/roles/fail2ban/templates/jail.local.j2
index f8294d44617f63ac2026c44422ebff62269ab690..5ba5ad8989525cce0c95093d2e1e54e6f7e1413b 100644
--- a/roles/fail2ban/templates/jail.local.j2
+++ b/roles/fail2ban/templates/jail.local.j2
@@ -27,7 +27,7 @@ sender = fail2ban@{{ansible_fqdn}}
 #   fail2ban-client set unban <IP>
 #   fail2ban-client set unban --all
 # see `fail2ban-client help` for full list of runtime commands
-banaction = firewallcmd-allports
+banaction = firewallcmd-ipset-allports
 
 # "ignoreip" can be a list of IP addresses, CIDR masks or DNS hosts. Fail2ban
 # will not ban a host which matches an address in this list. Several addresses