diff --git a/back/webmin/graphql/resolvers/BigResolver.ts b/back/webmin/graphql/resolvers/BigResolver.ts
index 5e88ec7726bb1f19278b7255984298244aaf246d..1ccc04b85bab54d12531f7542b9a30b9980c5120 100644
--- a/back/webmin/graphql/resolvers/BigResolver.ts
+++ b/back/webmin/graphql/resolvers/BigResolver.ts
@@ -10,6 +10,7 @@ import {gqlHeads} from '../../queries/gql-heads'
 import {gqlWs2pInfos} from '../../queries/gql-ws2p'
 import {gqlIsSyncStarted, gqlSynchronize} from '../../queries/gql-synchronize'
 import {gqlUid} from '../../queries/gql-uid'
+import {getConf, testAndSaveConf} from '../../queries/gql-conf'
 import {Arg} from 'type-graphql/dist/decorators/Arg'
 import {getForks, getMainChain} from '../../queries/gql-forks'
 import {ChainType} from '../types/ChainType'
@@ -67,6 +68,16 @@ export class BigResolver {
     return gqlUid(ApplicationContext.server)(null, { pub })
   }
 
+  @Query(type => String)
+  getConf(): Promise<string> {
+    return getConf(ApplicationContext.server)
+  }
+
+  @Query(type => String)
+  testAndSaveConf(@Arg("conf") conf: string): Promise<string> {
+    return testAndSaveConf(ApplicationContext.server, ApplicationContext.startServices, ApplicationContext.stopServices, conf)
+  }
+
   @Query(type => ChainType)
   getMainChain(@Arg("start", type => Int) start: number, @Arg("end", type => Int) end: number): Promise<ChainType> {
     return getMainChain(ApplicationContext.server, start, end)
diff --git a/back/webmin/queries/gql-conf.ts b/back/webmin/queries/gql-conf.ts
new file mode 100644
index 0000000000000000000000000000000000000000..fee3fc207acf9f33eb4c485c65c0871d160a5e7b
--- /dev/null
+++ b/back/webmin/queries/gql-conf.ts
@@ -0,0 +1,26 @@
+import {Server} from 'duniter/server'
+
+export async function getConf(server: Server): Promise<string> {
+  const raw = (await server.dal.confDAL.readRawConfFile()) || ''
+  if (!raw) {
+    return ''
+  }
+  return JSON.stringify(JSON.parse(raw), null, '\t')
+}
+
+export async function testAndSaveConf(
+  server: Server,
+  startServices: () => Promise<void>,
+  stopServices: () => Promise<void>,
+  conf: string
+): Promise<string> {
+  // Test the syntax
+  const jsonConf = JSON.parse(conf)
+  // OK: stop services and reload the server
+  await stopServices()
+  await server.dal.confDAL.saveConf(jsonConf)
+  await server.reloadConf()
+  await startServices()
+  // We reuse the getConf() function
+  return getConf(server)
+}
diff --git a/package.json b/package.json
index e700a73a51c61d5e34c3e1536d57aee289726184..087e6ee61fe71cea1a445f261fa7cc1a7d886093 100644
--- a/package.json
+++ b/package.json
@@ -56,7 +56,6 @@
     "express": "^4.16.4",
     "express-http-proxy": "^1.5.1",
     "graphql-tag": "^2.9.0",
-    "js-yaml": "^3.12.1",
     "mocha": "^6.1.4",
     "moment": "^2.23.0",
     "nodemon": "^1.18.9",
@@ -68,6 +67,7 @@
     "ts-node": "^8.1.0",
     "typescript": "^3.4.3",
     "vue-cli-plugin-apollo": "^0.20.0",
+    "vue-codemirror": "^4.0.6",
     "vue-template-compiler": "^2.5.21"
   },
   "postcss": {
diff --git a/src/lib/i18n/en.ts b/src/lib/i18n/en.ts
index 35390b070686f2ba7a5f6c9fde6208ac4141a71a..d563eb752bdc9f3146c667221ba5275adbde5687 100644
--- a/src/lib/i18n/en.ts
+++ b/src/lib/i18n/en.ts
@@ -25,4 +25,7 @@ export const i18nLangEn: lang = {
   'parameters.conf.file.explanation': 'This is your configuration file. You can directly edit it from here if you wish.',
   'fork.view.too.much': 'Too much blocks requested: max is {0}.',
   'parameters.menu.lang': 'Language',
+  'parameters.conf.file.save': 'Test and save file',
+  'parameters.conf.file.saved.and.applied': 'Configuration saved and server restarted.',
+  'parameters.lang.changed': 'Language switched to « English »'
 }
\ No newline at end of file
diff --git a/src/lib/i18n/fr.ts b/src/lib/i18n/fr.ts
index d40c24e732ecd7d63efc6082bae83e37708304d8..9bb5dae7a9238fdb2b4077098b514e40966bc95c 100644
--- a/src/lib/i18n/fr.ts
+++ b/src/lib/i18n/fr.ts
@@ -25,4 +25,7 @@ export const i18nLangFr: lang = {
   'parameters.conf.file.explanation': 'Ceci est votre fichier de configuration. Vous pouvez le modifier directement ici si vous le souhaitez.',
   'fork.view.too.much': 'Trop de blocs demandés : le maximum est de {0}.',
   'parameters.menu.lang': 'Langage',
+  'parameters.conf.file.save': 'Tester et sauvegarder le fichier',
+  'parameters.conf.file.saved.and.applied': 'Fichier sauvegardé et serveur redémarré.',
+  'parameters.lang.changed': 'Langue changée en « Français »',
 }
\ No newline at end of file
diff --git a/src/lib/i18n/lang.ts b/src/lib/i18n/lang.ts
index de0c9a05ee8d69381c65fc435028b7d682d6a589..4bbc40eed03905568f87eead093d7966f8fdccd7 100644
--- a/src/lib/i18n/lang.ts
+++ b/src/lib/i18n/lang.ts
@@ -23,4 +23,7 @@ export interface lang {
   'parameters.conf.file.explanation': string
   'fork.view.too.much': string
   'parameters.menu.lang': string
+  'parameters.conf.file.save': string
+  'parameters.conf.file.saved.and.applied': string
+  'parameters.lang.changed': string
 }
diff --git a/src/lib/services/webmin.service.ts b/src/lib/services/webmin.service.ts
index 44b717b00952c3cbdc58b805ee2d5bf372a01194..149fb98dc7570c74ef72beb4c060e17b66f22b24 100644
--- a/src/lib/services/webmin.service.ts
+++ b/src/lib/services/webmin.service.ts
@@ -277,6 +277,41 @@ export class WebminService {
     .result()
   }
 
+  async getConf(): Promise<string> {
+    const res = await this.getApollo()
+    .watchQuery<{ getConf: string }>({
+      query: gql`
+          query {
+              getConf
+          }
+      `,
+    })
+    .result()
+    return res.data.getConf
+  }
+
+  async testAndSaveConf(conf: string): Promise<string> {
+    const res = await this.getApollo()
+    .watchQuery<{ testAndSaveConf: string }>({
+      query: gql`
+          query ($conf: String!) {
+              testAndSaveConf(conf: $conf)
+          }
+      `,
+      variables: {
+        conf
+      }
+    })
+    // if (await res.getLastError()) {
+    //   throw Error(res.getLastError().stack)
+    // }
+    const result = (await res.result())
+    if (result.errors && result.errors.length) {
+      throw result.errors[0]
+    }
+    return result.data.testAndSaveConf
+  }
+
   async uid(pub: string) {
     const res = await this.getApollo()
     .watchQuery({
diff --git a/src/views/home/Parameters.vue b/src/views/home/Parameters.vue
index d64a0804eb6d488aa2f778b3a4ccc4bc6a97f052..66afcdaf186a38e64cb9c1e1cf9d9d62c825ff1e 100644
--- a/src/views/home/Parameters.vue
+++ b/src/views/home/Parameters.vue
@@ -36,6 +36,8 @@
   export default class extends Vue {
 
     menus = [
+      { route: '/home/parameters', name: 'parameters.menu.conf' },
+      { route: '/home/parameters/network', name: 'parameters.menu.network' },
       { route: '/home/parameters/lang', name: 'parameters.menu.lang' },
     ]
 
diff --git a/src/views/home/parameters/Conf.vue b/src/views/home/parameters/Conf.vue
new file mode 100644
index 0000000000000000000000000000000000000000..6da1fa846ba4a5779a4bf645a89074306f9164f1
--- /dev/null
+++ b/src/views/home/parameters/Conf.vue
@@ -0,0 +1,136 @@
+<style lang="css">
+  .CodeMirror,
+  .CodeMirror-merge,
+  .vue-codemirror.merge,
+  .vue-codemirror.merge > div,
+  .CodeMirror-merge.CodeMirror-merge-2pane > div {
+    height: 100%;
+  }
+
+  .CodeMirror-merge .CodeMirror,
+  .CodeMirror-merge.CodeMirror-merge-2pane {
+    height: 100%;
+  }
+
+  .CodeMirror-merge-l-inserted {
+    background-color: #aeffbc;
+    border-color: #aeffbc;
+  }
+
+  .CodeMirror-merge-l-deleted {
+    background-color: #ffa799;
+    border-color: #ffa799;
+  }
+
+  .CodeMirror-merge-left > .CodeMirror.cm-s-default {
+    background-color: #f1f1f1;
+  }
+</style>
+
+<template>
+
+  <div class="container-fluid">
+
+    <p>{{ $t('parameters.conf.file.explanation') }}</p>
+
+    <p class="d-flex align-items-center">
+      <b-spinner variant="success" label="Spinning" v-if="saving" class="mr-2"/>
+      <b-button
+          :disabled="saving || code === newCode"
+          :variant="saving || code === newCode ? 'outline-success' : 'success'"
+          @click="testAndSaveConf">{{ $t('parameters.conf.file.save') }}</b-button>
+    </p>
+
+    <div class="row">
+      <div class="col-12">
+        <codemirror :merge="true" :options="cmOption" :key="cmOption.origLeft" @input="changeCode" ></codemirror>
+      </div>
+    </div>
+
+  </div>
+
+</template>
+
+<script lang="ts">
+  import {Component, Vue} from 'vue-property-decorator';
+  import {codemirror} from 'vue-codemirror'
+  // require styles
+  import 'codemirror/lib/codemirror.css'
+  import 'codemirror/mode/javascript/javascript'
+
+  // merge js
+  import 'codemirror/addon/merge/merge.js'
+  // merge css
+  import 'codemirror/addon/merge/merge.css'
+  // google DiffMatchPatch
+  import DiffMatchPatch from 'diff-match-patch'
+  // DiffMatchPatch config with global
+  (window as any).diff_match_patch = DiffMatchPatch;
+  (window as any).DIFF_DELETE = -1;
+  (window as any).DIFF_INSERT = 1;
+  (window as any).DIFF_EQUAL = 0;
+
+  @Component({
+    components: {
+      codemirror
+    },
+  })
+  export default class extends Vue {
+
+    saving = false
+    newCode = ''
+    cmOption = {
+      value: '',
+      origLeft: '',
+      connect: 'align',
+      mode: 'text/javascript',
+      lineNumbers: true,
+      collapseIdentical: false,
+      highlightDifferences: true
+    }
+
+    changeCode(newCode) {
+      this.newCode = newCode
+    }
+
+    get code() {
+      return this.cmOption.value
+    }
+
+    async beforeMount() {
+      await this.refresh()
+    }
+
+    async refresh() {
+      const conf = await this.$webmin.getConf()
+      this.newCode = conf
+      this.cmOption.value = conf
+      this.cmOption.origLeft = conf
+    }
+
+    async testAndSaveConf() {
+      this.saving = true
+      try {
+        const conf = await this.$webmin.testAndSaveConf(this.newCode)
+        this.cmOption.value = conf
+        this.cmOption.origLeft = conf
+        this.$bvToast.toast(this.$t('parameters.conf.file.saved.and.applied'), {
+          title: 'Success',
+          variant: 'success',
+          autoHideDelay: 8000,
+          appendToast: true,
+        })
+      } catch (e) {
+        if (e.message.match(/Unexpected/)) {
+          this.$bvToast.toast(this.$t('parameters.conf.file.incorrect'), {
+            title: 'Error',
+            variant: 'danger',
+            autoHideDelay: 8000,
+            appendToast: true,
+          })
+        }
+      }
+      this.saving = false
+    }
+  }
+</script>
diff --git a/src/views/home/parameters/Language.vue b/src/views/home/parameters/Language.vue
index c70a8aa9d731d0038ecaf47eef55c56c4fd71dbb..18b0db02befb9027106efe7159487934aa1e5286 100644
--- a/src/views/home/parameters/Language.vue
+++ b/src/views/home/parameters/Language.vue
@@ -3,12 +3,7 @@
 
 <template>
 
-  <div>
-    <select v-model="lang" @change="changeLocale">
-      <option value="en">English</option>
-      <option value="fr">Français</option>
-    </select>
-  </div>
+  <b-form-select class="col-6" v-model="lang" :options="options" @change="changeLocale"/>
 
 </template>
 
@@ -30,6 +25,19 @@
     changeLocale() {
       this.$i18n.locale = this.lang
       localStorage.setItem(Constants.STORAGE_LANGUAGE, this.lang)
+      this.$bvToast.toast(this.$t('parameters.lang.changed'), {
+        title: 'Success',
+        variant: 'success',
+        autoHideDelay: 8000,
+        appendToast: true,
+      })
+    }
+
+    get options() {
+      return {
+        'en': 'English',
+        'fr': 'Français',
+      }
     }
   }
 </script>
diff --git a/src/views/home/parameters/Network.vue b/src/views/home/parameters/Network.vue
new file mode 100644
index 0000000000000000000000000000000000000000..15f73b1d6dbc60747fb015641cedc8023a206c14
--- /dev/null
+++ b/src/views/home/parameters/Network.vue
@@ -0,0 +1,23 @@
+<style lang="css" scoped>
+</style>
+
+<template>
+
+  <div>
+    <font-awesome-icon class="mr-3" icon="tools" style="font-size: 40px"/>
+    <font-awesome-icon class="mr-3" icon="hard-hat" style="font-size: 40px"/>
+    <font-awesome-icon class="mr-3" icon="exclamation-triangle" style="font-size: 40px"/>
+  </div>
+
+</template>
+
+<script lang="ts">
+  import {Component, Vue} from 'vue-property-decorator';
+
+  @Component({
+    components: {},
+  })
+  export default class extends Vue {
+
+  }
+</script>
diff --git a/src/vue-modules/register-router.ts b/src/vue-modules/register-router.ts
index af58b7c1fe010d0195a46b96bf44f0ea20b42d72..cb13b316575ba92891ea039fb25efa86d13c1baf 100644
--- a/src/vue-modules/register-router.ts
+++ b/src/vue-modules/register-router.ts
@@ -6,6 +6,8 @@ import Loader from '@/views/Loader.vue'
 import Sync from '@/views/Sync.vue'
 import Overview from '@/views/home/Overview.vue'
 import Parameters from '@/views/home/Parameters.vue'
+import Conf from '@/views/home/parameters/Conf.vue'
+import Network from '@/views/home/parameters/Network.vue'
 import Forkview from '@/views/home/Forkview.vue'
 import Language from '@/views/home/parameters/Language.vue'
 
@@ -42,14 +44,6 @@ export default new Router({
         name: 'parameters',
         component: Parameters,
         children: [{
-          path: 'lang',
-          name: 'lang',
-          component: Language
-        }]
-      }]
-    },
-    /*
-    {
           path: '',
           name: 'conf',
           component: Conf
@@ -57,8 +51,13 @@ export default new Router({
           path: 'network',
           name: 'network',
           component: Network
-        },
-     */
+        },{
+          path: 'lang',
+          name: 'lang',
+          component: Language
+        }]
+      }]
+    },
     {
       path: '/about',
       name: 'about',
diff --git a/src/vue-modules/register-vue-apollo.ts b/src/vue-modules/register-vue-apollo.ts
index c8c3defd9048a32801840a63f85a68a3405eb66f..72a0b14ac3e1ae3cb8d3210132cd5fa46f221a30 100644
--- a/src/vue-modules/register-vue-apollo.ts
+++ b/src/vue-modules/register-vue-apollo.ts
@@ -38,7 +38,7 @@ const apolloClient = new ApolloClient({
   defaultOptions: {
     watchQuery: {
       fetchPolicy: 'network-only',
-      errorPolicy: 'ignore',
+      errorPolicy: 'all',
     },
     query: {
       fetchPolicy: 'network-only',
diff --git a/yarn.lock b/yarn.lock
index ba951c9025bdd5383a345d68b0b56237d7c3a97c..41ae0106adf9d6920a473a3d2abc5f42a1f3362f 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2304,6 +2304,11 @@ code-point-at@^1.0.0:
   resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77"
   integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=
 
+codemirror@^5.41.0:
+  version "5.46.0"
+  resolved "https://registry.yarnpkg.com/codemirror/-/codemirror-5.46.0.tgz#be3591572f88911e0105a007c324856a9ece0fb7"
+  integrity sha512-3QpMge0vg4QEhHW3hBAtCipJEWjTJrqLLXdIaWptJOblf1vHFeXLNtFhPai/uX2lnFCehWNk4yOdaMR853Z02w==
+
 collection-visit@^1.0.0:
   version "1.0.0"
   resolved "https://registry.yarnpkg.com/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0"
@@ -3164,6 +3169,11 @@ dicer@0.3.0:
   dependencies:
     streamsearch "0.1.2"
 
+diff-match-patch@^1.0.0:
+  version "1.0.4"
+  resolved "https://registry.yarnpkg.com/diff-match-patch/-/diff-match-patch-1.0.4.tgz#6ac4b55237463761c4daf0dc603eb869124744b1"
+  integrity sha512-Uv3SW8bmH9nAtHKaKSanOQmj2DnlH65fUpcrMdfdaOxUG02QQ4YGZ8AE7kKOMisF7UqvOlGKVYWRvezdncW9lg==
+
 diff@3.5.0, diff@^3.1.0, diff@^3.2.0:
   version "3.5.0"
   resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12"
@@ -5504,7 +5514,7 @@ js-tokens@^4.0.0:
   resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
   integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==
 
-js-yaml@3.13.1, js-yaml@^3.12.1, js-yaml@^3.13.0, js-yaml@^3.13.1, js-yaml@^3.9.0:
+js-yaml@3.13.1, js-yaml@^3.13.0, js-yaml@^3.13.1, js-yaml@^3.9.0:
   version "3.13.1"
   resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.13.1.tgz#aff151b30bfdfa8e49e05da22e7415e9dfa37847"
   integrity sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==
@@ -10037,6 +10047,14 @@ vue-cli-plugin-apollo@^0.20.0:
     subscriptions-transport-ws "^0.9.16"
     ts-node "^8.0.3"
 
+vue-codemirror@^4.0.6:
+  version "4.0.6"
+  resolved "https://registry.yarnpkg.com/vue-codemirror/-/vue-codemirror-4.0.6.tgz#b786bb80d8d762a93aab8e46f79a81006f0437c4"
+  integrity sha512-ilU7Uf0mqBNSSV3KT7FNEeRIxH4s1fmpG4TfHlzvXn0QiQAbkXS9lLfwuZpaBVEnpP5CSE62iGJjoliTuA8poQ==
+  dependencies:
+    codemirror "^5.41.0"
+    diff-match-patch "^1.0.0"
+
 vue-functional-data-merge@^2.0.7:
   version "2.0.7"
   resolved "https://registry.yarnpkg.com/vue-functional-data-merge/-/vue-functional-data-merge-2.0.7.tgz#bdee655181eacdcb1f96ce95a4cc14e75313d1da"