diff --git a/defaults/main.yml b/defaults/main.yml
index 690851733966510124618d13ce87b0f9f3969c0f..bd3415f5d24c69c797e2a03bb769e1ed8c3189ce 100644
--- a/defaults/main.yml
+++ b/defaults/main.yml
@@ -22,3 +22,5 @@ kypo_interface_required_variables:
 
 kypo_interface_opnsense_config_file: /conf/config.xml
 kypo_interface_opnsense_local_config_file: '/tmp/config-{{ inventory_hostname }}'
+
+netplan_config_file: '/etc/netplan/50-cloud-init.yaml'
diff --git a/handlers/main.yml b/handlers/main.yml
index d402ec21b5a3e84d64f19cca2d2df7f8fbdeaa32..b5c01f2b452afd9d5611bdfd2feb43d5172235a0 100644
--- a/handlers/main.yml
+++ b/handlers/main.yml
@@ -1,6 +1,9 @@
+---
+
+- name: Apply Netplan configuration
+  command: netplan apply
 
 - name: kypo_interface_networking_restart
   service:
-      name: networking
-      state: restarted
-
+    name: networking
+    state: restarted
diff --git a/tasks/Debian.yml b/tasks/Debian.yml
index b4c8c62afc7d43cb96069735fb9bf051cdaeea0b..1dc363f2c0c0c944d9ecd85f8ce69a1b6d8284b4 100644
--- a/tasks/Debian.yml
+++ b/tasks/Debian.yml
@@ -1,36 +1,56 @@
+---
 
-- name: clean interfaces configuration
-  when: kypo_interface_clean is defined and kypo_interface_clean
+- name: Determine if Netplan is used
+  set_fact:
+    is_netplan: "{{ ansible_distribution == 'Ubuntu' or (ansible_distribution == 'Debian' and ansible_distribution_version is version('12', '>=')) }}"
+
+- name: Use Netplan for network configuration
+  when: is_netplan
+  block:
+    - name: Generate Netplan configuration
+      template:
+        src: "50-cloud-init.yaml.j2"
+        dest: "{{ netplan_config_file }}"
+      notify: Apply Netplan configuration
+
+    - name: Apply Netplan configuration
+      command: netplan apply
+
+- name: Use legacy configuration for older Debian
+  when: not is_netplan
   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: |
+    - 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
@@ -45,5 +65,5 @@
               pre-down ip route del {{ route['network'] }}/{{ route['mask'] }} via {{ route['gateway'] }}
               {% endfor %}
               {% endif %}
-  notify: kypo_interface_networking_restart
-  loop: '{{ kypo_interface_interfaces }}'
+      notify: kypo_interface_networking_restart
+      loop: '{{ kypo_interface_interfaces }}'
diff --git a/tasks/FreeBSD.yml b/tasks/FreeBSD.yml
index df89d60b1bf59a583d0eb83b6652d1500da09a47..a28dc50bb4297874f508e5bddaf0e5f970e852da 100644
--- a/tasks/FreeBSD.yml
+++ b/tasks/FreeBSD.yml
@@ -1,4 +1,3 @@
-
 - include_tasks: check-OPNsense.yml
 
 - name: clean interfaces configuration
diff --git a/tasks/check-OPNsense.yml b/tasks/check-OPNsense.yml
index 5e37faeacad1ae0ef60541ceb810272a36ce85fc..a503b4fefbb63efb790991cce6f5d5a326a3dd7b 100644
--- a/tasks/check-OPNsense.yml
+++ b/tasks/check-OPNsense.yml
@@ -1,4 +1,3 @@
-
 - name: stat OPNsense config file
   stat:
     path: '{{ kypo_interface_opnsense_config_file }}'
diff --git a/tasks/clean-Debian.yml b/tasks/clean-Debian.yml
index 3354ac7745b3eecfd8cd9ed8e16574249450f581..f4bf8481759f3f0e3bc67d6fed95de33bc50005a 100644
--- a/tasks/clean-Debian.yml
+++ b/tasks/clean-Debian.yml
@@ -1,14 +1,13 @@
-
 - name: remove old iface settings for retrieved interface name
   replace:
-      path: '{{ item }}'
-      regexp: ^iface[ \t]{{ kypo_interface_device }}[ \t].*(\n[ \t]+.*)*
+    path: '{{ item }}'
+    regexp: ^iface[ \t]{{ kypo_interface_device }}[ \t].*(\n[ \t]+.*)*
   notify: kypo_interface_networking_restart
   with_items: '{{ kypo_interface_config_files }}'
 
 - name: remove the rest of old settings for retrieved interface name
   replace:
-      path: '{{ item }}'
-      regexp: '^.*(?<=\s){{ kypo_interface_device }}(?=\s).*$'
+    path: '{{ item }}'
+    regexp: '^.*(?<=\s){{ kypo_interface_device }}(?=\s).*$'
   notify: kypo_interface_networking_restart
   with_items: '{{ kypo_interface_config_files }}'
diff --git a/tasks/main.yml b/tasks/main.yml
index 23bdea8db06bc6b307dc5e39cf17c18fdd409785..42b6a323cb1bb16da924966df54bc8f93db55047 100644
--- a/tasks/main.yml
+++ b/tasks/main.yml
@@ -1,13 +1,12 @@
-
 - name: check existence of required variables
   fail:
-      msg: required variable '{{ item.key }}' is undefined
+    msg: required variable '{{ item.key }}' is undefined
   when: item.value is undefined or not item.value
   with_dict: '{{ kypo_interface_required_variables }}'
 
 - name: check existence of required variables
   fail:
-      msg: kypo_interface_interfaces has an item with undefined kypo_interface_mac or kypo_interface_device
+    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)
diff --git a/templates/50-cloud-init.yaml.j2 b/templates/50-cloud-init.yaml.j2
new file mode 100644
index 0000000000000000000000000000000000000000..78f886d6d07bb1d897fd93c99992c4c3dcd84455
--- /dev/null
+++ b/templates/50-cloud-init.yaml.j2
@@ -0,0 +1,21 @@
+#jinja2: trim_blocks: True, lstrip_blocks: True
+network:
+  version: 2
+  ethernets:
+    {% for interface in kypo_interface_interfaces %}
+    {{ interface.kypo_interface_device }}:
+      dhcp4: true
+      mtu: {{ kypo_interface_mtu }}
+      {% if interface.kypo_interface_default_gateway is defined and interface.kypo_interface_default_gateway %}
+      routes:
+        - to: 0.0.0.0/0
+          via: {{ interface.kypo_interface_default_gateway }}
+      {% endif %}
+      {% if interface.kypo_interface_routes is defined and interface.kypo_interface_routes %}
+      routes:
+        {% for route in interface.kypo_interface_routes %}
+        - to: {{ (route['network'] ~ '/' ~ route['mask']) | ipaddr('net') }}
+          via: {{ route['gateway'] }}
+        {% endfor %}
+      {% endif %}
+    {% endfor %}