diff --git a/defaults/main.yml b/defaults/main.yml
index 1988c19836a9797fa6ef1ce70a9025a2d57051ee..690851733966510124618d13ce87b0f9f3969c0f 100644
--- a/defaults/main.yml
+++ b/defaults/main.yml
@@ -20,3 +20,5 @@ kypo_interface_interfaces: []
 kypo_interface_required_variables:
     kypo_interface_interfaces: '{{ kypo_interface_interfaces }}'
 
+kypo_interface_opnsense_config_file: /conf/config.xml
+kypo_interface_opnsense_local_config_file: '/tmp/config-{{ inventory_hostname }}'
diff --git a/tasks/Debian.yml b/tasks/Debian.yml
new file mode 100644
index 0000000000000000000000000000000000000000..b4c8c62afc7d43cb96069735fb9bf051cdaeea0b
--- /dev/null
+++ b/tasks/Debian.yml
@@ -0,0 +1,49 @@
+
+- name: clean interfaces configuration
+  when: kypo_interface_clean is defined and kypo_interface_clean
+  block:
+   - name: find all interfaces configuration files
+     find:
+         paths:
+             - '{{ kypo_interface_directory }}'
+     register: kypo_interface_extra_files
+
+   - set_fact:
+         kypo_interface_config_files: '{{ (kypo_interface_extra_files.files | map(attribute="path") | list) + [kypo_interface_default_file] }}'
+
+   - include_tasks: 'clean-Debian.yml'
+     vars:
+       kypo_interface_device: '{{ kypo_interface_item.kypo_interface_device }}'
+     loop_control:
+       loop_var: kypo_interface_item
+     loop: '{{ kypo_interface_interfaces }}'
+
+   - name: remove multiple consecutive new line characters
+     replace:
+         path: '{{ item }}'
+         regexp: '(\n)+'
+         replace: '\n'
+     with_items: '{{ kypo_interface_config_files }}'
+
+- name: configure interfaces
+  blockinfile:
+      path: '{{ kypo_interface_file }}'
+      create: yes
+      marker: '# {mark} {{ item.kypo_interface_device }}'
+      block: |
+          allow-hotplug {{ item.kypo_interface_device }}
+          auto {{ item.kypo_interface_device }}
+          iface {{ item.kypo_interface_device }} inet dhcp
+              mtu {{ kypo_interface_mtu }}
+              {% if item.kypo_interface_default_gateway is defined and item.kypo_interface_default_gateway -%}
+              gateway {{ item.kypo_interface_default_gateway }}
+              up route add default gw {{ item.kypo_interface_default_gateway }}
+              {% endif -%}
+              {% if item.kypo_interface_routes is defined and item.kypo_interface_routes -%}
+              {% for route in item.kypo_interface_routes -%}
+              post-up ip route add {{ route['network'] }}/{{ route['mask'] }} via {{ route['gateway'] }}
+              pre-down ip route del {{ route['network'] }}/{{ route['mask'] }} via {{ route['gateway'] }}
+              {% endfor %}
+              {% endif %}
+  notify: kypo_interface_networking_restart
+  loop: '{{ kypo_interface_interfaces }}'
diff --git a/tasks/FreeBSD.yml b/tasks/FreeBSD.yml
new file mode 100644
index 0000000000000000000000000000000000000000..6f1feaf59e8f33d3f05bebb6ac88a6b85c3f9fa5
--- /dev/null
+++ b/tasks/FreeBSD.yml
@@ -0,0 +1,73 @@
+
+- include_tasks: check-OPNsense.yml
+
+- name: clean interfaces configuration
+  xml:
+    path: '{{ kypo_interface_opnsense_local_config_file }}'
+    xpath: '/opnsense/interfaces/*[if and if[text()="{{ item.kypo_interface_device }}"]]'
+    state: absent
+  delegate_to: localhost
+  loop: '{{ kypo_interface_interfaces }}'
+  when: kypo_interface_clean is defined and kypo_interface_clean
+
+- name: configure interfaces
+  include_tasks: interface-FreeBSD.yml
+  vars:
+    kypo_interface_device: '{{ kypo_interface_item.kypo_interface_device }}'
+  loop_control:
+    loop_var: kypo_interface_item
+  loop: '{{ kypo_interface_interfaces }}'
+
+- name: get default gateway
+  set_fact:
+    kypo_interface_default_gateway: '{{ kypo_interface_interfaces | selectattr("kypo_interface_default_gateway", "defined") | first }}'
+
+- name: prepare variables with configuration
+  set_fact:
+    default_gateway:
+      interface: '{{ kypo_interface_default_gateway.kypo_interface_device }}'
+      gateway: '{{ kypo_interface_default_gateway.kypo_interface_default_gateway }}'
+      name: WAN
+      ipprotocol: inet
+      priority: 1
+      weight: 1
+      monitor_disable: 1
+    firewall_rule:
+      type: pass
+      interface: '{{ kypo_interface_interfaces | map(attribute="kypo_interface_device") | join(",") }}'
+      ipprotocol: inet
+      descr: Allow everything
+      direction: any
+      source/any: 1
+      destination/any: 1
+      statetype: keep state
+      quick: 1
+      floating: 'yes'
+
+- name: configure gateway
+  xml:
+    path: '{{ kypo_interface_opnsense_local_config_file }}'
+    xpath: '/opnsense/gateways/gateway_item[name[text()="{{ default_gateway.name }}"]]/{{ item.key }}'
+    pretty_print: yes
+    value: '{{ item.value }}'
+  loop: '{{ default_gateway | dict2items }}'
+  delegate_to: localhost
+
+- name: add firewall rule
+  xml:
+    path: '{{ kypo_interface_opnsense_local_config_file }}'
+    xpath: '/opnsense/filter/rule[descr[text()="{{ firewall_rule.descr }}"]]/{{ item.key }}'
+    pretty_print: yes
+    value: '{{ item.value }}'
+  loop: '{{ firewall_rule | dict2items }}'
+  delegate_to: localhost
+
+- name: copy the modified configuration to machine
+  copy:
+    src: '{{ kypo_interface_opnsense_local_config_file }}'
+    dest: '{{ kypo_interface_opnsense_config_file }}'
+  register: configuration_copy
+
+- name: reboot
+  reboot:
+  when: configuration_copy is changed
diff --git a/tasks/check-OPNsense.yml b/tasks/check-OPNsense.yml
new file mode 100644
index 0000000000000000000000000000000000000000..1d99aadddecea109c6dbbf753a4874f34d7a3442
--- /dev/null
+++ b/tasks/check-OPNsense.yml
@@ -0,0 +1,34 @@
+
+- name: stat OPNsense config file
+  stat:
+    path: '{{ kypo_interface_opnsense_config_file }}'
+  register: opnsense_config_stat
+
+- name: check if config file exists
+  fail:
+    msg: "/conf/config.xml not found, only OPNsense is supported out of FreeBSD systems"
+  when: not opnsense_config_stat.stat.exists
+
+- name: fetch config file
+  fetch:
+    src: '{{ kypo_interface_opnsense_config_file }}'
+    dest: '{{ kypo_interface_opnsense_local_config_file }}'
+    flat: yes
+
+- name: install lxml on controller
+  pip:
+    name: lxml
+  delegate_to: localhost
+
+- name: check config file contains opnsense xml root
+  xml:
+    path: '{{ kypo_interface_opnsense_local_config_file }}'
+    xpath: /opnsense
+    content: attribute
+  delegate_to: localhost
+  register: opnsense_config_root
+
+- name: assert if OPNsense
+  fail:
+    msg: "Only OPNsense is supported out of FreeBSD systems"
+  when: opnsense_config_root.matches | length != 1
diff --git a/tasks/clean.yml b/tasks/clean-Debian.yml
similarity index 51%
rename from tasks/clean.yml
rename to tasks/clean-Debian.yml
index 5b4294541ebaab43a935eb080d6727e7e3f5e47c..3354ac7745b3eecfd8cd9ed8e16574249450f581 100644
--- a/tasks/clean.yml
+++ b/tasks/clean-Debian.yml
@@ -1,13 +1,4 @@
 
-- name: find all interfaces configuration files
-  find:
-      paths:
-          - '{{ kypo_interface_directory }}'
-  register: kypo_interface_extra_files
-
-- set_fact:
-      kypo_interface_config_files: '{{ (kypo_interface_extra_files.files | map(attribute="path") | list) + [kypo_interface_default_file] }}'
-
 - name: remove old iface settings for retrieved interface name
   replace:
       path: '{{ item }}'
@@ -21,11 +12,3 @@
       regexp: '^.*(?<=\s){{ kypo_interface_device }}(?=\s).*$'
   notify: kypo_interface_networking_restart
   with_items: '{{ kypo_interface_config_files }}'
-
-- name: remove multiple consecutive new line characters
-  replace:
-      path: '{{ item }}'
-      regexp: '(\n)+'
-      replace: '\n'
-  with_items: '{{ kypo_interface_config_files }}'
-
diff --git a/tasks/interface-FreeBSD.yml b/tasks/interface-FreeBSD.yml
new file mode 100644
index 0000000000000000000000000000000000000000..c6c2d45ffe63cfa4cf768afd9a4ee0a7a271b2b2
--- /dev/null
+++ b/tasks/interface-FreeBSD.yml
@@ -0,0 +1,16 @@
+- name: prepare interface configuration
+  set_fact:
+    kypo_interface_config:
+      if: '{{ kypo_interface_device }}'
+      ipaddr: dhcp
+      mtu: '{{ kypo_interface_mtu }}'
+      enable: 1
+
+- name: configure interface
+  xml:
+    path: '{{ kypo_interface_opnsense_local_config_file }}'
+    xpath: '/opnsense/interfaces/{{ kypo_interface_device }}/{{ item.key }}'
+    value: '{{ item.value }}'
+    pretty_print: yes
+  delegate_to: localhost
+  loop: '{{ kypo_interface_config | dict2items }}'
diff --git a/tasks/interface.yml b/tasks/interface.yml
deleted file mode 100644
index f226c9eeb50e044cb863785fb960aa6f4edfb4e7..0000000000000000000000000000000000000000
--- a/tasks/interface.yml
+++ /dev/null
@@ -1,23 +0,0 @@
-
-- name: configure interface
-  blockinfile:
-      path: '{{ kypo_interface_file }}'
-      create: yes
-      marker: '# {mark} {{ kypo_interface_device }}'
-      block: |
-          allow-hotplug {{ kypo_interface_device }}
-          auto {{ kypo_interface_device }}
-          iface {{ kypo_interface_device }} inet dhcp
-              mtu {{ kypo_interface_mtu }}
-              {% if kypo_interface_default_gateway -%}
-              gateway {{ kypo_interface_default_gateway }}
-              up route add default gw {{ kypo_interface_default_gateway }}
-              {% endif -%}
-              {% if kypo_interface_routes -%}
-              {% for route in kypo_interface_routes -%}
-              post-up ip route add {{ route['network'] }}/{{ route['mask'] }} via {{ route['gateway'] }}
-              pre-down ip route del {{ route['network'] }}/{{ route['mask'] }} via {{ route['gateway'] }}
-              {% endfor %}
-              {% endif %}
-  notify: kypo_interface_networking_restart
-
diff --git a/tasks/main-interface.yml b/tasks/main-interface.yml
deleted file mode 100644
index 4ccab52f480614e24d708c7bbf6dd96e9c3e8fe6..0000000000000000000000000000000000000000
--- a/tasks/main-interface.yml
+++ /dev/null
@@ -1,15 +0,0 @@
-
-- name: check existence of required variables
-  fail:
-      msg: kypo_interface_mac is not defined
-  when: not kypo_interface_mac
-
-- set_fact:
-      kypo_interface_device: '{%- from "roles/kypo-common/templates/network.j2" import mac_to_interface with context -%}
-                         {{ mac_to_interface(kypo_interface_mac) | default("") }}'
-
-- include: clean.yml
-  when: kypo_interface_clean is defined and kypo_interface_clean
-
-- include: interface.yml
-
diff --git a/tasks/main.yml b/tasks/main.yml
index 2ff0968c92ecdc7195b35d8da6e10c62e6f17012..23bdea8db06bc6b307dc5e39cf17c18fdd409785 100644
--- a/tasks/main.yml
+++ b/tasks/main.yml
@@ -5,12 +5,11 @@
   when: item.value is undefined or not item.value
   with_dict: '{{ kypo_interface_required_variables }}'
 
-- include: main-interface.yml
-  loop_control:
-      loop_var: kypo_interface_interface
-  vars:
-      kypo_interface_default_gateway: '{{ kypo_interface_interface.kypo_interface_default_gateway | default() }}'
-      kypo_interface_routes: '{{ kypo_interface_interface.kypo_interface_routes | default([]) }}'
-      kypo_interface_mac: '{{ kypo_interface_interface.kypo_interface_mac | default() }}'
-  with_items: '{{ kypo_interface_interfaces }}'
+- name: check existence of required variables
+  fail:
+      msg: kypo_interface_interfaces has an item with undefined kypo_interface_mac or kypo_interface_device
+  when: |
+    (kypo_interface_interfaces | rejectattr('kypo_interface_mac', 'defined') | length > 0) or
+    (kypo_interface_interfaces | rejectattr('kypo_interface_device', 'defined') | length > 0)
 
+- include_tasks: '{{ ansible_facts.os_family }}.yml'