diff --git a/Cargo.lock b/Cargo.lock
index b202936a3b599caaa14cf66f7573e9d7dd83dba4..0ccece6f4efb194e4070b741bdd19c04d670a59c 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -997,6 +997,7 @@ dependencies = [
  "dubp-user-docs 0.14.0",
  "dup-crypto 0.7.0",
  "durs-common-tools 0.2.0",
+ "durs-message 0.3.0-dev",
  "durs-module 0.3.0-dev",
  "envy 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
diff --git a/lib/core/conf/Cargo.toml b/lib/core/conf/Cargo.toml
index 3449896a0905ff483cd7c22b87b47654a6845709..bb34ff368f00dd16a68bf6671209c089d7a0fb2f 100644
--- a/lib/core/conf/Cargo.toml
+++ b/lib/core/conf/Cargo.toml
@@ -14,6 +14,7 @@ dirs = "2.0.2"
 dup-crypto = { path = "../../crypto" }
 dubp-currency-params = { path = "../../dubp/currency-params" }
 dubp-user-docs= { path = "../../dubp/user-docs" }
+durs-message =  { path = "../message" }
 durs-module = { path = "../module" }
 durs-common-tools = { path = "../../tools/common-tools" }
 envy = "0.4.1"
diff --git a/lib/core/conf/src/lib.rs b/lib/core/conf/src/lib.rs
index 0cf9a602bc1834ebeec5e2f4a6f544df22bfb75c..f1d979d9b9c923d1d0de90b71671e8c8a1dd2331 100644
--- a/lib/core/conf/src/lib.rs
+++ b/lib/core/conf/src/lib.rs
@@ -40,7 +40,7 @@ pub mod errors;
 pub mod file;
 mod global_conf;
 pub mod keypairs;
-mod modules_conf;
+pub mod modules_conf;
 mod resources;
 mod v1;
 
diff --git a/lib/core/conf/src/modules_conf.rs b/lib/core/conf/src/modules_conf.rs
index 38e975b0c38a189261b732d86635d365ce64e66c..ab54a2816cfae66c04899213f1e9edd7eea03c7b 100644
--- a/lib/core/conf/src/modules_conf.rs
+++ b/lib/core/conf/src/modules_conf.rs
@@ -15,7 +15,24 @@
 
 //! Dunitrust modules configuration
 
-use durs_module::ModuleName;
+use crate::constants;
+use crate::keypairs::DuniterKeyPairs;
+use crate::DuRsConf;
+use dubp_currency_params::CurrencyName;
+use durs_common_tools::traits::merge::Merge;
+use durs_message::DursMsg;
+use durs_module::{
+    DursConfTrait, DursModule, ModuleConfError, ModuleName, ModuleStaticName, RequiredKeysContent,
+};
+
+/// Module configurations and required keys
+pub type ModuleConfsAndKeys<M> = (
+    (
+        <M as DursModule<DuRsConf, DursMsg>>::ModuleConf,
+        Option<<M as DursModule<DuRsConf, DursMsg>>::ModuleUserConf>,
+    ),
+    RequiredKeysContent,
+);
 
 #[derive(Debug, Clone, Deserialize, PartialEq, Serialize)]
 /// Modules conf
@@ -29,6 +46,44 @@ impl Default for ModulesConf {
 }
 
 impl ModulesConf {
+    // get module conf
+    fn get_module_conf<M: DursModule<DuRsConf, DursMsg>>(
+        currency_name: Option<&CurrencyName>,
+        global_conf: &<DuRsConf as DursConfTrait>::GlobalConf,
+        module_conf_json: Option<serde_json::Value>,
+    ) -> Result<(M::ModuleConf, Option<M::ModuleUserConf>), ModuleConfError> {
+        let file_module_user_conf: M::ModuleUserConf =
+            if let Some(module_conf_json) = module_conf_json {
+                let file_module_user_conf_opt: Option<M::ModuleUserConf> =
+                    serde_json::from_str(module_conf_json.to_string().as_str())?;
+                file_module_user_conf_opt.unwrap_or_default()
+            } else {
+                M::ModuleUserConf::default()
+            };
+
+        let env_module_user_conf = Self::get_env_module_user_conf::<M::ModuleUserConf>(M::name())?;
+
+        M::generate_module_conf(
+            currency_name,
+            global_conf,
+            Some(file_module_user_conf.merge(env_module_user_conf)),
+        )
+    }
+
+    // get module conf from environment variables
+    fn get_env_module_user_conf<ModuleUserConf: serde::de::DeserializeOwned>(
+        module_name: ModuleStaticName,
+    ) -> Result<ModuleUserConf, ModuleConfError> {
+        let prefix = format!(
+            "{}{}_",
+            constants::DURS_ENV_PREFIX,
+            module_name.0.to_ascii_uppercase()
+        );
+
+        envy::prefixed(prefix)
+            .from_env::<ModuleUserConf>()
+            .map_err(ModuleConfError::EnvyErr)
+    }
     /// Change module conf
     pub fn set_module_conf(&mut self, module_name: ModuleName, new_module_conf: serde_json::Value) {
         if self.0.is_null() {
@@ -44,3 +99,97 @@ impl ModulesConf {
         }
     }
 }
+
+/// Get module conf and keys
+pub fn get_module_conf_and_keys<M: DursModule<DuRsConf, DursMsg>>(
+    currency_name: Option<&CurrencyName>,
+    global_conf: &<DuRsConf as DursConfTrait>::GlobalConf,
+    module_conf_json: Option<serde_json::Value>,
+    keypairs: DuniterKeyPairs,
+) -> Result<ModuleConfsAndKeys<M>, ModuleConfError> {
+    Ok((
+        ModulesConf::get_module_conf::<M>(currency_name, global_conf, module_conf_json)?,
+        DuniterKeyPairs::get_required_keys_content(M::ask_required_keys(), keypairs),
+    ))
+}
+
+#[cfg(test)]
+mod tests {
+
+    use super::*;
+    use once_cell::sync::Lazy;
+    use std::sync::Mutex;
+
+    // Empty mutex used to ensure that only one test runs at a time
+    static MUTEX: Lazy<Mutex<()>> = Lazy::new(|| Mutex::new(()));
+
+    #[derive(Debug, Default, Deserialize, PartialEq)]
+    struct TestModuleUserConf {
+        field1: Option<String>,
+        field2: Option<usize>,
+    }
+
+    #[inline]
+    fn prefix() -> String {
+        format!("{}MODULE_TEST_", constants::DURS_ENV_PREFIX)
+    }
+
+    fn clear_env_vars() {
+        if std::env::var(&format!("{}FIELD1", prefix())).is_ok() {
+            std::env::remove_var(&format!("{}FIELD1", prefix()));
+        }
+        if std::env::var(&format!("{}FIELD2", prefix())).is_ok() {
+            std::env::remove_var(&format!("{}FIELD2", prefix()));
+        }
+    }
+
+    #[test]
+    fn test_env_module_conf_without_env_vars() -> Result<(), ModuleConfError> {
+        let _lock = MUTEX.lock().expect("MUTEX poisoned");
+        clear_env_vars();
+
+        assert_eq!(
+            TestModuleUserConf::default(),
+            ModulesConf::get_env_module_user_conf(ModuleStaticName("module_test"))?,
+        );
+
+        Ok(())
+    }
+
+    #[test]
+    fn test_env_module_conf_with_some_valid_env_vars() -> Result<(), ModuleConfError> {
+        let _lock = MUTEX.lock().expect("MUTEX poisoned");
+        clear_env_vars();
+
+        std::env::set_var(&format!("{}FIELD1", prefix()), "toto");
+        std::env::set_var(&format!("{}FIELD2", prefix()), "4");
+
+        assert_eq!(
+            TestModuleUserConf {
+                field1: Some("toto".to_owned()),
+                field2: Some(4),
+            },
+            ModulesConf::get_env_module_user_conf(ModuleStaticName("module_test"))?,
+        );
+
+        Ok(())
+    }
+
+    #[test]
+    fn test_env_module_conf_with_invalid_env_var() -> Result<(), ModuleConfError> {
+        let _lock = MUTEX.lock().expect("MUTEX poisoned");
+        clear_env_vars();
+
+        // field2 must be a number
+        std::env::set_var(&format!("{}FIELD2", prefix()), "toto");
+
+        if let Err(ModuleConfError::EnvyErr(_)) = ModulesConf::get_env_module_user_conf::<
+            TestModuleUserConf,
+        >(ModuleStaticName("module_test"))
+        {
+            Ok(())
+        } else {
+            panic!("get_env_module_user_conf() must return an error ModuleConfError::EnvyErr.");
+        }
+    }
+}
diff --git a/lib/core/core/src/lib.rs b/lib/core/core/src/lib.rs
index cecf3fb6427c44eb4925c477bbd6306aeb5d1922..0ce8e79256bd93780cccb87853443cc45a3eac3d 100644
--- a/lib/core/core/src/lib.rs
+++ b/lib/core/core/src/lib.rs
@@ -44,7 +44,6 @@ use crate::errors::DursCoreError;
 use dubp_currency_params::CurrencyName;
 use durs_bc::{dbex::DbExQuery, BlockchainModule};
 use durs_common_tools::fatal_error;
-use durs_common_tools::traits::merge::Merge;
 pub use durs_conf::{
     constants::KEYPAIRS_FILENAME, keypairs::cli::*, ChangeGlobalConf, DuRsConf, DuniterKeyPairs,
 };
@@ -124,16 +123,17 @@ impl DursCore<DuRsConf> {
             .get(&M::name().to_string().as_str())
             .cloned();
 
-        let ((module_conf, module_user_conf), required_keys) = get_module_conf_and_keys::<M>(
-            durs_core.currency_name.as_ref(),
-            &durs_core.soft_meta_datas.conf.get_global_conf(),
-            module_conf_json,
-            durs_core.keypairs,
-        )
-        .map_err(|e| DursCoreError::PlugModuleError {
-            module_name: M::name(),
-            error: e.into(),
-        })?;
+        let ((module_conf, module_user_conf), required_keys) =
+            durs_conf::modules_conf::get_module_conf_and_keys::<M>(
+                durs_core.currency_name.as_ref(),
+                &durs_core.soft_meta_datas.conf.get_global_conf(),
+                module_conf_json,
+                durs_core.keypairs,
+            )
+            .map_err(|e| DursCoreError::PlugModuleError {
+                module_name: M::name(),
+                error: e.into(),
+            })?;
         // Execute module subcommand
         let new_module_conf = M::exec_subcommand(
             &durs_core.soft_meta_datas,
@@ -411,12 +411,13 @@ impl DursCore<DuRsConf> {
                         .cloned();
 
                     // Load module conf and keys
-                    let ((module_conf, _), required_keys) = get_module_conf_and_keys::<NM>(
-                        self.currency_name.as_ref(),
-                        &soft_meta_datas.conf.get_global_conf(),
-                        module_conf_json,
-                        self.keypairs.clone(),
-                    )?;
+                    let ((module_conf, _), required_keys) =
+                        durs_conf::modules_conf::get_module_conf_and_keys::<NM>(
+                            self.currency_name.as_ref(),
+                            &soft_meta_datas.conf.get_global_conf(),
+                            module_conf_json,
+                            self.keypairs.clone(),
+                        )?;
 
                     let sync_params = network_sync.clone();
                     let thread_builder = thread::Builder::new().name(NM::name().0.into());
@@ -495,12 +496,13 @@ impl DursCore<DuRsConf> {
                     .get(&M::name().to_string().as_str())
                     .cloned();
                 // Load module conf and keys
-                let ((module_conf, _), required_keys) = get_module_conf_and_keys::<M>(
-                    self.currency_name.as_ref(),
-                    &soft_meta_datas.conf.get_global_conf(),
-                    module_conf_json,
-                    self.keypairs.clone(),
-                )?;
+                let ((module_conf, _), required_keys) =
+                    durs_conf::modules_conf::get_module_conf_and_keys::<M>(
+                        self.currency_name.as_ref(),
+                        &soft_meta_datas.conf.get_global_conf(),
+                        module_conf_json,
+                        self.keypairs.clone(),
+                    )?;
 
                 let thread_builder = thread::Builder::new().name(M::name().0.into());
                 self.threads.insert(
@@ -553,66 +555,6 @@ impl DursCore<DuRsConf> {
     }
 }
 
-/// Module configurations and required keys
-pub type ModuleConfsAndKeys<M> = (
-    (
-        <M as DursModule<DuRsConf, DursMsg>>::ModuleConf,
-        Option<<M as DursModule<DuRsConf, DursMsg>>::ModuleUserConf>,
-    ),
-    RequiredKeysContent,
-);
-
-/// Get module conf and keys
-pub fn get_module_conf_and_keys<M: DursModule<DuRsConf, DursMsg>>(
-    currency_name: Option<&CurrencyName>,
-    global_conf: &<DuRsConf as DursConfTrait>::GlobalConf,
-    module_conf_json: Option<serde_json::Value>,
-    keypairs: DuniterKeyPairs,
-) -> Result<ModuleConfsAndKeys<M>, ModuleConfError> {
-    Ok((
-        get_module_conf::<M>(currency_name, global_conf, module_conf_json)?,
-        DuniterKeyPairs::get_required_keys_content(M::ask_required_keys(), keypairs),
-    ))
-}
-
-fn get_env_module_user_conf<ModuleUserConf: serde::de::DeserializeOwned>(
-    module_name: ModuleStaticName,
-) -> Result<ModuleUserConf, ModuleConfError> {
-    let prefix = format!(
-        "{}{}",
-        durs_conf::constants::DURS_ENV_PREFIX,
-        module_name.0.to_ascii_uppercase()
-    );
-
-    envy::prefixed(prefix)
-        .from_env::<ModuleUserConf>()
-        .map_err(ModuleConfError::EnvyErr)
-}
-
-/// get module conf
-pub fn get_module_conf<M: DursModule<DuRsConf, DursMsg>>(
-    currency_name: Option<&CurrencyName>,
-    global_conf: &<DuRsConf as DursConfTrait>::GlobalConf,
-    module_conf_json: Option<serde_json::Value>,
-) -> Result<(M::ModuleConf, Option<M::ModuleUserConf>), ModuleConfError> {
-    let file_module_user_conf: M::ModuleUserConf = if let Some(module_conf_json) = module_conf_json
-    {
-        let file_module_user_conf_opt: Option<M::ModuleUserConf> =
-            serde_json::from_str(module_conf_json.to_string().as_str())?;
-        file_module_user_conf_opt.unwrap_or_default()
-    } else {
-        M::ModuleUserConf::default()
-    };
-
-    let env_module_user_conf = get_env_module_user_conf::<M::ModuleUserConf>(M::name())?;
-
-    M::generate_module_conf(
-        currency_name,
-        global_conf,
-        Some(file_module_user_conf.merge(env_module_user_conf)),
-    )
-}
-
 /// Launch databases explorer
 pub fn dbex(profile_path: PathBuf, csv: bool, query: &DbExQuery) {
     // Launch databases explorer