diff --git a/Cargo.lock b/Cargo.lock
index 4b0fd97e404f619cd7211138dddcd08333497002..ba44a36760f1d0d359f25be4ba99bf92a0711a9e 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1164,7 +1164,9 @@ dependencies = [
  "log",
  "logwatcher",
  "nix 0.17.0",
+ "read_input",
  "rusty-hook",
+ "serde_json",
  "structopt",
 ]
 
@@ -2933,6 +2935,12 @@ dependencies = [
  "rand_core 0.3.1",
 ]
 
+[[package]]
+name = "read_input"
+version = "0.8.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b57518cc6538a2eb7dce826e24fa51d0b7cf8e744ee10c7f56259cdec40050e5"
+
 [[package]]
 name = "redox_syscall"
 version = "0.1.57"
diff --git a/Cargo.toml b/Cargo.toml
index 57b22316f6bbbf3e9285006bd68595cd47ded856..c671f85a12b45215f0b35d8185a459439e0cced6 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -21,6 +21,8 @@ dirs = "3.0.1"
 log = "0.4.11"
 logwatcher = "0.1.1"
 nix = "0.17.0"
+read_input = "0.8.4"
+serde_json = "1.0.53"
 structopt = "0.3.18"
 
 [dev-dependencies]
diff --git a/app/lib/dto/ConfDTO.ts b/app/lib/dto/ConfDTO.ts
index b80564a06834daa699c15a152aab5d86b04b3066..69325df7b8a4b8a77ed390d61268249b0e57fae1 100644
--- a/app/lib/dto/ConfDTO.ts
+++ b/app/lib/dto/ConfDTO.ts
@@ -181,6 +181,7 @@ export class ConfDTO
     public nonWoTPeersLimit: number,
     public proxiesConf: ProxiesConf | undefined,
     public gva?: {
+      enabled: boolean;
       host?: string;
       port?: number;
       path?: string;
diff --git a/app/modules/config.ts b/app/modules/config.ts
index 2dfe10269ade0665d43e9f1ae8f39781df5af346..27925692eee116e30a076bcfea985575e7299bba 100644
--- a/app/modules/config.ts
+++ b/app/modules/config.ts
@@ -21,16 +21,7 @@ import { ProgramOptions } from "../lib/common-libs/programOptions";
 
 module.exports = {
   duniter: {
-    cliOptions: [
-      {
-        value: "--gva",
-        desc: "Enable gva API and database.",
-      },
-      {
-        value: "--no-gva",
-        desc: "Disable gva API and database.",
-      },
-    ],
+    cliOptions: [],
 
     config: {
       onLoading: async (conf: ConfDTO, program: ProgramOptions) => {
@@ -38,31 +29,6 @@ module.exports = {
         conf.sigReplay = conf.msPeriod;
         conf.switchOnHeadAdvance =
           CommonConstants.SWITCH_ON_BRANCH_AHEAD_BY_X_BLOCKS;
-
-        // Gva
-        if (
-          program.gva &&
-          program.gva === true &&
-          (!program.noGva || program.noGva === undefined)
-        ) {
-          // Fill with default conf if needed
-          if (conf.gva) {
-            conf.gva.host = conf.gva.host || "localhost";
-            conf.gva.port = conf.gva.port || 30901;
-            conf.gva.path = conf.gva.path || "gva";
-            conf.gva.subscriptionsPath =
-              conf.gva.subscriptionsPath || "gva-sub";
-          } else {
-            conf.gva = {
-              host: "localhost",
-              port: 30901,
-              path: "gva",
-              subscriptionsPath: "gva-sub",
-            };
-          }
-        } else if (program.noGva) {
-          conf.gva = undefined;
-        }
       },
       beforeSave: async (conf: ConfDTO) => {
         conf.msPeriod = conf.msWindow;
diff --git a/doc/use/configure.md b/doc/use/configure.md
index 4d3d1a371a5975ee59a7fff7fd0a7e9248998251..5a394554ead86c338a5737c92606dcc875fb6819 100644
--- a/doc/use/configure.md
+++ b/doc/use/configure.md
@@ -183,9 +183,11 @@ This mode is optional if only because technically it is sometimes difficult or e
 
 ### Configuring GVA
 
-GVA is still disabled by default. To enable it you have to add the option `--gva` during synchronization and at each start of your duniter node (`duniter start --gva`).
+GVA is still disabled by default, to enable it you need to use wizard command:
 
-GVA is not yet configurable from the command line, but it is possible to manually edit `conf.json` file :
+`duniter wizard gva`
+
+It is also possible to manually edit `conf.json` file :
 
 | parameter | type | default value |
 |:-:|:-:|:-:|
@@ -211,8 +213,6 @@ duniter sync DUNITER_NODE_HOST:DUNITER_NODE_PORT
 
 For Ğ1, if you don't know any node you can choose the official node `g1.duniter.org:443`.
 
-NB: If you want to enable GVA you have to synchronize with the `--gva` option.
-
 ## Launch
 
 There are four different commands depending on whether or not you want to demonize your Duniter instance and whether or not you want to use the web-ui:
diff --git a/rust-bins/duniter-launcher/src/duniter_ts_args.rs b/rust-bins/duniter-launcher/src/duniter_ts_args.rs
index 1b3724526b790688363c4817b4af0ca823cebd64..6a7e59c9b61a6650fafc4651ce7c65551be216d5 100644
--- a/rust-bins/duniter-launcher/src/duniter_ts_args.rs
+++ b/rust-bins/duniter-launcher/src/duniter_ts_args.rs
@@ -16,9 +16,6 @@
 use crate::*;
 
 fn gen_start_args(args: &DuniterStartArgs, duniter_ts_args: &mut Vec<String>) {
-    if args.gva {
-        duniter_ts_args.push("--gva".to_owned());
-    }
     if let Some(ref keyfile) = args.keyfile {
         duniter_ts_args.push("--keyfile".to_owned());
         duniter_ts_args.push(
@@ -130,6 +127,7 @@ pub(crate) fn gen_duniter_ts_args(args: &DuniterArgs, duniter_js_exe: String) ->
                         duniter_ts_args.push(p.to_string());
                     }
                 }
+                WizardCommand::Gva { .. } => unreachable!(),
             }
         }
         DuniterCommand::WS2P(ref ws2p_command) => {
diff --git a/rust-bins/duniter-launcher/src/main.rs b/rust-bins/duniter-launcher/src/main.rs
index 67865daecf49f20eb74d552a2ecaa85f4b4bc65f..0c93e331ba835a7462e43bf4d756722a1e54a686 100644
--- a/rust-bins/duniter-launcher/src/main.rs
+++ b/rust-bins/duniter-launcher/src/main.rs
@@ -28,6 +28,7 @@ mod config;
 mod daemon;
 mod duniter_ts_args;
 mod sync;
+mod wizard_gva;
 
 use anyhow::{anyhow, Result};
 use daemonize_me::Daemon;
@@ -168,7 +169,9 @@ enum WizardCommand {
         #[structopt(short)]
         p: Option<usize>,
     },
-    #[structopt(display_order(1), alias = "network")]
+    #[structopt(display_order(1))]
+    Gva,
+    #[structopt(display_order(2), alias = "network")]
     Bma,
 }
 
@@ -186,9 +189,6 @@ enum WS2PCommand {
 
 #[derive(StructOpt)]
 struct DuniterStartArgs {
-    /// Enable GVA API
-    #[structopt(long)]
-    gva: bool,
     /// Force to use the keypair of the given YAML file. File must contain `pub:` and `sec:` fields.
     #[structopt(long, parse(from_os_str), env("DUNITER_KEYFILE"))]
     keyfile: Option<PathBuf>,
@@ -213,41 +213,45 @@ fn main() -> Result<()> {
     } else {
         let profile_path = get_profile_path(args.profile.as_deref())?;
 
-        let current_exe = std::env::current_exe()?;
-        let prod = current_exe == PathBuf::from(DUNITER_EXE_LINK_PATH)
-            || current_exe == PathBuf::from(DUNITER_EXE_PATH);
+        if let DuniterCommand::Wizard(WizardCommand::Gva) = args.command {
+            wizard_gva::wizard_gva(args.profile.as_deref(), profile_path)
+        } else {
+            let current_exe = std::env::current_exe()?;
+            let prod = current_exe == PathBuf::from(DUNITER_EXE_LINK_PATH)
+                || current_exe == PathBuf::from(DUNITER_EXE_PATH);
 
-        let duniter_ts_args = duniter_ts_args::gen_duniter_ts_args(&args, duniter_js_exe()?);
+            let duniter_ts_args = duniter_ts_args::gen_duniter_ts_args(&args, duniter_js_exe()?);
 
-        match args.command {
-            DuniterCommand::Restart => {
-                daemon::start(prod, &profile_path, &daemon::stop(&profile_path)?)
-            }
-            DuniterCommand::Start(_) | DuniterCommand::Webstart { .. } => {
-                daemon::start(prod, &profile_path, &duniter_ts_args)
-            }
-            DuniterCommand::Status => daemon::status(&profile_path),
-            DuniterCommand::Stop => {
-                daemon::stop(&profile_path)?;
-                Ok(())
-            }
-            DuniterCommand::Logs => watch_logs(profile_path),
-            _ => {
-                ctrlc::set_handler(move || {
-                    // This empty handler is necessary otherwise the Rust process is stopped immediately
-                    // without waiting for the child process (duniter_js) to finish stopping.
-                })?;
-                let mut duniter_js_command = Command::new(get_node_path()?);
-                if prod {
-                    duniter_js_command.current_dir(DUNITER_JS_CURRENT_DIR);
+            match args.command {
+                DuniterCommand::Restart => {
+                    daemon::start(prod, &profile_path, &daemon::stop(&profile_path)?)
+                }
+                DuniterCommand::Start(_) | DuniterCommand::Webstart { .. } => {
+                    daemon::start(prod, &profile_path, &duniter_ts_args)
                 }
-                //println!("TMP duniter_ts_args={:?}", duniter_ts_args);
-                let exit_code_opt = duniter_js_command.args(duniter_ts_args).status()?.code();
-                if let Some(exit_code) = exit_code_opt {
-                    std::process::exit(exit_code);
-                } else {
+                DuniterCommand::Status => daemon::status(&profile_path),
+                DuniterCommand::Stop => {
+                    daemon::stop(&profile_path)?;
                     Ok(())
                 }
+                DuniterCommand::Logs => watch_logs(profile_path),
+                _ => {
+                    ctrlc::set_handler(move || {
+                        // This empty handler is necessary otherwise the Rust process is stopped immediately
+                        // without waiting for the child process (duniter_js) to finish stopping.
+                    })?;
+                    let mut duniter_js_command = Command::new(get_node_path()?);
+                    if prod {
+                        duniter_js_command.current_dir(DUNITER_JS_CURRENT_DIR);
+                    }
+                    //println!("TMP duniter_ts_args={:?}", duniter_ts_args);
+                    let exit_code_opt = duniter_js_command.args(duniter_ts_args).status()?.code();
+                    if let Some(exit_code) = exit_code_opt {
+                        std::process::exit(exit_code);
+                    } else {
+                        Ok(())
+                    }
+                }
             }
         }
     }
diff --git a/rust-bins/duniter-launcher/src/sync.rs b/rust-bins/duniter-launcher/src/sync.rs
index ccedf568dad70d8c8be7763cac1e20c708b439b6..5e908cafa1adda896136d9bed9cd35b62a51409f 100644
--- a/rust-bins/duniter-launcher/src/sync.rs
+++ b/rust-bins/duniter-launcher/src/sync.rs
@@ -20,9 +20,6 @@ pub(crate) struct DuniterSyncArgs {
     /// Check all DUPB rules (very long).
     #[structopt(hidden(true), long)]
     cautious: bool,
-    /// Populate GVA DB (Necessary for the GVA api to work)
-    #[structopt(long)]
-    gva: bool,
     /// Allow to synchronize on nodes with local network IP address.
     #[structopt(hidden(true), long)]
     localsync: bool,
@@ -63,9 +60,6 @@ pub(crate) fn gen_args(args: &DuniterSyncArgs, duniter_ts_args: &mut Vec<String>
     if args.cautious {
         duniter_ts_args.push("--cautious".into());
     }
-    if args.gva {
-        duniter_ts_args.push("--gva".into());
-    }
     if args.localsync {
         duniter_ts_args.push("--localsync".into());
     }
diff --git a/rust-bins/duniter-launcher/src/wizard_gva.rs b/rust-bins/duniter-launcher/src/wizard_gva.rs
new file mode 100644
index 0000000000000000000000000000000000000000..27e9e237c86b8805319f407635450a927bda81f5
--- /dev/null
+++ b/rust-bins/duniter-launcher/src/wizard_gva.rs
@@ -0,0 +1,172 @@
+//  Copyright (C) 2020 Éloïs SANCHEZ.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as
+// published by the Free Software Foundation, either version 3 of the
+// License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program.  If not, see <https://www.gnu.org/licenses/>.
+
+use crate::*;
+use read_input::prelude::*;
+use std::{
+    net::{Ipv4Addr, Ipv6Addr},
+    str::FromStr,
+};
+
+/*
+struct GvaConf {
+    host: Option<String>,
+    port: Option<u16>,
+    path: Option<String>,
+    subscriptions_path: Option<String>,
+    remote_host: Option<String>,
+    remote_port: Option<u16>,
+    remote_path: Option<String>,
+    remote_subscriptions_path: Option<String>,
+    remote_tls: Option<bool>,
+}
+*/
+
+pub(crate) fn wizard_gva(profile_name_opt: Option<&str>, profile_path: PathBuf) -> Result<()> {
+    let file_path = profile_path.join("conf.json");
+
+    if !file_path.exists() {
+        if let Some(profile_name) = profile_name_opt {
+            Command::new(duniter_js_exe()?)
+                .args(&["--mdb", profile_name, "config"])
+                .status()?;
+        } else {
+            Command::new(duniter_js_exe()?).arg("config").status()?;
+        }
+    }
+
+    let mut file = File::open(file_path.as_path())?;
+    let mut contents = String::new();
+    file.read_to_string(&mut contents)?;
+
+    let mut conf_json = if contents.is_empty() {
+        serde_json::Value::Object(serde_json::Map::new())
+    } else {
+        serde_json::Value::from_str(&contents)?
+    };
+
+    let conf_json_obj = conf_json
+        .as_object_mut()
+        .ok_or_else(|| anyhow::Error::msg("json conf must be an object"))?;
+
+    let mut gva_conf = serde_json::Map::new();
+
+    // Enable GVA API?
+    let res = input().msg("Enable GVA API? [Y/n]").default('Y').get();
+    let gva_enabled = res != 'n';
+    gva_conf.insert("enabled".to_owned(), serde_json::Value::Bool(gva_enabled));
+
+    if gva_enabled {
+        // ip4
+        let ip4 = input()
+            .msg("Listen to ip v4 ? [127.0.0.1]")
+            .default(Ipv4Addr::LOCALHOST)
+            .get();
+        gva_conf.insert("ip4".to_owned(), serde_json::Value::String(ip4.to_string()));
+        // ip6
+        let res = input().msg("Listen to ip v6? [Y/n]").default('Y').get();
+        if res != 'n' {
+            let ip6 = input()
+                .msg("Enter ip v6: [::1]")
+                .default(Ipv6Addr::LOCALHOST)
+                .get();
+            gva_conf.insert("ip6".to_owned(), serde_json::Value::String(ip6.to_string()));
+        }
+        // port
+        let port = input()
+            .msg("Listen to port ? [30901]")
+            .default(30901u16)
+            .get();
+        gva_conf.insert(
+            "port".to_owned(),
+            serde_json::Value::Number(serde_json::Number::from(port)),
+        );
+        // path
+        let path = input().msg("Path ? [gva]").default("gva".to_owned()).get();
+        gva_conf.insert("path".to_owned(), serde_json::Value::String(path));
+        // subscriptionsPath
+        let subscriptions_path = input()
+            .msg("Subscriptions path ? [gva-sub]")
+            .default("gva-sub".to_owned())
+            .get();
+        gva_conf.insert(
+            "subscriptionsPath".to_owned(),
+            serde_json::Value::String(subscriptions_path),
+        );
+        // remoteHost
+        let res = input()
+            .msg("Define a remote host? [y/N]")
+            .default('N')
+            .get();
+        if res == 'y' || res == 'Y' {
+            let remote_host = input().msg("Enter remote host:").get();
+            gva_conf.insert(
+                "remoteHost".to_owned(),
+                serde_json::Value::String(remote_host),
+            );
+        }
+        // remotePort
+        let res = input()
+            .msg("Define a remote port? [y/N]")
+            .default('N')
+            .get();
+        if res == 'y' || res == 'Y' {
+            let remote_port = input()
+                .msg("Enter remote port ? [443]")
+                .default(443u16)
+                .get();
+            gva_conf.insert(
+                "remotePort".to_owned(),
+                serde_json::Value::Number(serde_json::Number::from(remote_port)),
+            );
+        }
+        // remotePath
+        let res = input()
+            .msg("Define a remote path? [y/N]")
+            .default('N')
+            .get();
+        if res == 'y' || res == 'Y' {
+            let remote_path = input().msg("Enter remote path:").get();
+            gva_conf.insert(
+                "remotePath".to_owned(),
+                serde_json::Value::String(remote_path),
+            );
+        }
+        // remoteSubscriptionsPath
+        let res = input()
+            .msg("Define a remote subscriptions path? [y/N]")
+            .default('N')
+            .get();
+        if res == 'y' || res == 'Y' {
+            let remote_path = input().msg("Enter remote subscriptions path:").get();
+            gva_conf.insert(
+                "remoteSubscriptionsPath".to_owned(),
+                serde_json::Value::String(remote_path),
+            );
+        }
+    }
+
+    // Insert GVA json conf in global json conf
+    conf_json_obj.insert("gva".to_owned(), serde_json::Value::Object(gva_conf));
+
+    // Write new_conf
+    let new_conf_str = serde_json::to_string_pretty(&conf_json)?;
+    let mut file = File::create(file_path.as_path())?;
+    file.write_all(new_conf_str.as_bytes())?;
+
+    println!("Configuration successfully updated.");
+
+    Ok(())
+}