diff --git a/inventory.sample b/inventory.sample
index 1190cb679ed78e7156770cf3f0839ca921bd61bc..5d6803e23d4e4eb2450046e5f1473e4685c281d5 100644
--- a/inventory.sample
+++ b/inventory.sample
@@ -17,6 +17,7 @@ localhost
 
 [server:vars]
 timezone="UTC"
+gateway="<GATEWAY_IP>"
 
 [workstation:vars]
 timezone="Europe/Paris"
diff --git a/tasks/firewall.yml b/tasks/firewall.yml
new file mode 100644
index 0000000000000000000000000000000000000000..3493d3734a186281155badf1445f62e199d69c51
--- /dev/null
+++ b/tasks/firewall.yml
@@ -0,0 +1,65 @@
+---
+- hosts: "{{ host_list }}"
+  remote_user: root
+
+  tasks:
+    - name: FIREWALL | install packages
+      ansible.builtin.apt:
+        cache_valid_time: 3600
+        force_apt_get: yes
+        pkg:
+            - fail2ban
+            - ufw
+        state: present
+        update_cache: true
+
+    - name: UFW | reset before setting
+      community.general.ufw:
+        state: reset
+
+    - name: UFW | deny everything IN
+      community.general.ufw:
+        direction: incoming
+        policy: deny
+
+    - name: UFW | allow everything OUT
+      community.general.ufw:
+        direction: outgoing
+        policy: allow
+
+    - name: UFW | limit tcp port 22 IN
+      community.general.ufw:
+        direction: in
+        log: yes
+        port: '22'
+        proto: tcp
+        rule: limit
+
+    - name: UFW | allow tcp port 80 IN
+      when: inventory_hostname in groups.web
+      community.general.ufw:
+        direction: in
+        rule: allow
+        port: '80'
+        proto: tcp
+
+    - name: UFW | enable & set logging
+      community.general.ufw:
+        logging: full
+        state: enabled
+
+    - name: FAIL2BAN | ensure deamon is running
+      service:
+        name: fail2ban
+        state: started
+        enabled: true
+
+    - name: FAIL2BAN | set local config
+      template:
+        src: templates/jail.local.j2
+        dest: /etc/fail2ban/jail.local
+
+    - name: FAIL2BAN | restart service
+      service:
+        name: fail2ban
+        state: restarted
diff --git a/tasks/templates/jail.local.j2 b/tasks/templates/jail.local.j2
new file mode 100644
index 0000000000000000000000000000000000000000..fde1f94fe4b49c93361c6635f37d44a35923271b
--- /dev/null
+++ b/tasks/templates/jail.local.j2
@@ -0,0 +1,12 @@
+[DEFAULT]
+banaction = ufw
+bantime   = 3600
+maxretry  = 3
+ignoreip  = 127.0.0.1 {{gateway}} {% for host in groups['all'] %}{{hostvars[host]['ansible_host']|ansible.netcommon.ipaddr('public')}} {% endfor %}
+
+
+[ssh]
+enabled  = true
+filter = sshd
+logpath = /var/log/auth.log
+findtime = 300