diff --git a/virtweb_backend/src/libvirt_lib_structures/domain.rs b/virtweb_backend/src/libvirt_lib_structures/domain.rs
index 7c2d1f6..60b93c7 100644
--- a/virtweb_backend/src/libvirt_lib_structures/domain.rs
+++ b/virtweb_backend/src/libvirt_lib_structures/domain.rs
@@ -1,4 +1,5 @@
 use crate::libvirt_lib_structures::XMLUuid;
+use crate::utils::cloud_init_utils::CloudInitConfig;
 
 /// VirtWeb specific metadata
 #[derive(serde::Serialize, serde::Deserialize, Default, Debug, Clone)]
@@ -8,6 +9,8 @@ pub struct DomainMetadataVirtWebXML {
     pub ns: String,
     #[serde(skip_serializing_if = "Option::is_none")]
     pub group: Option<String>,
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pub cloud_init: Option<CloudInitConfig>,
 }
 
 /// Domain metadata
diff --git a/virtweb_backend/src/libvirt_rest_structures/vm.rs b/virtweb_backend/src/libvirt_rest_structures/vm.rs
index 63cc646..214c9bd 100644
--- a/virtweb_backend/src/libvirt_rest_structures/vm.rs
+++ b/virtweb_backend/src/libvirt_rest_structures/vm.rs
@@ -4,6 +4,7 @@ use crate::libvirt_lib_structures::XMLUuid;
 use crate::libvirt_lib_structures::domain::*;
 use crate::libvirt_rest_structures::LibVirtStructError;
 use crate::libvirt_rest_structures::LibVirtStructError::StructureExtraction;
+use crate::utils::cloud_init_utils::CloudInitConfig;
 use crate::utils::file_size_utils::FileSize;
 use crate::utils::files_utils;
 use crate::utils::vm_file_disks_utils::{VMDiskBus, VMDiskFormat, VMFileDisk};
@@ -94,6 +95,9 @@ pub struct VMInfo {
     pub tpm_module: bool,
     /// Strings injected as OEM Strings in SMBios configuration
     pub oem_strings: Vec<String>,
+    /// Cloud init configuration
+    #[serde(default)]
+    pub cloud_init: CloudInitConfig,
 }
 
 impl VMInfo {
@@ -340,6 +344,7 @@ impl VMInfo {
                 virtweb: DomainMetadataVirtWebXML {
                     ns: "https://virtweb.communiquons.org".to_string(),
                     group: self.group.clone().map(|g| g.0),
+                    cloud_init: Some(self.cloud_init.clone()),
                 },
             }),
             os: OSXML {
@@ -582,6 +587,13 @@ impl VMInfo {
                 .and_then(|s| s.oem_strings)
                 .map(|s| s.entries.iter().map(|o| o.content.to_string()).collect())
                 .unwrap_or_default(),
+            cloud_init: domain
+                .metadata
+                .clone()
+                .unwrap_or_default()
+                .virtweb
+                .cloud_init
+                .unwrap_or_default(),
         })
     }
 }
diff --git a/virtweb_backend/src/utils/cloud_init_utils.rs b/virtweb_backend/src/utils/cloud_init_utils.rs
new file mode 100644
index 0000000..1059845
--- /dev/null
+++ b/virtweb_backend/src/utils/cloud_init_utils.rs
@@ -0,0 +1,19 @@
+/// VM Cloud Init configuration
+///
+/// RedHat documentation: https://docs.redhat.com/fr/documentation/red_hat_enterprise_linux/9/html/configuring_and_managing_cloud-init_for_rhel_9/configuring-cloud-init_cloud-content
+/// cloud-localds source code: https://github.com/canonical/cloud-utils/blob/main/bin/cloud-localds
+#[derive(Clone, Debug, serde::Serialize, serde::Deserialize, Default)]
+pub struct CloudInitConfig {
+    attach_config: bool,
+    /// Main user data
+    user_data: String,
+    /// Instance ID, set in metadata file
+    #[serde(skip_serializing_if = "Option::is_none")]
+    instance_id: Option<String>,
+    /// Local hostname, set in metadata file
+    #[serde(skip_serializing_if = "Option::is_none")]
+    local_hostname: Option<String>,
+    /// Network configuration
+    #[serde(skip_serializing_if = "Option::is_none")]
+    network_configuration: Option<String>,
+}
diff --git a/virtweb_backend/src/utils/mod.rs b/virtweb_backend/src/utils/mod.rs
index 92023bb..8371269 100644
--- a/virtweb_backend/src/utils/mod.rs
+++ b/virtweb_backend/src/utils/mod.rs
@@ -1,3 +1,4 @@
+pub mod cloud_init_utils;
 pub mod exec_utils;
 pub mod file_disks_utils;
 pub mod file_size_utils;